排序算法(二)选择&插入

选择排序

思路:

在一组数中找到最大者后,拿出,再去该组数中找到最大者,直到空

有点像 冒泡排序 但比冒泡排序少了反复比较的步骤

找到最大者后直接放在了最后的位置,而不是一步步交换到该位置

每次在未排序部分找到最大元素,放到已排序部分的最前端

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²

插入排序也是输入敏感型算法

在这里插入图片描述

嗯,这两个排序先写到这,以后学了什么再回来更新

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值