数据结构之简单排序(浙大mooc笔记)

简单排序的定义(浙大mooc学习笔记)


常用命名格式: void X_sort(ELementType A[],int N)
大多数情况下,为简单起见,讨论 从小到大排序

默认条件:

1.N是正整数
2.只讨论基于比较的排序(> = < 有定义)
3.只讨论内部排序
4.稳定性:任意两个相等的数据,排序前后的相对位置不发生改变

重要的一点:没有任何一种排序是任何情况下都表现最好的

冒泡排序

图例:

冒泡排序

原始的冒泡排序:

void Bublle_Sort(ElemenType A[],int N)
{
    for(p = N - 1; p >= 0; p--){
        for(i = 0; i < p ;i++){/*一趟冒泡*/
            if(A[i]>A[i+1]){
                Swap(A[i],A[i+1]);
            }
        }
    }
}

存在的问题:如果在排序途中,序列已经是有序的了,此时排序还是会运行进行比较

冒泡排序的改进:

void Bublle_Sort(ElemenType A[],int N)
{
    for(p = N - 1; p >= 0; p--){
        flag = 0;/*初始状态,未交换*/
        for(i = 0; i < p ;i++){/*一趟冒泡*/
            if(A[i]>A[i+1]){
                Swap(A[i],A[i+1]);
                flag = 1;/*标识发生了交换*/
            }
        }
        if(flag == 0)break;/*全程无交换*/
    }
}

当全程无交换时,自动跳出循环

冒泡排序的时间复杂度

最好情况:顺序(一遍过)   T = O ( N ) T = O(N) T=O(N)
最坏情况: 逆序(全部逆序)   T = ( ( n ) + ( n − 1 ) + ⋯ + ( 2 ) + ( 1 ) ) = n ∗ ( n − 1 ) 2 = O ( N 2 ) T = \left((n)+(n-1)+\cdots+(2)+(1)\right) = \frac{n*(n-1)}{2} =O(N^2) T=((n)+(n1)++(2)+(1))=2n(n1)=O(N2)

思考

如果元素使用链表存储,该怎么写冒泡排序?

冒泡排序是否稳定?

稳定


插入排序

插入排序可以理解为打扑克牌时的理牌方法。
插入排序

代码描述

伪码描述如下:

void Insertion_Sort(ElementType A[],int N)
{
    for(p = 1; p < N; p++){/*从1开始而不是从0开始,因为手牌只有一张的时不需要排序*/
        Tmp = A[p];/*摸下一张牌*/
        for(i = p; i > 0 && A[i-1] > Tmp; i--)/*与手里的牌一一对比*/
            A[i] = A[i-1];/*移出空位,把原来的牌往后移*/
        A[i] = Tmp;/*新牌落位*/
    }
}

复杂度

最好情况:顺序(不需要错位,例如:3、4、5、6、7)       T = O ( N ) T=O(N) T=O(N)
最坏情况:逆序(每摸一张牌,把原来的牌往后错一位)       T = 1 + 2 + ⋯ + n = O ( n 2 ) T=1+2+\cdots+n=O(n^2) T=1+2++n=O(n2)

与冒泡排序的比较

冒泡排序是两两元素互换,交换过程有3步。
插入排序是每个元素向后移位,最后一次性将元素插入。

插入排序是否稳定?

稳定

例题

1.给定初始序列 { 34 , 8 , 64 , 51 , 32 , 21 } \{34,8,64,51,32,21\} {34,8,64,51,32,21},冒泡排序和插入排序分别需要多少次元素交换才能完成?
解:冒泡排序9次,插入排序9次

2.对一组包含10个元素的非递减有序序列,采用插入排序排成非递增序列,其可能的比较次数和移动次数分别是
A. 45, 44
B. 54, 63
C. 100, 54
D. 100, 100

答案:A
解析:他问的是可能的比较次数和移动次数分别是多少,那我们就假设原理就是全部递增的,插入排序后要求全部递减,这样的比较次数应该是最多的。


时间复杂度下限

逆序对

对于下标i<j,如果a[i]>a[j],则称**(i,j)**是一对 逆序对。(也就是不符合递增的数对)

例题: { 34 , 8 , 64 , 51 , 32 , 21 } \{34,8,64,51,32,21\} {34,8,64,51,32,21}中有多少逆序对?

解答:(34,8),(34,32),(34,21),(64,51),(64,32),(64,21),(51,32),(51,21),(32,21)
可以看到,有9个逆序对。在前面我们知道,对于这个序列,冒泡排序和插入排序都需要交换9次元素。

可以得出:
插入排序: T ( N , I ) = O ( N + I ) , 其 中 N 为 序 列 中 元 素 个 数 , I 为 序 列 中 逆 序 对 个 数 T(N,I)=O(N+I),其中N为序列中元素个数,I为序列中逆序对个数 T(N,I)=O(N+I),NI

可以知道,如果一个序列基本有序,那么插入排序运行起来会很快。

两个定理

  • 任意 N N N个不同元素组成的序列平均具有 N ( N − 1 ) 4 N(N-1)\over4 4N(N1) 个逆序对

  • 任意仅以交换相邻两元素来排序的算法,其平均时间复杂度为 Ω ( N 2 ) \Omega(N^2) Ω(N2)

这意味着,如果要提高算法效率我们必须:

  • 每次消去不止一个逆序对
  • 每次交换相隔较远的两个元素。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值