• 数据结构:冒泡排序及其改进、插入排序和希尔排序


    前提

    void X_Sort ( ElementType A[], int N )

    • 大多数情况下,为简单起见,讨论从小大的整数排序
    • N是正整数
    • 只讨论基于比较的排序(> = < 有定义)
    • 只讨论内部排序(若内存小于数据大小,则需要外部排序)
    • 稳定性:任意两个相等的数据,排序前后的相对位置不发生改变
    • 没有一种排序是任何情况下都表现最好的

    简单排序

    冒泡排序

    基础冒泡

    • 从第1个泡泡开始,大的下沉,沉到不能沉为止,此时第n个泡泡最大。
    • 从第i个泡泡开始,大的下沉,沉到不能沉为止,比较到n-i个泡泡即可。
    void Bubble_Sort( ElementType 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]);
    }
    }
    }
    }
    

    加强版冒泡

    • 用一个flag来标记,若一趟下来,不发生交换,则说明排序完成。
    void Bubble_Sort( ElementType 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^2 )

    优点

    • 易于实现
    • 对数组 链表都没问题
    • 稳定的

    缺点

    • 复杂度过高

    插入排序

    • 摸出第1张牌,从第n张开始比较,若大小关系错误,则第n张后移一位,再与n-1相比较,直到大小关系正确,插入该位置。
    • 摸出第i张牌,从第n张开始比较,若大小关系错误,则第n张后移一位,再与n-1相比较,直到大小关系正确,插入该位置。
    void Insertion_Sort( ElementType A[], int N )
    { for ( P=1; P<N; P++ ) {
    Tmp = A[P]; /* 摸下一张牌*/
    for ( i=P; i>0 && A[i-1]>Tmp; i-- )
    A[i] = A[i-1]; /* 移出空位*/
    A[i] = Tmp; /* 新牌落位*/
    }
    }
    

    优缺点分析

    最好情况:顺序T = O( N )
    最坏情况:逆序T = O( N2 )

    优点

    • 易于实现
    • 比冒泡好,每一步都少一些步骤
    • 稳定的

    缺点

    • 复杂度高

    插入排序的改进:希尔排序

    • 定义增量序列 Dm>Dm-1>……>D1=1
    • 对每个Dk进行“Dk-间隔”排序(K=m,m-1,……1)
    • 注意:Dk间隔有序的序列,在执行“Dk-1间隔”排序后,仍然是Dk间隔有序的。

    一个例子

    一个坏例子

    • 原始希尔排序DM = 向下取整( N / 2 ) , Dk = 向下取整( Dk+1 / 2 )。
    • 最坏情况: T = θ( N2 )
    void Shell_sort( ElementType A[], int N )
    { for ( D=N/2; D>0; D/=2 ) { /* 希尔增量序列*/
    for ( P=D; P<N; P++ ) { /* 插入排序*/
    Tmp = A[P];
    for ( i=P; i>=D && A[i-D]>Tmp; i-=D )
    A[i] = A[i-D];
    A[i] = Tmp;
    }
    }
    }
    

    更多增量序列

    基于比较的排序

    时间复杂度下界

    • 对于下标i<j,如果A[i]>A[j],则称(i,j)是
      一对逆序对(inversion)
    • 问题:序列{34, 8, 64, 51, 32, 21}中有多少逆序对?
    • (34, 8) (34, 32) (34, 21) (64, 51) (64, 32) (64, 21) (51, 32) (51, 21) (32, 21)
    • 交换2个相邻元素正好消去1个逆序对!
    • 插入排序:T(N, I) = O( N+I )
    • 如果序列基本有序,则插入排序简单且高效

    相关定理

    • 定理:任意N个不同元素组成的序列平均具有
      N ( N - 1 ) / 4 个逆序对。
    • 定理:任何仅以交换相邻两元素来排序的算
      法,其平均时间复杂度为Ω ( N2 ) 。
    • 这意味着:要提高算法效率,我们必须每次消去不止1个逆序对!
    • 每次交换相隔较远的2个元素!
  • 相关阅读:
    java 重定向和转发的区别
    Python练习100则--部分概念的没有做
    MYSQL忘记root密码后如何修改
    二分查找注意点
    数据库连接串整理
    MYSQL mysqldump数据导出详解
    MVCC的一些理解
    MySQL 加锁处理分析-转载
    扩展1
    maven-windows使用
  • 原文地址:https://www.cnblogs.com/vancasola/p/8043710.html
Copyright © 2020-2023  润新知