你必须要知道的8种基本排序方法

2023-10-30

1.选择排序

定义:首先,选出数组中最小的元素,将它与数组中第一个元素交换。然后找出次小的元素,并将它与数组中第二个元素交换。按照这种方法一直进行下去,直到整个数组排完序。

交换次数:N-1

缺点:运行时间对文件已有序的部分依赖较少,从文件中选出最小元素的每一遍操作过程,并没有给出下一遍要找的最小元素的位置的相关消息。例如,该程序对已排好序的文件或各元素都相同的元素文件与对随机排列的文件排序所花的时间基本相同。

适用性:对于元素比较大,关键字又比较小的文件,应该选择该方法,而其他算法移动数据的步数都比选择排序更多。

sc(source code):

template <typename T, typename Compare>
void SelectSort(vector<T> & arr, Compare cp)
{
Display(arr,
"before SelectSort:");
for (size_t i=0; i<arr.size(); ++i) {
size_t m
= i;
for (size_t j=i+1; j<arr.size(); ++j) {
if ( !cp(arr[m], arr[j]) ) {
m
= j;
}
}
if (m != i) {
swap(arr[i], arr[m]);
}

Display(arr, i);
}
}

2.插入排序(摘自:http://zh.wikipedia.org/wiki/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F

插入排序(Insertion Sort的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

算法描述:

一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:

  1. 从第一个元素开始,该元素可以认为已经被排序

  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描

  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置

  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

  5. 将新元素插入到该位置中

  6. 重复步骤2

如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序

算法复杂度:

如果目标是把n个元素的序列升序排列,那么采用插入排序存在最好情况和最坏情况。最好情况就是,序列已经是升序排列了,在这种情况下,需要进行的比较操作需(n-1)次即可。最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。插入排序的赋值操作是比较操作的次数减去(n-1)次。平均来说插入排序算法复杂度为O(n2)。因而,插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。

sc

template <typename T, typename Compare>
void InsertSort(vector<T>& arr, Compare cp)
{
Display(arr,
"before InsertSort:");
for(size_t i=1; i<arr.size(); ++i) {
T temp
= arr[i];
for(size_t j=i ; j>0 && !cp(temp, arr[j-1]) ; --j) {
arr[j]
= arr[j-1];
arr[j
-1] = temp;
Display(arr,
"----");
}
Display(arr, i);
}
}

3.冒泡排序

定义:遍历文件,如果紧邻的两个元素大小顺序不对,就将两者交换,重复这样的操作直到整个文件排好序。

小结:

1)选择排序使用大概次比较操作和N次交换操作。

2)在平均情况下,插入排序执行大约次比较操作和次交换(移动)操作,而在最坏情况下需要两倍的数量。

3)在平均情况和最坏情况下,冒泡排序执行大约次比较操作和次交换操作。

4)对于逆序数[文件中一对顺序不对的元素称为一个逆序]是常数级的文件,插入排序和冒泡排序所要进行的比较和交换操作的数目的是输入的线性函数。

5)如果文件中固有部分的元素的逆序数超过常数级,插入排序所执行的比较和交换操作仍是线性的。

6)对于数据项较大,关键字较小的文件,选择排序的运行时间是线性的。

4.希尔排序(http://zh.wikipedia.org/wiki/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F

希尔排序,也称递减增量排序算法,是插入排序的一种高速而稳定的改进版本。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率

  • 但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位

算法实现

希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。

假设有一个很小的数据在一个已按升序排好序的数组的末端。如果用复杂度为O(n2)的排序(冒泡排序插入排序),可能会进行n次的比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,所以小数据只需进行少数比较和交换即可到正确位置。

一个更好理解的希尔排序实现:将数组列在一个表中并对列排序(用插入排序)。重复这过程,不过每次用更长的列来进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算法,算法本身仅仅对原数组进行排序(通过增加索引的步长,例如是用i += step_size而不是i++)。

例如,假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5行的表中来更好地描述算法,这样他们就应该看起来是这样:

13 14 94 33 82

25 59 94 65 23

45 27 73 25 39

10

然后我们对每列进行排序:

10 14 73 25 23

13 27 94 33 39

25 59 94 65 82

45

当我们以单行来读取数据时我们得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].这时10已经移至正确位置了,然后再以3为步长进行排序:

10 14 73

25 23 13

27 94 33

39 25 59

94 65 82

45

