数据结构中八大排序的实例分析和总结(直接插入排序、希尔排序、简单选择排序、堆排序、冒泡排序、快速排序、归并排序和桶排序)

排序

这里我分析的是内部排序,外部排序没有进行分析,总结如下
在这里插入图片描述

接下来我将对我的总结进行定向的分析
一共分析的是八个排序
分别是:

1.插入排序—直接插入排序
2. 插入排序—希尔排序
3. 选择排序—简单选择排序
4. 选择排序—堆排序
5. 交换排序—冒泡排序
6. 交换排序—快速排序
7. 归并排序
8. 桶排序/基数排序

1.插入排序—直接插入排序

基本思想:将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
要点:设立哨兵,作为临时存储和判断数组边界之用。 实例如下
在这里插入图片描述
如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
算法的实现如下
在这里插入图片描述在这里插入图片描述

时间复杂度是:O(n^2)

分析: 1>时间复杂度分析 最坏情况:序列是逆序的,总的执行次数是n(n-1)/2;因此时间复杂度是O(n^2);;

2>空间复杂度分析 根据代码,很容易就可以看出,空间复杂度是O(1)

理解:直接插入排序,一趟是无法排序好的,而且值得注意的是
我们可以看出,对于直接插入排序,在最后一趟排序前,这个序列没有任何一个数据达到最终的位置,我觉得这应该是插入类排序的共同特点

2.插入排序—希尔排序

这个排序的代码我不会写,但是我会手算排序到某一个阶段序列是什么样的

基本思想:将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
如图可以看到 在这里插入图片描述
原理还是相当的好理解的,就是分块排序,然后再把每一块排序好,主要就是递归思想和分块的方法,能准确的分块就没问题了

这个是我在网上找到的代码,不是参考资料打出来的,截图到这里看一下
在这里插入图片描述在这里插入图片描述

具体的代码分析我就不写了 分析: 1>时间复杂度分析 希尔排序的平均情况是O(nlog2n) 2>空间复杂度分析 空间复杂度是O(1)

理解:希尔排序的增量的取法要注意,首先增量的最后一个值一定是1;其次增量序列中的值没有除1之外的公因子
比如8,4,2,1这样的序列就不要去(8、4、2有公因子2)

3. 选择排序—简单选择排序

基本思想:在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
实例:
在这里插入图片描述
代码如下
在这里插入图片描述在这里插入图片描述

分析:
3>时间复杂度分析 总的执行次数是(n-1+1)(n-1)/2=n(n-1)/2;因此时间复杂度是O(n^2);;

4>空间复杂度分析 根据代码,很容易就可以看出,空间复杂度是O(1) 这里的代码是每次只能排序一个数据 我在网上深入的了解了一下,有改进以后的代码
简单选择排序,每趟循环只能确定一个元素排序后的定位。我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。改进后对n个数据进行排序,最多只需进行[n/2]趟循环即可。具体实现如下:
在这里插入图片描述

4.选择排序—堆排序

堆排序是一种树形选择排序,是对直接选择排序的有效改进。 基本思想:
堆的定义如下:具有n个元素的序列(k1,k2,…,kn),当且仅当满足
在这里插入图片描述
时称之为堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最小项(小顶堆)。
在这里插入图片描述
初始时把要排序的n个数的序列看作是一棵顺序存储的二叉树(一维数组存储二叉树),调整它们的存储序,使之成为一个堆,将堆顶元素输出,得到n
个元素中最小(或最大)的元素,这时堆的根节点的数最小(或者最大)。然后对前面(n-1)个元素重新调整使之成为堆,输出堆顶元素,得到n
个元素中次小(或次大)的元素。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。称这个过程为堆排序。
因此,实现堆排序需解决两个问题:

  1. 如何将n 个待排序的数建成堆;
  2. 输出堆顶元素后,怎样调整剩余n-1 个元素,使其成为一个新堆。

首先讨论第二个问题:输出堆顶元素后,对剩余n-1元素重新建成堆的调整过程。 调整小顶堆的方法: 1)设有m
个元素的堆,输出堆顶元素后,剩下m-1
个元素。将堆底元素送入堆顶((最后一个元素与堆顶进行交换),堆被破坏,其原因仅是根结点不满足堆的性质。
2)将根结点与左、右子树中较小元素的进行交换。 3)若与左子树交换:如果左子树堆被破坏,即左子树的根结点不满足堆的性质,则重复方法 (2).
4)若与右子树交换,如果右子树堆被破坏,即右子树的根结点不满足堆的性质。则重复方法 (2).
5)继续对不满足堆性质的子树进行上述交换操作,直到叶子结点,堆被建成。 称这个自根结点到叶子结点的调整过程为筛选。如图:
在这里插入图片描述
代码很复杂,我没有写,在网上找到有截图,可以了解一下
在这里插入图片描述在这里插入图片描述在这里插入图片描述

分析 1>时间复杂度 O(nlog2n) 2>空间复杂度 空间复杂度是O(1)
堆排序同树的运用很紧密,想要掌握相关的知识,要对树理解透彻,以及明天堆排序的原理

