16. 排序--简单排序

排序

方法模板

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个元素
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章