排序之后变为:

10 14 13

25 23 33

27 25 59

39 65 73

45 94 82

94

最后以1步长进行排序(此时就是简单的插入排序了)。

步长序列

步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。

Donald Shell 最初建议步长选择为n/2并且对步长取半直到步长达到1。虽然这样取可以比O(n2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。 可能希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。

已知的最好步长序列由Marcin Ciura设计(141023571323017011750,…) 这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长序列的希尔排序比插入排序堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。

另一个在大数组中表现优异的步长序列是(斐波那契数列除去01将剩余的数以黄金分割比的两倍的进行运算得到的数列):(1, 9, 34, 182, 836, 4025, 19001, 90358, 428481, 2034035, 9651787, 45806244, 217378076, 1031612713, …

sc

template <typename T, typename Compare>
void ShellSort(vector<T>& arr, Compare cp)
{
Display(arr,
"before ShellSort");

int gap = 0;
while (gap <= arr.size()) {
gap
= gap * 3 + 1;
}
T temp;
while (gap > 0) {
for (int i=gap; i<arr.size(); ++i) {
int j = i - gap;
temp
= arr[i];
while (( j>=0 ) && ( cp(arr[j], temp) )) {
arr[j
+gap] = arr[j];
j
-= gap;
}
arr[j
+ gap] = temp;
}
gap
= (gap - 1) / 3;
Display(arr, gap);
}
Display(arr,
"end sort");
}

5.快速排序

我之前的一篇随笔:快速排序

快速排序算法是一种分治排序算法。它将数组划分为两个部分,然后分别对两个部分进行排序。划分的准确位置取决于输入文件中元素的初始位置。关键在于划分过程,它重排元素,使得以下三个条件成立:

对于某一ia[i]在数组的最终位置上;

a[1],…a[i-1]中的元素都比a[i]小;

a[i+1],…,a[r]中的元素都比a[i]大。

我们通过划分来完成排序,然后递归地应用该方法处理子文件。

递归实现:

sc:

int Partition(vector<int> &  arr, int left, int right)
{
int i = left - 1;
int j = right;
int v = arr[right];

for (;;) {
while (arr[++i] < v) ;

while (arr[--j] > v) {
if (j == left) {
break;
}
}

if (i >= j) {
break;
}

swap(arr[i], arr[j]);
}

swap(arr[i], arr[right]);
return i;
}

void QuickSort(vector<int> & arr, int left, int right)
{
if (right <= left) return ;

int i = Partition(arr, left, right);
QuickSort(arr, left, i
-1);
QuickSort(arr, i
+1, right);
}

非递归实现:

sc:

int Partition(vector<int> &  arr, int left, int right)
{
int i = left - 1;
int j = right;
int v = arr[right];

for (;;) {
while (arr[++i] < v) ;

while (arr[--j] > v) {
if (j == left) {
break;
}
}

if (i >= j) {
break;
}

swap(arr[i], arr[j]);
}

swap(arr[i], arr[right]);
return i;
}

void QuickSort(vector<int> & arr, int left, int right)
{
stack
< pair<int, int> > sk;
sk.push(make_pair
<int, int>(left, right));

while (!sk.empty()) {
pair
<int, int> lr = sk.top();
sk.pop();

if (lr.first >= lr.second) continue;

int i = Partition(arr, lr.first, lr.second);
if (i-lr.first > lr.second-i) {
sk.push(make_pair
<int, int>(lr.first, i-1));
sk.push(make_pair
<int, int>(i+1, lr.second));
}
else {
sk.push(make_pair
<int, int>(i+1, lr.second));
sk.push(make_pair
<int, int>(lr.first, i-1));
}
}

}

快速排序的性能特征:

1)快速排序最坏情况下使用大约次比较。

2)快速排序平均情况下使用大约2NlgN次比较。

3)如果两个子文件的较小者首先是排好序的,那么在使用快速排序对N个元素进行排序时,栈中元素不会超过lgN个。

6.归并排序

我之前的一篇随笔:递归与分治策略中的归并排序。

