排序算法(二):时间复杂度为O(nlogn)的排序算法

本文详细介绍了时间复杂度为O(nlogn)的排序算法,包括希尔排序、堆排序和快速排序。希尔排序通过增量序列逐步调整数组,达到O(n^1.3)的时间复杂度;堆排序利用大顶堆或小顶堆原理,实现O(nlogn)的排序;快速排序则以分治策略为基础,平均时间复杂度同样为O(nlogn),但最坏情况下为O(n^2)。
摘要由CSDN通过智能技术生成

一、希尔排序(实际上很少用到,了解即可)

1、算法步骤

  1. 将待排序数组按照一定的间隔进行排序,如此时排序间隔为gap:则从index=gap处的元素开始排序;对于index = i的元素,每次和当前index - gap处的元素进行比较,直到符合插入条件;然后继续比较index = i++的元素,直到数组末尾,完成当前间隔的排序
  2. 逐渐缩小间隔进行下一轮排序
  3. 最后一轮时,取间隔为 1,也就相当于直接使用插入排序。但这时经过前面的「宏观调控」,数组已经基本有序了,所以此时的插入排序只需进行少量交换便可完成
    在这里插入图片描述

其中,每一遍排序的间隔在希尔排序中被称之为增量,所有的增量组成的序列称之为增量序列, 上图中增量序列为 [5, 2, 1]。增量依次递减,最后一个增量必须为 1

有一条非常重要的性质保证了希尔排序的效率:D(K+1)间隔有序的序列在经过D(K)间隔排序后仍然是D(K+1)间隔有序的,其中D(K+1) >= D(K)

2、算法实现

void shellSort(vector<int>& arr){
   
	//排序间隔循环
    for(int gap = arr.size() / 2; gap > 0; gap /= 2){
   

		/-------以下代码其实就是插入排序-----------/
    	//使用当前间隔进行排序,元素范围为`[gap, size()-1)
        for(int i = gap; i < arr.size(); i++){
   
        
        	//记录当前待插入元素 和 第一个被比较的元素
            int curNum = arr[i];
            int j = i - gap;
            
            //如果没有比较到首元素 或 带插入元素仍小于当前比较元素,继续比较
            while(j >= 0 && arr[j] > curNum){
   
                arr[j + gap] = arr[j];
                j -= gap;
            }

			//找到了插入位置j+gap(这里加gap是抵消最后一次-gap)
            arr[j + gap] = curNum;
        }
    }
}

3、算法性能

排序方式:in-place

希尔排序稳定性:不稳定

希尔排序时间复杂度:与增量序列有关,O(n)到O(n^2)之间,最好为O(n^1.3)

希尔排序空间复杂度:O(1)

4、增量序列的选择

1)Knuth增量序列(D1 = 1,Dk+1 = 3Dk + 1)

平均时间复杂度为O(n^1.5)

2)Hibbard增量序列(Dk = 2^k - 1)

最坏时间复杂度O(n^1.5),平均时间复杂度O(n^1.25)

3)Sedgewick增量序列(94^k - 92^k + 1 和 4^k - 3*2^k + 1序列交替构成)

最坏时间复杂度O(n^(4/3)),平均时间复杂度O(n^(7/6))

5、希尔排序算法与O(n^2)级别算法的本质区别

逆序对

当我们从小到大排序时,在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对

希尔排序突破O(n^2)的关键

对于随机数组,逆序对的数量是 O(n^2)级的,如果采用「交换相邻元素」的办法来消除逆序对,每次最多只能消除一组逆序对,因此必须执行 O(n^2)级的交换次数,这就是为什么冒泡、插入、选择算法只能到 O(n^2)级的原因。反过来说,基于交换元素的排序算法要想突破 O(n^2) 级,必须通过一些比较,交换间隔比较远的元素,使得一次交换能消除一个以上的逆序对。

二、堆排序(用的也比较少,快速排序比对排序要快)

大顶堆与小顶堆

堆是符合以下两个条件之一的完全二叉树:

  • 根节点的值 ≥ 子节点的值,这样的堆被称之为最大堆,或大顶堆;
  • 根节点的值 ≤ 子节点的值,这样的堆被称之为最小堆,或小顶
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值