前言

几个排序算法的实现代码,具体的原理可查看数据结构教科书,这里主要是为了自己时常回顾,方便复习。

  • 这里的排序算法实现的统一的函数名称为:
    void X_Sort(ElementType A[],int N)
    这里X为排序算法的名称
  • 稳定性:任意两个相等的数据,排序前后的相对位置不发生改变
  • 没有一种排序是任何情况下都表现最好的。每一种算法都有其必须存在的理由,每一种算法都是你的数据结构具有某种特征时,这种算法可能是最好的
冒泡排序
void Bubble_Sort(ElementType A[], int N)
{    
    for(P=N-1; P>=0; P--)//这个for循环目的是针对[0,P]这个范围
    {                    //把最大值放到范围的最右端
        flag = 0;//bool is_changed = false;
        for(i=0; i<P; i++)//i为要交换的相邻两个数的左端点 
        { /* 一趟冒泡 */
           if(A[i] > A[i+1])//这里只能用>号,保证冒泡排序是稳定的 
           {
                Swap(A[i], A[i+1]);
                flag = 1; /* 标识发生了交换 */
                //is_changed = true;
            }
        }
        if(flag==0)//if(!is_changed)
            break; /* 全程无交换 */
    }
}
  • 最好情况:顺序 \(T= O(N)\)
  • 最坏情况:逆序 \(T = O(N^2)\)
  • 稳定
插入排序
void InsertionSort(ElementType A[], int N)
{ /* 插入排序 */
    int P, i;
    ElementType Tmp; 
    for(P=1; P<N; P++)//不断加入新的元素,在前面已经排好序的序列 
    {                 //中找到它应该被插入的位置
        Tmp = A[P];
        //下标i为试探新元素P应该放置的位置
        //从后往前试探,0位置不用试探,如果到达了0位置,直接停下来
        //不用判断,已经找到了,至于除0以外的其它位置,
       //试探时需要加上判断条件(应放置位置的前一个元素应该小于tmp,由于前面已经排好
       //序了,那么前一个元素之前的所有的元素都小于tmp)  
        for(i=P; i>0 && A[i-1]>Tmp; i--)
            A[i] = A[i-1];  
        A[i] = Tmp;  
    }
}
  • 最好情况:顺序 \(T= O(N)\)
  • 最坏情况:逆序 \(T = O(N^2)\)
  • 稳定

冒泡排序和插入排序都是交换相邻的元素。交换2个相邻元素(仅仅影响这两个,与其它元素的逆序关系不变)正好消去1个逆序对!
插入排序:\(T(N,I) = O(N+I)\),这里\(N\)为插入排序最外层的循环,\(I\)为逆序对个数。如果序列基本有序,则插入排序简单且高效

  • 定理:任意\(N\)个不同元素组成的序列平均具有\(N(N-1)/4\)个逆序对。
  • 定理:任何仅以交换相邻两元素来排序的算法,其平均时间复杂度为\(\Omega (N^2)\)
  • 这意味着:要提高算法效率,我们必须
    • 每次消去不止1个逆序对!
    • 每次交换相隔较远的2个元素!