7.堆排序(参见堆积排序

8.基数排序(参见基数排序

   亦可参见基数排序

附上述代码中缺失Display方法代码:

template <typename T>
void Display(const vector<T> & arr, size_t count)
{
cout
<< count << ": ";
copy (arr.begin(), arr.end(), ostream_iterator
<T>(cout, " "));
cout
<< endl;
}

template
<typename T>
void Display(const vector<T> & arr, string prompt=string())
{
cout
<< prompt << " ";
copy (arr.begin(), arr.end(), ostream_iterator
<T>(cout, " "));
cout
<< endl;
}

文章参考资料:

《算法:C语言实现》

/********************************************************/
* 本文由chinazhangjie整理,转载请注明博客链接,谢谢!
* 时间:2011.07.29

/*******************************************************/



转载于:https://www.cnblogs.com/chinazhangjie/archive/2011/07/29/2121200.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

你必须要知道的8种基本排序方法 的相关文章

  • 在 bash 中使用单个命令为 shell 变量分配默认值

    我对 bash 3 00 shell 脚本中的变量进行了大量测试 如果未设置变量 则它会分配默认值 例如 if z VARIABLE then FOO default else FOO VARIABLE fi 我似乎记得有一些语法可以在一行
  • git 别名中的 AWK 语句

    我正在尝试创建一个 git 别名来以特定格式打印日志中的所有拉取请求 但是 我在使用 AWK 删除双空格时遇到问题 这是使用以下命令的 git log 的输出 git log merges grep pull request pretty
  • 添加要在给定命令中运行的 .env 变量

    我有一个 env 文件 其中包含如下变量 HELLO world SOMETHING nothing 前几天我发现了这个很棒的脚本 它将这些变量放入当前会话中 所以当我运行这样的东西时 cat env grep v xargs node t
  • OSX bash 最小化窗口

    在 Mac 中并使用 bash shell 我想执行一个包含单个命令 启动 Jupyter Lab 的文件并立即最小化终端窗口 有没有办法在不安装第三方软件的情况下做到这一点 是的 只需使用osascript https ss64 com
  • sed 错误“未终止的 's' 命令”故障排除

    我正在构建一个script https stackoverflow com questions 4036832 replacing a specific term in an xml file其中 它将用文件夹路径替换 XML 文件中的模式
  • 从 shell 命令调用 SOAP 请求

    我使用curl 向Web 服务发送SOAP 请求 并使用shell 脚本获取响应 请在下面找到我正在使用的命令 curl H Content Type text xml charset utf 8 H SOAPAction d sample
  • 如何在shell中输出返回码?

    我正在尝试通过调用自定义 shell 脚本sh bin sh c myscript sh gt log txt 2 gt 1 echo 该命令的输出是创建的后台进程的 PID 我想指导 bin sh保存返回码myscript sh到某个文件
  • 如何在 PHP 中运行 shell 脚本?

    我正在尝试使用 PHP 触发 shell 脚本的运行 本质上 当用户在我们用 PHP 编写的网站上完成一个操作时 我们希望触发一个 shell 脚本 该脚本本身调用一个 Java 文件 提前致谢 See shell exec http ph
  • 符合 POSIX 标准的 shell 相当于 Bash“while read -d $'\0' ...”?

    我正在尝试使 Bash 脚本严格符合 POSIX 标准 即消除任何潜在的 Bashisms http mywiki wooledge org Bashism 通过使用checkbashisms px script filename 在给定的
  • 使用 plistBuddy 获取值数组

    var keychain access groups declare a val usr libexec PlistBuddy c Print var sample plist echo val echo val 0 Ouput Array
  • 这种 bash 文件名提取技术有何用途?

    我有一部分 bash 脚本正在获取不带扩展名的文件名 但我试图了解这里到底发生了什么 是做什么用的 有人可以详细说明 bash 在幕后做了什么吗 如何在一般基础上使用该技术 bin bash for src in tif do txt sr
  • 如果未设置,则从控制台读取 Makefile 变量

    我正在更新一个从外部源访问某些资源的 Makefile 即存在以下形式的规则 External cvs up 对于不受限制的资源 它可以按预期工作 现在 出现了功能漂移 外部资源需要更复杂的登录 因此规则已更改为与此没有太大不同的内容 Ex
  • 为什么 shell=True 的 subprocess.Popen() 在 Linux 和 Windows 上的工作方式不同?

    使用时subprocess Popen args shell True 跑步 gcc version 仅作为示例 在 Windows 上我们得到 gt gt gt from subprocess import Popen gt gt gt
  • 如何在 Linux/OS X 上温和地终止 Firefox 进程

    我正在使用 Firefox 进行一些自动化操作 尽管我可以从 shell 打开 Firefox 窗口 但我无法正确终止它 如果我kill火狐进程与kill 3 or kill 2当我下次打开新的 Firefox 窗口时 命令会询问我是否要在
  • 如何列出 nginx 中的所有虚拟主机

    有没有一个命令可以列出 CentOS 上 nginx 下运行的所有虚拟主机或服务器 我想将结果通过管道传输到文本文件以用于报告目的 我正在寻找与我用于 Apache 的命令类似的命令 apachectl S 2 gt 1 grep 端口 8
  • Bash - 比较 2 个文件列表及其 md5 校验和

    我有 2 个列表 其中包含带有 md5sum 检查的文件 即使文件相同 列表也具有不同的路径 我想检查每个文件的 md5 和 我们正在讨论数千个文件 这就是为什么我需要脚本来仅显示差异 第一个列表是普通列表 第二个列表是文件的当前状态 我想
  • PHP exec rm -Rf 不适用于子目录

    我试图删除特定文件夹中的所有内容 但它似乎不会影响子文件夹 但它应该 因为 bash 命令是从控制台执行的 system rm Rf some dir 该命令中不需要星号 如果要与文件一起删除目录 请同时删除斜杠 留下斜杠将删除文件 但保留
  • adb shell 输入带有空格的文本

    如何发送带有空格的文本 例如 一些文字 using adb shell input text 找到以下解决方案 adb shell input text some stext 工作正常 但是有什么简单的方法可以用 s 替换空格吗 Examp
  • 在 bash 中,如何除以两个变量并输出四舍五入到小数点后 5 位的答案? [复制]

    这个问题在这里已经有答案了 我将两个变量作为输入 将它们相除后 我希望将输出四舍五入到小数点后 5 位 我已经尝试过这种方法 gt sum 12 n 7 output scale 5 sum n bc echo output 我的代码没有显
  • 查找并删除超过 x 天的文件或文件夹

    我想删除超过 7 天的文件和文件夹 所以我尝试了 17 07 14 email protected cdn cgi l email protection find tmp mindepth 1 maxdepth 1 ctime 7 exec

随机推荐

  • Spring已经添加属性注入了,但是还是报空指针错误 说明 .

    2019独角兽企业重金招聘Python工程师标准 gt gt gt public class DocumentPressUCCImpl extends TaskUCCImpl implements IDocumentPressUCC 中 已
  • arm平台tslib的编译与qte源代码包配置中的-qt-mouse-tslib

    自己一个人学习摸索 真不是件容易的事 为了能够在qt embedded linux opensource src 4 5 3里配置 qt mouse tslib不出问题 我可是足足折腾了三天 以下我将自己的工作成果贴出 与大家共享 一 下载
  • 斗地主服务器维护中,天天斗地主游戏问题解决方法

    天天斗地主游戏问题解决方法 天天斗地主游戏常见的一些问题 娜娜给大家整理了一下几种 希望可以对大家有所帮助 Q 在游戏中卡住了 怎么办 A 游戏突然卡住 如果是非服务器端正常维护导致的此情况发生 建议您先刷新页面 如果仍没有改善 建议您关闭
  • 网络传输的基本流程

    1 网络传输的进本流程 同一网段内两台主机进行文件传输 文件传输的流程 2 理解封装和分用 不同协议对数据报有不同的称谓 在传输层叫做段 segment 在网络层叫做数据报 datagram 在链路层叫做帧 frame 应用层数据通过协议栈
  • 关于mpvue切换页面数据没清空

    场景 页面 add 和 update 写在同一个页面里面 我来回进入当前界面 页面缓存数据 这不科学啊 思路 加载页面的时候 小程序生命周期重置data数据 onLoad Object assign this data this optio
  • 十个接私活赚外快的网站,你有技术就有钱

    大家好 我是尼奥 前两天在知乎上发了一篇文章 现在程序员的工资是不是被高估了 有一些网友就私信我说 为什么工资被高估了 我还这么穷 有没有什么兼职平台推荐的 我一想 还真有 毕竟自己也做过那么几年兼职 有些经验 就整理了这篇文章 给大家讲讲
  • swagger-springboot详解

    文章目录 1 什么是swagger 2 swagger ui 和 springfox swagger ui 3 springboot使用swagger 1 导包 2 编写swagger配置类 3 配置API文档信息 4 配置swagger扫
  • 《银行法律法规》二、银行业务——2、贷款业务

    第二章 贷款业务 第一节 个人贷款业务 个人贷款是指贷款人向符合条件的自然人发放的用于个人消费 生产经营等用途的本外币贷款 部分个人贷款也用于生产经营 但绝大多数个人贷款主要用于消费 个人贷款主要分为四大类 即 个人住房贷款 个人消费贷款
  • SpringBoot 使用 Amqp

    目录 一 服务如何安装rabbitmqdocker 安装 rabbitmq 二 导入依赖 三 配置文件内容 四 配置类 五 用户类 六 发送类 七 接收类 八 Api类 代码地址 一 服务如何安装rabbitmqdocker 安装 rabb
  • PCL 直通滤波(C++详细过程版)

    直通滤波 一 概述 二 代码实现 三 结果展示 1 原始点云 2 滤波结果 一 概述 直通滤波在PCL里有现成的调用函数 具体算法原理和实现代码见 PCL 直通滤波器 为充分了解直通滤波算法实现的每一个细节和有待改进的地方 使用C 代码对算
  • StyleGAN 阅读笔记(翻译)

    A Style Based Generator Architecture for Generative Adversarial Networks 作者 Tero Karras NVIDIA Samuli Laine NVIDIA Timo
  • Node.js 的安装及基础方法的使用

    一 Node js的简介 1 什么是Node js Node js是一个基于Chrome V8引擎的JavaScript运行环境 2 Node js的运行环境 Node js内置API fs path http JS内置对象 queryst
  • Java实现PDF生成(Word文档转Pdf)

    准备工作 1 准备模板 模板为Word 文档 当修改好想要的格式后 保存为Pdf格式 2 准备软件 Adobe Acrobat 9 Pro 需要编辑PDF 如哪里需要添加文字 哪里需要添加图片 软件部分 1 点击表单 启动表单向导 现有文档
  • 百度工程师手把手教你实现代码规范检测工具

    01 引言 代码规范是软件开发领域经久不衰的话题 在前端领域中 说到代码规范 我们会很容易想到检查代码缩进 尾逗号以及分号等等 除此之外 代码规范还包括了针对特殊场景定制化的检查 JavaScript 代码规范检查工具包括 JSLint J
  • 小学生听力测试软件,亲测十款小学英语APP,为了孩子请收藏

    很多家长说自己不懂英语 不知道怎么教小孩 如果这样的话 可以为孩子准备一些学习工具 但是 如果你还在用学校里发下来的磁带 光盘 那你就out了 现在手机端有很多好的学习APP 查老师亲自从应用市场下载并尝试 从老师的角度来给大家推荐几款 当
  • java与C#的比较

    一 C 和java哪个更好 几天前 我的北理工研究生面试 老师问了我这样一个问题 你认为C 和java哪个更好 那么 作为读者的你 会怎么回答这道题呢 其实 在我看来 这道题无非是想问你c 和java有什么异同 同为开发语言 并不能说哪个更
  • powerbi使用说明_PowerBI动态报告嵌入到PPT中,这个方法推荐给你

    PowerBI做出的可视化报表很炫酷 但目前做汇报用的最多的还是PPT 如何在PPT中动态演示PowerBI报表 就成了一个很头疼的问题 也是我平时最常被问到的问题之一 之前有一个做法是使用加载项PowerBI Tiles 不过它的体验并不
  • 使用mysql存储动态字段策略&&对于两个集合之间的数据封装问题

    使用mysql存储动态字段策略 对于两个集合之间的数据封装问题 一 使用mysql存储动态字段策略 字段表结构 数据表结构 专家表 二 对于两个集合之间的数据封装问题 专家评审表 专家库表 一 使用mysql存储动态字段策略 字段表结构 数
  • C语言CGI编程入门(一)

    C语言CGI编程入门 一 http www leavesongs com WEB CGIforC 1 html CGI是指web服务器调用编程语言编写的程序的一个接口 比如我们可以编写一个用户注册的页面 用户将其输入的邮箱 用户名 密码输入
  • 你必须要知道的8种基本排序方法

    1 选择排序 定义 首先 选出数组中最小的元素 将它与数组中第一个元素交换 然后找出次小的元素 并将它与数组中第二个元素交换 按照这种方法一直进行下去 直到整个数组排完序 交换次数 N 1 缺点 运行时间对文件已有序的部分依赖较少 从文件中