1. 程式人生 > >【初賽】各種排序演算法總結

【初賽】各種排序演算法總結

一、演算法評價

排序方法 平均時間 最好時間 最壞時間
氣泡排序(穩定) O(n^2) O(n) O(n^2)
選擇排序(不穩定) O(n^2) O(n^2) O(n^2)
插入排序(穩定) O(n^2) O(n) O(n^2)
快速排序(不穩定) O(nlogn) O(nlogn) O(n^2)
歸併排序(穩定) O(nlogn) O(nlogn) O(nlogn)
堆排序(不穩定) O(nlogn) O(nlogn) O(nlogn)
基數排序(穩定) O(n) O(n) O(n)
桶排序(不穩定) O(n) O(n) O(n)
希爾排序(不穩定) O(nlogn) O(n^1.2) O(n^2)

其中,冒泡和插入在資料有序時複雜度為只需要O(n),快速排序在資料有序時退化到O(n^2).

二、程式碼實現

1、氣泡排序

  • 迴圈n次,每次相鄰的資料兩兩比較,小數放前面,大數放後面
  • 這樣每一次操作過後最小的數就被排在了最前面
void BubbleSort(int a[], int n){
    for(int i = 1; i < n; i++){ //迴圈有序陣列,每次迴圈後保證到i位置的值是有序的。
        for(int j = n; j > i; j--) //迴圈無序陣列兩兩比較
            if
(a[j] < a[j-1])swap(a[j],a[j-1]); //如果是逆序對就交換(保證每次把最小的值往前交換) //Print(a,n); } }

2、選擇排序

  • 在未排序序列中找到最小的元素,記錄位置
  • 將它放到已排序序列的末尾(和第一個無序元素交換即可)
void SelecSort(int a[], int n){
    for(int i = 1; i <= n; i++){ //對於每一個位置的值(實質是未排序序列的第一個元素)
        int index = i;  //index:記錄未排序序列中最小元素的位置
        for(int j = i+1; j <= n; j++) //遍歷剩餘未排序序列
            if(a[j] < a[index])index = j; //保證index是最小元素的位置
        swap(a[i],a[index]);//將最小的值放到未排序序列的第一個,完成排序
        //for(int i = 1; i <= n; i++)cout<<a[i]<<" ";  cout<<"\n";
    }
}

3、插入排序

  • 資料分為兩部分,一開始有序部分包含1個元素
  • 依次將無序部分的元素插入到有序部分當中
void InsertSort(int a[], int n){  //直接插入排序
    for(int i = 2; i <= n; i++){ //遍歷無序部分,每次取出第一個元素
        int j = i-1, k = a[i];  //j為當前下標, k為無序部分第一個元素
        while(j>=1 && k<a[j]){ //找到k元素在有序部分的位置
            a[j+1] = a[j];    //迴圈的時候直接右移有序陣列,為k騰出位置
            j--;             //不是k正確的位置,繼續往前迴圈
        }
        a[j+1] = k;  //出來的時候j多減了1,要加回去
        //for(int i = 1; i <= n; i++)cout<<a[i]<<" ";  cout<<"\n";
    }
}

4、快速排序

  • 每次選擇一個基準數,把比之小的都放到其左邊,大的都放到其右邊
  • 排放時候的細節
void QuickSort(int a[], int n, int l, int r){
    if(l > r)return ; //遞迴出口,越界返回
    int k = a[l];//k就是基準數(k的選取與內迴圈的找數順序有關)
    int i = l, j = r;//區間
    while(i < j){ //i==j時,兩數相遇,
        //順序有影響,先從右往左找,找到第一個比基準數小的位置
        while(i<j && a[j]>=k)j--;//切記‘>=’(可以忽略掉與k相等的值,不然i永遠不會大於j,則死迴圈)
        //然後從左往右找到第一個比基準數大的位置
        while(i<j && a[i]<=k)i++;
        //如果他們沒有相遇,就交換這兩個數的位置,並繼續尋找
        if(i < j)swap(a[i],a[j]);
    }
    //將基準數歸位
    a[l] = a[i];  //相遇的位置
    a[i] = k;    //
    QuickSort(a,n,l,i-1);//遞迴後不用考慮基準數
    QuickSort(a,n,i+1,r);
}

5、歸併排序

  • 先使每個子序列有序,再使子序列段間有序。
  • 遞迴到底層子序列自然有序,段間有序要求每次去合併
void MergeSort(int a[], int n, int l, int r){
    if(l == r)return ;
    int mid = l+r>>1;
    MergeSort(a,n,1,mid);
    MergeSort(a,n,mid+1,r);
    int i = 1, j = mid+1;
    int c[r-l+1], k = 1;
    while(i <= mid && j <= r){
        if(a[i]<a[j])c[k++] = a[i++];
        else c[k++] = a[j++];
    }
    while(i <= mid)c[k++] = a[i++];
    while(j <= r)c[k++] = a[j++];
    for(int i = l; i <= r; i++)
        a[i] = c[i];
}

6、堆排序