算法第4版-笔记-排序-1

定义:排序就是将一组对象按照某种逻辑顺序重新排列的过程。

学习排序算法至少有三大实际意义

  1. 对排序算法的分析将有助于你全面理解比较算法性能的方法
  2. 类似的技术能有效解决其他类型的问题
  3. 排序算法常常是我们解决问题的第一步

最重要的是,我们将学到经典、优雅、高效的算法。

初级排序算法

排序关注的对象是数组元素,每个元素都有一个主键。排序的目的是将所有元素的主键按某种方式排列。排序后索引较大的元素的主键>=索引较小的(总之满足预期的顺序)。

大多数情况下,排序代码只会通过两个方法操作数据:

  1. 对元素的主键进行比较
  2. 将元素交换位置

评估算法的时间性能:各个排序算法在不同的随机输入下的基本操作的次数(包括:比较、交换、读写数组)

空间性能:额外内存开销。可根据额外内存开销将排序算法分为两类:

  1. 除了固定数目的实例变量之外无需额外内存的原地排序算法
  2. 需要额外内存空间来存储零一份数组副本的其他排序算法

选择排序

一种最简单的排序算法,步骤如下:

  1. 找到待排数组里最小的那个元素a
  2. 将a和数组的第一个元素交换位置
  3. 将数组的第一个元素排除出待排数组
  4. 待排数组重复1、2、3,直到整个数组都没有一个元素待排,此时整个元素都排好序了

这个算法叫选择排序因为它不断地选择剩余元素的最小者

对于长度为N的数组,选择排序大约需要N^2/2次比较和N次交换,时间复杂度应该是O(n^2)

选择排序有两个鲜明特点:

  1. 运行时间和输入无关
  2. 数据移动是最少的。交换次数和数组大小是线性关系,这在排序算法里很少见
//假设:
//已定义比大小函数less(a,b),返回a是否小于b
//已定义交换数组元素函数exch(nums,a,b),交换数组nums下标a和下标b的元素

void selectSort(vector<int>a){
    int num=a.size();
    for(int i=0;i<num;++i){
        int min=i;
        for(int j=i+1;j<num;++j){
            if(less(a[j],a[min]){
                min=j;
            }
            exch(nums,i,min);
        }
    }
}

插入排序

认为当前索引左边的所有元素有序,从右边依次挑选元素,插入到已经有序的元素中的适当位置

和选择排序不同的是,插入排序所需的时间取决于输入元素中的初始顺序。如果是一个有序的数组,它不需要哪怕一次元素交换

时间性能:对于随机排列的长度为N的数组,平均情况下插入排序需要N^2/4次比较和N^2/4次交换。最坏情况下需要N^2/2次比较和N^2/2次交换,最好情况下需要N-1次比较和0次交换。

void insertSort(vector<int>a){
    int num=a.size();
    for(int i=1;i<num;++i){
        for(int j=i;j>0&&less(a[j],a[j-1];--j){
            exch(a,j,j-1);
        }
    }
}

插入算法对一些部分有序的数组有奇效,甚至可能是最快的算法

插入排序需要的交换操作和数组中逆序对的数量相同,需要的比较次数大于等于逆序对的数量

每次交换都纠正了一个逆序对,当数组中逆序对数量为0时,排序就完成了

希尔排序

这是一种基于插入排序的快速的排序算法,它为了加快速度简单地改进了插入排序,交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。

希尔排序的思想:使数组中任意间隔为h的元素都有序,比如1…h+1…2h+1…,这几个元素有序。一个h有序数组就是h个互相独立的有序数组编织在一起组成的一个数组。在进行排序时,如果h很大,我们就能将元素移动到很远的地方,为实现更小的h有序数组创造方便。用这种方式,对于任意以1结尾的h序列,我们都能够将数组排序。

实现希尔排序的方法:对于每个h,用插入排序将h个子数组独立地排序。排序用插入排序,只需将移动元素的距离由1改为h即可。这样,希尔排序就转化为一个类似于插入排序但使用不同增量的过程。

希尔排序高效的原因:它权衡了子数组的规模和有序性。排序之前,各个子数

组都很短,排序之后子数组都是部分有序的。这两种情况都很适合插入排序。

希尔排序的性能:不知道,最坏是O(N^{3/2})

void shellSort(vector<int>a){
    int num=a.size();
    int h=1;
    while(h<num/3){
        h=3*h+1;
    }
    while(h>=1){
        for(int i=h;i<num;++i){
            for(int j=i;j>=h&&less(a[j],a[j-h]);j-=h){
                exch(a,j,j-h);
            }
        }
        h=h/3;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值