16. 排序--简单排序

来源:互联网 发布:mac lion dmg 编辑:程序博客网 时间:2024/06/02 19:41

排序

方法模板

void X_Sort(ElementType[] A, int N)
  • 大多数情况下,为简单起见,讨论从小到大的整数排序
  • N是正整数,表示数组的长度

前提

  • 只讨论基于比较的排序(例如通过 > = < 进行比较)
  • 只讨论内部排序(所有数据加载入内存中)
  • 稳定性:任意两个相等的数据,排序前后的相对位置不发生改变
  • 没有一种排序是任何情况下都表现最好的

简单排序

冒泡排序

算法原理

从后往前开始遍历:

  1. 比较相邻的两个元素,如果第二个元素比第一个元素小,则进行交换
  2. 从开始一对到最后一对,对每一对相邻元素做2的工作。这步操作完成后,最后的元素应该是最大的元素
  3. 重复以上步骤,直到倒数第一个元素(最后一个元素不参与上述循环)
  4. 持续每次对越来越少的元素重复以上的步骤,直到没有任何一对元素需要比较

实现

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(N2)
  • 稳定性:基于A[i] > A[i + 1]的判断方式,该冒泡排序是稳定
  • 冒泡排序可以处理单向链表的排序

插入排序

算法原理

从第二个元素遍历到最后一个元素:
1. 记录当前元素为temp
2. 从当前位置向前遍历,如果前一个元素大于temp,则把下个元素后移,直到前一个个元素小于或等于temp
3. 把temp置于空出来的位置

实现

void Insertion_Sort(ElementType[] A, int N) {    for (P = 1; P < N; P++) {        temp = A[P];    // 记录要比较的元素        for (i = P; i > 0 && A[i - 1] > temp; i--)            A[i] = A[i - 1];    // 向后移动元素,空出空位        A[i] = temp;    // 元素置于空位    }}
  • 时间复杂度:
    • 最好情况:已经顺序排好,T=O(N)
    • 最坏情况:逆序排好,T=O(N2)
  • 稳定性:基于A[i - 1] > temp的判断方式,该插入排序是稳定

时间复杂度下界

逆序对

对于下标i<j,如果A[i] > A[j],则称<i,j>是一对逆序对(inversion)

  • 定理:任意N个不同元素组成的序列平均具有N(N1)/4个逆序对

逆序对与排序

对于冒泡、插入排序:

  • 交换2个相邻元素正好消去1个逆序对
  • n个逆序对,则需要交换n次元素
  • 插入排序:T(N,I)=O(N+I)N是元素的个数,I是逆序对的个数
    • 如果序列基本有序,则插入排序简单且高效

对于排序:

  • 定理:任何仅以交换相邻两元素来排序的算法,其平均时间复杂度为Ω(N2)
  • 如果要提高算法效率,必须
    • 每次消去不止1个逆序对
    • 每次交换相隔较远的2个元素
原创粉丝点击