【知识框架】
排序的稳定性:
就是如果排序前 2个变量A\B的值都是1,且他们是A B这样排的,排序完后他们变成B A这样排了,就说明这个排序算法不稳定(算法优劣与稳定性无关
内部排序:排序时,元素全部放在内存中排序
外部排序:排序时,元素在内外存间移动
插入排序
直接插入排序
第一个直接不选,从第二个开始,把第二个数值给哨兵,然后开始从第二个向前比较
折半插入排序
假设现在移动55,先用折半查找对55前面搜一下55要插到哪(因为前面都是已经排好序的 有序的)找到后发现55要插到5,于是把5~7的都往右移,然后把55插进去,这样节省了查找时间
希尔排序(基于顺序表,链表不行)
先追求表中的元素部分有序,再逼近全部有序
先将待排序表分割成若干形如L[i,i+d,i + 2....i+kd]的“特殊”子表,对各个子表
分别进行直接插入排序。缩小增量d,重复上述过程,直到d=1为止。
第一趟后 ↓
第二趟后 ↓
总体的来看
希尔本人建议:每次将增量缩小一半
但是考题可能会规定不同的每次的增量
交换排序
根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置
冒泡排序
这就不用说了吧!
快速排序
刚开始先取一个元素pivot作为枢轴/基准,通常取首元素,然后通过一次快排,把小于pivot的放在前面,大于pivot的放在后面 ,pivot放在中间,然后把大于的和小于的看做2个字表,再递归进行快排(完成第i次排序后,有i个元素到达他该在的位置)
当序列已经有序时最慢!
当每次递归的第一个是pivot能刚好分成左右2个一样大的子表时最快!
选择排序
选择排序的比较次数与初态无关
简单选择排序
堆排序
顶层互换后可能需要下坠
排好后87在顶 然后直接和最后的09调换,然后把87排除在外。
将09在上部分进行下坠,然后再把堆顶元素和堆底最后的调换
在堆中插入新元素
对于小根堆,新元素放到表尾,与父节点对比,若新元素比父节点更小,则将二者互换。新元素就这样一路“上升",直到无法继续上升为止
在堆中删除元素
被删除的元素用堆底元素替代,然后让该元素不断“下坠",直到无法下坠为止
归并排序(稳定)
j先合并完,超出长度后,把左边表剩下的全部移过来就行
把两个有序序列合二为一叫二路归并
四路归并就是4个有序数组 四合一
空间复杂度来自于辅助数组
基数排序(会手算就行)
排完后,关键字按“递减”排序
不能对float 和 double型实数进行排序
1、排个位
2、从Q9往Q0收集个位
3、排十位
4、从Q9往Q0收集十位
5、排百位
6、从Q9往Q0收集百位
外部排序
磁盘读写数据以块为单位
内存不够东西放,要在外存进行排序
优化:用多路归并,增加路数k,减少读写时间
k:路数,r:归并段数
败者树(考差不多,手算
对于k路归并,第一次构造败者树需要对比关键字k-1次
第一次选出1位最小的
然后1的那个位置就空缺了 这时候就把1所在的归并段3的下一个提上去,再进行败者树,但这时并不需要全部重新比较,所以节约了比较次数
置换-选择排序(生成初试归并段)
↓ 假设工作区WA能容纳3个
设初始待排文件为FI,初始归并段输出文件为FO,内存工作区为WA, FO和WA的初始状态为空,WA可容纳w个记录。置换选择算法的步骤如下:
1)从FI输入w个记录到工作区WA。
2)从WA中选出其中关键字取最小值的记录,记为MINIMAX记录。
3)将MINIMAX记录输出到FO中去。
4)若FI不空,则从FI输入下一个记录到WA中。
5)从WA中所有关键字比MINIMAX记录的关键字大的记录中选出最小关键字记录,作为新的MINIMAX记录。
6)重复3) ~5),直至在WA中选不出新的MINIMAX记录为止,由此得到一个初始归并段输出一个归并段的结束标志到FO中去。
7)重复2) ~6),直至WA为空。由此得到全部初始归并段。
最佳归并树
↑叶子结点的权值是代表该归并段的长度
标准的三路归并树长这样
但如果减少一个归并段,则最后一次归并就无法三路归并了,只能两路归并了
正确的做法是加一个权值为0的虚段
注意:对于k叉归并,若初始归并段的数量无法构成严格的k叉归并树,
则需要补充几个长度为0的“虚段”,再进行k叉哈夫曼树的构造。
①若(初始归并段数量-1) % (k-1) = 0,说明刚好可以构成严格k叉树,此时不需要添加虚段
②若(初始归并段数量-1) % (k-1) = u ≠ 0,则需要补充(k-1)- u个虚段