1. 程式人生 > >[資料結構]七種排序演算法小結

[資料結構]七種排序演算法小結

氣泡排序

時間複雜度o(n2)。下面以一個例子來看什麼是氣泡排序。
例:
這裡寫圖片描述
第一次取區間[0,7],通過比較第i個和第i+1個的大小,如果第i+1個數字小於第i個,則互換。這樣位置7就是最大的數了。
第二次取區間[0,6],通過比較第i個和第i+1個的大小,如果第i+1個數字小於第i個,則互換。這樣位置6就是第二大的數了。
依次往下,可以得到排序,這就是氣泡排序。

選擇排序

時間複雜度o(n2)。還是以上面的例子來說明。
第一次取區間[0,7],選擇該區間最小的數和位置0的數進行交換;
第二次取區間[1,7],選擇該區間最小的數和位置1的數進行交換;
第三次取區間[2,7],選擇該區間最小的數和位置2的數進行交換;
依次往下,可以得到排序,這就是選擇排序。

插入排序

時間複雜度o(n2)。以上面的例子來說明。
第一次將位置0和位置1進行比較,小的放前。
第二次將位置2上的數字,插入到位置0和位置1中(按照順序)。

第k次將位置k上的數字,插入到第k-1次已經完成的序列中。
這就是插入排序。

歸併排序

時間複雜度為o(N×LogN)。歸併排序的思想是將兩個順序序列合併成一個順序序列的方法。參考自歸併排序_百度百科

設有數列{6,202,100,301,38,8,1}
初始狀態:6,202,100,301,38,8,1
第一次歸併後:{6,202},{100,301},{8,38},{1},比較次數:3;
第二次歸併後:{6,100,202,301},{1,8,38},比較次數:4;
第三次歸併後:{1,6,8,38,100,202,301},比較次數:4;
總的比較次數為:3+4+4=11;

快速排序

快速排序的時間複雜度是o(N×LogN)。它是對氣泡排序的一種改進。

首先在序列中隨機選取一個數字,將大於該數字的放在其右邊,小於該數字的放在左邊。對於該數字左、右邊的序列遞迴呼叫該過程。
其過程描述如下(來源自牛客網
這裡寫圖片描述

快排的JAVA實現

參考了MoreWindows的白話經典算法系列之六,自己實現了一下JAVA版本的快排,程式碼如下。

public class QuickSort {

    public static int getMiddle(int low, int high, Integer[] list) {
        int
tmp = list[low];// 選擇第一個數作為基準 while (low < high) { while (list[high] >tmp && high > low) {// 找到後面大於基準的數 high--; } if (low < high) {// 插入到空白處 list[low] = list[high]; low++; } while (list[low] <= tmp && low < high) { low++; } if (low < high) { list[high] = list[low]; high--; } } list[low] = tmp; return low; } public static void quick(Integer[] x, int low, int high) { if (high > low) { int middle = getMiddle(low, high, x); System.out.println("本次基準是:" + middle); quick(x, low, middle - 1); quick(x, middle + 1, high); } } public static void main(String[] args) { Integer[] test = { 1, 3, 2 }; Integer[] test1 = { 1, 2, 2 }; Integer[] test2 = { 1000, 2, 2,34,11,222,11,33,2}; quick(test, 0, 2); for (int i = 0; i < 3; i++) System.out.print("排序結果:"+test[i]+" "); System.out.println(); quick(test1, 0, 2); for (int i = 0; i < 3; i++) { System.out.print("排序結果:"+test1[i]+" "); } System.out.println(); quick(test2, 0, 8); for (int i = 0; i < 9; i++) { System.out.print("排序結果:"+test2[i]+" "); } } }

筆者又自行根據思路實現了一次C++版本的快排,可以參考。

快排的C++實現

#include<iostream>
using namespace std;

//

void quick_sort(int s[],int begin,int end)
{
    if(begin>end)
        return ;
    int jizhun=s[begin];
    int keng=begin;
    bool flag=false;
    while(!flag)
    {
        flag=true;
        for(int i=end;i>keng;i--)//從右到左找小的
        {
            if(s[i]<jizhun)
            {
                s[keng]=s[i];
                keng=i;
                flag=false;
                break;
            }
        }
        for(int i=begin;i<keng;i++)//從左到右找大的
        {
            if(s[i]>jizhun)
            {
                s[keng]=s[i];
                keng=i;
                flag=false;
                break;
            }
        }
    }
    s[keng]=jizhun;
    quick_sort(s,begin,keng-1);
    quick_sort(s,keng+1,end);
}

int main()
{
    int b[9]={1000,2,2,34,11,222,11,33,2};
    quick_sort(b,0,8);
    for(int i=0;i<9;i++)
        cout<<b[i]<<" ";
    cout<<endl;

    return 0;
}

堆排序

堆排序的時間複雜度是o(N×LogN)。要理解堆排序,首先應該要明白的概念是堆。可以參考博文白話經典算法系列之七 堆與堆排序
二叉堆的定義

二叉堆是完全二叉樹或者是近似完全二叉樹。

二叉堆滿足二個特性:

1.父結點的鍵值總是大於或等於(小於或等於)任何一個子節點的鍵值。
2.每個結點的左子樹和右子樹都是一個二叉堆(都是最大堆或最小堆)。

當父結點的鍵值總是大於或等於任何一個子節點的鍵值時為最大堆(大根堆)。當父結點的鍵值總是小於或等於任何一個子節點的鍵值時為最小堆(小根堆)。

堆排序其實就是將大根堆的堆頂刪除,再構造大根堆,依次下去即可。

希爾排序

希爾排序的時間複雜度是o(N×LogN)。希爾排序(參考博文白話經典演算法之三 希爾排序的實現)是插入排序的一個改進。希爾排序是非穩定排序演算法,實質就是分組插入排序,該方法又稱縮小增量排序,因DL.Shell於1959年提出而得名。
該方法的基本思想是:先將整個待排元素序列分割成若干個子序列(由相隔某個“增量”的元素組成的)分別進行直接插入排序,然後依次縮減增量再進行排序,待整個序列中的元素基本有序(增量足夠小)時,再對全體元素進行一次直接插入排序。因為直接插入排序在元素基本有序的情況下(接近最好情況),效率是很高的,因此希爾排序在時間效率上比前兩種方法有較大提高。
百度圖片上找到一個例子,供參考
這裡寫圖片描述