第五章:排序算法

第五章:排序算法1

本章结构
内部排序
外部排序
三大经典排序算法
特殊排序算法
插入排序
选择排序
交换排序
归并排序
基数排序

Part1:内部排序2

1、三大经典排序算法

1.1 插入排序

将待排序记录插入到已排好序的序列中

  1. 直接插入排序

    每次将一个记录使用顺序查找3,插入到前面已经排好序的子序列中

请添加图片描述

  1. 折半插入排序

    在1的基础之上,对子序列进行折半查找

  2. 希尔排序(Shell Sort)

    先追求表中元素部分有序,然后逐渐逼近全局有序。每次有n个记录使用直接插入排序(n=length/distance)

    具体操作:选择一个距离d,另表中相距d的元素之间使用直接插入排序,另d=d/2,重复该过程

请添加图片描述

扫描二维码关注公众号,回复: 13638090 查看本文章

1.2选择排序

每次均从无序序列中找到一个最值,并且放入有序序列中,并将其从无序序列中删除

  1. 简单选择排序

    遍历无序序列,从中找到最值并且固定,从剩下的无需序列中重复该过程

  2. 堆排序4

    • 堆:即用顺序结构存储的完全二叉树

      • 大根堆:根结点>左右孩子(就算是数值上相同,也认为是严格大于)
      • 小根堆:根结点<左右孩子
    • 具体操作(以大根堆为例)

      将无序序列视为堆,并将其成为大根堆,从而选出最大值,并且加入有序序列,对剩下的序列重复该操作即可

请添加图片描述

1.3交换排序

根据比较结果,交换两个元素在序列中的位置,故称为交换

  1. 冒泡排序

    比较两个相邻元素的值,如果不符合序,则交换他们。

    在这个过程中,各个元素会逐渐到达他们最终的位置,就像水底的气泡向上冒一样,故称之为冒泡排序。(每次均可确定一个最值)

请添加图片描述

  1. 快速排序5

    基本思路:挖坑填树+分治法

    即选择一个基数,对数组分区(左边均小于这个基数,右边均大于这个基数),对左右区间重复该过程直到左右区间只有1或者0个数。

请添加图片描述

2、特殊排序算法

2.1 归并排序(Merge Sort)

将n个有序的序列合并为1个成为n路归并,而归并排序,是将原来含有n个元素的无序序列视为n个有序的序列,然后归并

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B7nK3qf7-1641112616224)(./image/chapter05/6.jpeg)]

2.2 基数排序(Radix Sort)

基本思想:通过比较元素各位大小,然后排序

实现思路:采用一个辅助队列,先比低位,按序入队并出队,然后再比较高位,重复

请添加图片描述

Part2:外部排序

由于数据元素太多无法一次性调入内存,故只能每次一部分一部分的调入内存排序,称为外部排序。

1、实现思路

在内存中开辟n个缓冲区(n >= 2+1)6将数据元素分区读入,然后

  • 缓冲区内部使用内部排序使其有序
  • 缓冲区之间使用归并排序,使其生成初始归并段并写回外存
  • 从外存中读取不同的归并段,并使用归并排序,写回外存,重复至归并段只有一个

请添加图片描述

2、对该过程的分析

每次排序,都需要读写in缓冲区(1中的例子)个数的磁盘块(Block)由于磁盘块读写时间远大于内部排序和归并排序的时间,所有影响该过程的时间因素主要是磁盘读写时间。

设Block个数为x,采用k路归并(in缓冲区个数有k个),归并次数为m次,r为初始归并段个数
磁 盘 读 写 次 数 = 2 ∗ x + m ∗ 2 ∗ x 磁盘读写次数=2*x+m*2*x =2x+m2x
其中

  • 第一个2x表示生成初始归并段所需要读写的次数(读入为x次,写入为x次)

  • 第二个部分m2x表示归并排序所需读写次数


m = ⌈ l o g k r ⌉ r = ⌈ l o g k x ⌉ m=\lceil log_k r\rceil \\ r=\lceil log_k x\rceil m=logkrr=logkx
由于x无法改变,所以我们只能考虑减小m来减少磁盘读写时间

  • 增大k——多路平衡归并——败者树优化
  • 减小r——增加归并段的长度——置换-选择排序

3、败者树

采用多路平衡归并需要付出两个代价,一个是需要多片缓冲区,一个是需要k-1次的关键词对比,为了优化多路平衡归并,只能从k-1次的关键词对比下手了。

在k-1次对比中,如果不是第一次对比,那么可以根据以往的比较记录快速比较出最值,即败者树。

通常以一颗完全二叉树来表示这种数据结构,其叶子节点表示元素,非叶子节点表示失败者;

请添加图片描述

4、置换-选择排序

设外部排序有m个记录,而in缓冲区中可存放n个记录,则初始归并段数量为(m>>n)
⌈ m / n ⌉ \lceil m/n \rceil m/n
可以使用置换-选择排序来增大归并段长度,从而减少归并段数量

基本思想:采用一个temp来记录当前段的最大值,并且不断输出可用最小值,知道无可用最小值为止,这样为一段。重复该过程

请添加图片描述

通过置换-选择排序生成的归并段长度是不同的,这样子就造成了一个问题,把这些长度不同的归并段写回外存的开销是不同的,显然长度越长,开销越大。这就相当于给这些归并段赋予了权重,我们可以采用哈夫曼树的思想来优化,即为最佳归并树

5、最佳归并树

例如当我们有5个归并段,采用二路归并时

请添加图片描述

同理可以扩展至k路归并

请添加图片描述

对于k叉归并(k>2),有时归并段的数量不满足严格k叉树,这个时候我们就要补充几个长度为0的虚段使其满足。(技巧,如果题目中只告诉你目前有几个归并段,和k的值,那么将归并段权重假设为一样即可,这样子一下就可看出需要补充几个虚段)

请添加图片描述

Part end:参考文献和一些说明:


  1. 对本章结构的一些说明:根据数据元素是否在内存中,将排序算法分为内部排序和外部排序。 ↩︎

  2. 在三大经典算法中,所有加速过的算法均是不稳定的(希尔,堆,快速),而简单算则排序也是不稳定的,其余算法均为稳定的 ↩︎

  3. 注意这里的顺序查找是从后面往前面查找,以从小到大排序为例,如果该记录更小一些,那么后面的元素后移,记录插入到空出来的位置。所以对于已经排序的序列只需要对比n次即可 ↩︎

  4. 注意将关键词依次插入到初始为空的大根堆中,和将关键字序列直接成堆最后得到的序列不同,做题时要注意! ↩︎

  5. 这个部分全部参考自:https://blog.csdn.net/morewindows/article/details/6684558 ↩︎

  6. 2表示2个读入缓冲区,1表示一个输出缓冲区 ↩︎

猜你喜欢

转载自blog.csdn.net/qq_45712772/article/details/122277779