选择排序
思路:
在一组数中找到最大者后,拿出,再去该组数中找到最大者,直到空
有点像 冒泡排序 但比冒泡排序少了反复比较的步骤
找到最大者后直接放在了最后的位置,而不是一步步交换到该位置
每次在未排序部分找到最大元素,放到已排序部分的最前端
template <typename T>
void List<T>::select_sort(Posi(T) p, int n){
Posi(T) header = p->pred;
Posi(T) tailer = p;
while(0 < n--)
tailer = tailer->succ;
while(1 < n){
insert_before(tailer,remove( select_max(header->succ, n) ));
tailer = tailer->pred;
n--;
}
return ;
}
//tailer是通过 while 循环到 n 处的,因为不能直接做加法吧,需要一步步遍历到
//在排序中只需要排到倒数第二个元素,每次都忘也是没救了
//不能写成 while( n-- ) , 会优先对 n 减 1 ,这样在选择循环中,就缺失了一个元素
// n 是 int 类型,表示需要判断的数量
template<typename T>
Posi(T) List<T>::select_max(Posi(T) p , int n ){
Posi(T) max = p;
Posi(T) current = p->succ;
while(1 < n--){
if(current->data >= max->data)
max = current;
current = current->succ;
}
return max;
}
//current 作用等同于 for 语句中的 i
//怎么说,就是普通的遍历了一遍
//要注意的是那个 >= ,因为可以取相同的元素,若遇到,取最后的元素
//先取最后的元素插入,维持了算法的稳定性
//若是严格大于的话,顺序就反过来了,若没有比 p 大的,就取当前的 p
复杂度分析:
虽然 insert_before , remove 可以看成常数时间
但实际应用中,会*100 ,这么看的话,这个复杂度就不是很美好了
select_max 要 O(n),select_sort 也要遍历 n 次
整体复杂度 O(n²),好家伙,比冒泡效率好了那么一点?
毕竟移动次数少了,n ——> 1
优化思路:
等我学到第十章回来更新
插入排序
思路:
假如你在玩扑克牌,你手里的牌已经排好序了
这时有一张新发下来的牌,你要根据新发下来牌的大小
插入不大于它大小的那张牌的 后面
减而治之的过程, r 加一
!:和选择排序并不是特别一样,不如说完全不一样
选择排序:
无序部分和有序部分是有关联的,有序部分在后
无序部分的最大者 < 有序部分的最小者
插入排序:
无序部分和有序部分无关,不然你要做老千吗
有序部分在前
具体过程:
设有序部分为 r (刚开始 r == 0),每次取未排序部分的第一个元素
在已排序部分中找到合适的位置,插入
问题规模减少,至多经历 n 次,就排好啦
template <typename T>
void List<T>::insert_sort(Posi(T) p, int n){
int r = 0;
while(r < n){
insert_after( search( p->data , r , p) ,p->data);
p = p->succ;
remove(p->pred);
r += 1;
}
return ;
}
// p 代表 未排序部分每次取出的第一个元素
//search 以 p 为终点的 r 个前驱中,找到不小于 p->data 的最后一个元素
//如果数值相同,insert_after 维持了稳定性
//remove 移除的是最开始的 p 自己,插入的应该是 p 的复制品,所以会多出来
复杂度分析:
在最好情况下,所有的元素都是排序的,此时只需要比较一次
整体复杂度 O(n)
空间上也很美好,只需要 p 的复制空间 O(1),inplace-algorithm
但处于最坏情况时(完全逆序)
需要进行 r 次比较,循环 n-1 次,整体O(n²)
平均来讲:不想打符号…
逆序对:
(这里可能有些表达不清)
首先定义逆序对,两个元素,中间可以有间隔,前者严格大于后者
可以有多个元素严格大于一个元素,并把这个属性加在后者
比如 ,有 n 个元素严格大于 p ,此时 p 的属性为 n
一组数据的逆序对最多有 n² 个
逆序对和插入排序的关系
已知前半部分是有序的,那元素 p 必定会插入有序部分中
相当于把有序部分一分为二,p和后者形成逆序对的关系(此时未插入)
在插入过程中,p需要依次和后部分比较并跨过
假设需要 i 次,也就是有序部分后部分的长度,这是一个元素需要的
那全部次数是 i 求和(全部的未排序部分),I 次
那插入排序的复杂度就可以写成O(I + n)//插入O(1),累积为 n
最好情况,I = 0 ;最坏情况 ,I = n²
插入排序也是输入敏感型算法
嗯,这两个排序先写到这,以后学了什么再回来更新