选择排序的基本思想:每一趟(如第i趟)在后面n-i+1(i=1,2,3,...,n-1)个待排序元素中选取关键字最小的元素,作为有序子序列的第i个元素,直到第n-1趟做完,待排序元素只剩下1个,就不用再选了。选择排序中的堆排序是历年考查的重点。
(独特性)考题:排序过程中的比较次数与序列初始状态无关的是选择排序法。
堆排序,二轮的时候,再梳理逻辑,自己再做一个。(留了个坑要填)
1.简单选择排序
简单选择排序算法的思想是:我们在n个数里选出最小的那个数放进A[0],然后再在剩下的n-1个数里选出最小的那个数放进A[1]......总计选择n-1次即可得到有序序列。
原理:每一趟从待排序的数据元素中选择最小(或最大)的一个元素作为首元素,直到所有元素排完为止。
简单选择排序法就是通过n-p次关键字间的比较,从n-p+1个记录中选出关键字最小的记录,并和第p(1≤p≤n)个记录交换。
可以看出,简单排序比较机械。
代码:
算法性能分析:
可以自己形成这种思想,当一些知识点可以自己举简单的例子进行证明。
简单选择排序按不同视角被分到:
- 不稳定排序
- 简单排序
- 内排序
- 选择排序
2.堆排序
注:非常重要,为高频考点。
总览:
概念:
两张图进行自我的检验(第一反应就知道图的意思,就说明基本掌握):
大根堆
小根堆
2.1前言
前言:简单选择排序我们选择了n-1次最小数,每次选择最小数时我们需要比较很多次,这些比较有的在上一次选择时已经比较过了,我们并没有存储比较的信息导致之后还会重复比较很多次。堆排序可以在选择最小数的时候对已经比较过的信息进行合理利用,这样会显著提高选择的效率。堆排序用到了堆这个数据结构。(突破点就是储存比较的信息)
注:根据前沿进行回归,更有逻辑
2.2预备知识点
- 堆:堆用数组储存,逻辑结构被看成一个近似的完全二叉树,分为大顶堆和小顶堆。
- 大顶堆:每个结点的值都大于或等于其左右孩子结点的值的完全二叉树。
- 小顶堆:每个结点的值都小于或等于其左右孩子结点的值的完全二叉树。
- 堆排序算法:将待排序列构造成一个大顶堆,然后将堆顶的最大值放与堆数组的末尾元素交换。将剩余的n-1个序列重新构造成一个堆,然后将此时堆顶的最大值与此时堆数组的末尾元素交换。如此反复执行,便能得到一个有序序列。
解决的问题:
和简单选择排序对比我们就能发现,堆排序其实就是利用了堆这个数据结构来选择最值,然后放入该放的位置。实现这个算法需要解决两个问题 :
- 如何由一个无序序列构成一个堆?
- 如何在输出堆顶元素后,调整剩余元素成为一个新的堆?
(可以又此启发,我们可以通过自己发问这个算法解决了什么问题,来自我引导式的复习。)
二轮的代码
先看代码
问题一的解决为什么用到了问题二的HeapAdjust函数?我们先分析HeapAdjust函数,我们在堆中将堆顶的数和堆数组最后一个数交换,此时堆顶的数就不是最大的数了,我们就要调整这个堆使之还是大顶堆,那我们可以将堆顶的关键字与它的左右孩子关键字中最大的比较,如果比孩子关键字小,那我们交换它们,然后继续向下比较,直到没有发生交换那我们就得到了一个新的堆。我们在代码中继续解析:
问题二已经解决了,问题一怎么解决呢?HeapAdjust函数就是解决只有堆顶元素位置不对,其余部分已经是一个大顶堆的情况,那么我们就这个图而言,我们解决④号结点,然后解决③、②、①号,我们就建好一个大顶堆了,也就是说我们要从下而上解决的是所有非终端结点共计N/2个。
for(p=N/2; p>0; p--) HeapAdjust(A[p],A[N]);
算法分析
堆排序建堆的时间复杂度为O(n),更改堆元素后重建堆的时间复杂度为O(nlogn),所以堆排序的最好、最坏时间复杂度都为O(nlogn),堆排序的空间复杂度为O(1)。
稳定性分析:假如上图④和⑥都是相同的关键字,建堆的过程中⑥跑到③,④没变,稳定性被破坏,所以堆排序是不稳定排序。
堆排序按不同视角被分到:
- 不稳定排序
- 改进排序
- 内排序
- 选择排序
堆也支持插入操作,将新结点放在堆的末端,再对这个新结点向上执行调整操作。
n个结点的堆中插入或删除一个元素的时间复杂度为O(logn)
通常,取一大堆数据中的K个最大(最小)元素时,都优先使用堆排序。
2.3常考知识点
2.4错题