5. 交换排序—冒泡排序

基本思想:
在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
实例如下
在这里插入图片描述
冒泡排序的算法的结束条件是在一趟排序中没有元素发生改变 算法的实现如下
在这里插入图片描述
1.设置一标志性变量pos,用于记录每趟排序中最后一次进行交换的位置。由于pos位置之后的记录均已交换到位,故在进行下一趟排序时只要扫描到pos位置即可。
改进后算法如下:
在这里插入图片描述
2.传统冒泡排序中每一趟排序操作只能找到一个最大值或最小值,我们考虑利用在每趟排序中进行正向和反向两遍冒泡的方法一次可以得到两个最终值(最大者和最小者)
, 从而使排序趟数几乎减少了一半。 改进后的算法实现为:
在这里插入图片描述
分析 1>时间复杂度 双重循环,显然复杂度是O(n^2) 2>空间复杂度 根据代码很容易就能看出来是O(1)

6.交换排序—快速排序

基本思想: 1)选择一个基准元素,通常选择第一个元素或者最后一个元素,
2)通过一趟排序讲待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另一部分记录的 元素值比基准值大。
3)此时基准元素在其排好序后的正确位置 4)然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序。 示例:
在这里插入图片描述

代码如下
在这里插入图片描述在这里插入图片描述

分析: 1>时间复杂度 最坏的时候是O(n^2),最好的时候是O(nlog2n) 2>空间复杂度 O(log2n)
特点:快速排序并不快,当给定的数据的顺序越有序时,排序需要的时间越多 就平均时间复杂度而言,快速排序是最好的

7. 归并排序

基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
示例:
在这里插入图片描述
具体的方法是这样的 设r[i…n]由两个有序子表r[i…m]和r[m+1…n]组成,两个子表长度分别为n-i +1、n-m。
1.j=m+1;k=i;i=i; //置两个子表的起始下标及辅助数组的起始下标
2.若i>m 或j>n,转⑷ //其中一个子表已合并完,比较选取结束
3.//选取r[i]和r[j]较小的存入辅助数组rf 如果r[i]<r[j],rf[k]=r[i]; i++; k++; 转⑵ 否则,rf[k]=r[j]; j++; k++; 转⑵
4.//将尚未处理完的子表中元素存入rf 如果i<=m,将r[i…m]存入rf[k…n] //前一子表非空 如果j<=n , 将r[j…n] 存入rf[k…n] //后一子表非空
5.合并结束 这个排序的算法掌握情况只需要了解原理会用就行了 下面是两路归并排序的代码 在这里插入图片描述
分析: 1>时间复杂度 平均状态下是O(nlog2n) 2>空间复杂度 O(n)
特点:归并排序的时间复杂度与初始序列无关,因此这里是没有最好和最坏的区分的,复杂度的变化只受数据的个数的影响

8. 桶排序/基数排序

基本思想:是将阵列分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。当要被排序的阵列内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是
比较排序,他不受到 O(n log n) 下限的影响。 简单来说,就是把数据分组,放在一个个的桶中,然后对每个桶里面的在进行排序。
这个就简单带过一下吧,用的太少了 然后代码是这样的
在这里插入图片描述

关于这次的八种排序我来一个总结
在这里插入图片描述

这个是一定要掌握的,应用于考试上
然后下面的就是具体的分析了
我是根据时间复杂度来记忆的:

(1)平方阶(O(n2))排序   
各类简单排序:直接插入、直接选择和冒泡排序;

(2)线性对数阶(O(nlog2n))排序  
快速排序、堆排序和归并排序;

(3)O(n1+§))排序,§是介于0和1之间的常数。
希尔排序

(4)线性阶(O(n))排序   
基数排序,此外还有桶、箱排序。

对于具体的应用的时候
当原表有序或基本有序时,直接插入排序和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n);

而快速排序则相反,当原表基本有序时,将蜕化为冒泡排序,时间复杂度提高为O(n2);
原表是否有序,对简单选择排序、堆排序、归并排序和基数排序的时间复杂度影响不大。(强烈建议背下来,在考研数据结构的书上看到的)

稳定性:(主要应用于考试方面的总结)
排序算法的稳定性:若待排序的序列中,存在多个具有相同关键字的记录,经过排序, 这些记录的相对次序保持不变,则称该算法是稳定的;若经排序后,记录的相对 次序发生了改变,则称该算法是不稳定的。

稳定性的好处:排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。基数排序就是这样,先按低位排序,逐次按高位排序,低位相同的元素其顺序再高位也相同时是不会改变的。另外,如果排序算法稳定,可以避免多余的比较;
稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序
不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序
对于这次的学习,有一部分的代码我是在网上找到的,用编译器去实现了一下,然后查阅的资料有课本,考研总复习的数据结构笔记以及网上的别人写的代码

最后加上了我自己的总结和理解,总的来说收获还是很大的,在未整理以前,我做到的是能够灵活的考试,现在我对代码的理解加深了,能初步的自己独立的编写以及改良代码

  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值