1. 程式人生 > >排序詳細分析

排序詳細分析

前言 : 博主之前也是一直很懶 排序的時間複雜度也是都去看別人寫的 沒有測試過. 今天想想就把程式碼全部貼出來 C語言和JAVA程式碼都會貼出來 測試是在JAVA上測試的 而且之前一直沒怎麼用插入 因為懶就去寫冒泡的程式碼 因為短嘛! 我知道有人和我是一樣的哈哈. 如果是寫題或者別的幹嘛 就會 用C++的algorithm庫中的sort 或者 JAVA的 的sort方法. 其實C語言stdlib庫中也有qsort方法 有興趣的去查查. 最近學完了希爾排序 才發現 希爾排序也不是一般的好用 而且程式碼很好寫.所以今天我想把 各種排序的時間都貼出來和大家分享 注意! 我是在JAVA虛擬機器上測試出來的.

話不多說 : 先說說測試了什麼 

1.簡單選擇排序

2.氣泡排序

3.插入排序

4.優化的插入排序

5.希爾排序.

6.優化的希爾排序.

7快速排序.

8.歸併排序.

9.JAVA的Arrays的sort方法(沒學JAVA可以不用管這個)

10.堆排序

 

先說明 我這裡的測試 用了0 - 10005 的隨機數

而且所有的排序都是用了同一個隨機數陣列 也就是9個方法 我複製了9份這樣陣列

for (int i = 0; i < N; i++) {
            box[i] = rm.nextInt(10005); //這裡就是獲得一個[0,10005)的隨機數
            box2[i] = box[i];
            box3[i] = box[i];
            box4[i] = box[i];
            box5[i] = box[i];
            box6[i] = box[i];
            box7[i] = box[i];
            box8[i] = box[i];
            box9[i] = box[i];
        }

 

看不懂JAVA的不用去管 知道 這是隨機數就好

 

 

好了 宣告 N 就是我們的測試個數

開始讓N為10看一下結果

當N變為100

當N變為1000

 

兩張圖 1000的兩次結果 為了說明結果

接下來都是兩張圖

N = 10000

 

N = 100000

 

 

好了 接下來 加0的時候我準備取消幾個排序

以免太慢

有一次 我N = 1000000

我出去吃了個飯 冒泡還沒跑完

最後 跑了36分鐘....

N = 1000000

 

 

一激動 放了4張圖

N = 10000000

 

 

好了 結果已經對比出來了 冒泡 最慢 然後是 簡單選擇 

然後是插入

 

當時剛學C語言1個多月的時候去打比賽

當時因為只掌握了冒泡和簡單選擇 快排不是太熟

怕寫不出來 有一道題要用排序 就用了冒泡

因為當時覺得 冒泡應該是插入 冒泡 和 簡單選擇 

三個排序中最快的

後來發現是最慢的

結果那道題 一直執行超時 真後悔啊

 

總結 : 資料較少的時候都很快 N = 1000的時候建議用插入

這裡說一下 插入的優化 和希爾排序的優化是什麼

沒有優化的是交換

優化了的是 覆蓋 然後最後一次交換

 

N = 10000的時候 冒泡就開始吃力. 我記得C語言的比賽

時間限制好像是3000ms

插入排序在資料少 有序資料多的情況很不錯

資料少的時候不是很建議去使用快排 歸併

因為他們都有遞迴

而且 歸併雖然很快 但是有時間開銷.

 

其實我們現在做的無非也就是用時間去換空間

或者用空間去換時間

 

這裡我強烈推薦希爾排序 時間複雜度可以接受

不消耗空間 且寫法簡單

接下來就是程式碼

因為用到的語法和C語言很像就說明一下

如果想學習可以去看看別人的演算法教學

應該都很詳細,我就不講了哈哈哈...

後面都只寫核心程式碼

1.簡單選擇排序

for (int i = 0; i < N - 1; i++) {
            int index = i;
            for (int j = i + 1; j < N; j++) {
                if (arr[index] < arr[j]) {
                    index = j;
                }
            }
            int t = arr[i];
            arr[i] = arr[index];
            arr[index] = t;
        }

 

2.氣泡排序

 

 for (int i = 0; i < N - 1; i++) {
            for (int j = 0; j < N - i; j++) {
                if(arr[j] > arr[j+1]) {
                    int t = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j+1] = t;
                }
            }
        }

 

3.插入排序

 

 for (int i = 1; i < N; i++) {
            int j;
            for (j = i; j > 0 && arr[j] < arr[j - 1]; j--) {
                int t = arr[j];
                arr[j] = arr[j - 1];
                arr[j - 1] = t;
            }
        }

 

4.優化插入排序

 

for (int i = 1; i < N; i++) {
            int temp = arr[i];
            int j;
            for (j = i;j> 0 && temp < arr[j - 1] ; j--) {
                arr[j] = arr[j - 1];
            }
            arr[j] = temp;
        }

 

5.希爾排序(個人最喜歡)

 

  int n = 1;
        while(n < N/3) n = n*3 + 1;
        while (n >= 1) {
            for (int i = n; i < N; i++) {
                int j;
                for (j = i; j >=n && arr[j] < arr[j-n]; j-=n) {
                    int t = arr[j];
                    arr[j] = arr[j - n];
                    arr[j - n] = t;
                }
            }
            n/=3;
        }

 

6.優化希爾排序(個人最喜歡)

 

 int n = 1;
        while(n < N/3) n = n*3 + 1;
        while (n >= 1) {
            for (int i = n; i < N; i++) {
                int j;
                int temp = arr[i];
                for (j = i; j >=n && temp < arr[j-n]; j-=n) {
                    arr[j] = arr[j - n];
                }
                arr[j] = temp;
            }
            n/=3;
        }

 

7.快速排序

 

因為用到函式遞迴所以函式宣告也寫

C語言把前面public static 去掉即可

public static void sort(int[] arr, int left, int right) { 
        if (left > right) {
            return ;
        }
        int i = left, j = right, temp = arr[left], t;
        while (i != j) {
            while (arr[j] >= temp && i < j) {
                j--;
            }
            while (arr[i] <= temp && i<j) {
                i++;
            }
            if (i < j) {
                t = arr[i];
                arr[i] = arr[j];
                arr[j] = t;
            }
        }
        arr[left] = arr[i];
        arr[i] = temp;
        sort(arr, left, i - 1);
        sort(arr, i+1, right);
    }

 

 

 

8.歸併排序

因為用到函式遞迴所以函式宣告也寫

C語言把前面public static 去掉即可

下文分配空間C語言可以在合併函式裡分配一個輔助空間

大小滿足r-l+1就行

直接定義 或者malloc(用完釋放)都可以

 public static int[] temp = new int[N]; //這是分配空間的 
    public static void sort(int[] arr,int l, int r) {
        if (l >= r) {
            return;
        }
        int mid = (l + r)/2;
        sort(arr, l, mid);
        sort(arr, mid+1, r);
        marge(arr,l, mid, r);
    }

    public static void marge(int[] arr, int l,int mid, int r) {
        int i = l, j = mid+1;

        for (int k = l; k <= r; k++) {
            temp[k] = arr[k];
        }

        for (int k = l; k <= r; k++) {
            if(i > mid) arr[k] = temp[j++];
            else if(j > r) arr[k] = temp[i++];
            else if(temp[j] < temp[i]) arr[k] = temp[j++];
            else arr[k] = temp[i++];
        }

    }

 

10.歸併排序

 

因為用到函式遞迴所以函式宣告也寫

C語言把前面public static 去掉即可

 

 public static void sort(int[] arr) {
        for (int i = (N - 1) /2 -1; i >= 0; i--)
            sink(arr,i,N-1);
        int n = N - 1;
        while (n > 0) {
            int t = arr[0]; arr[0] = arr[n]; arr[n] = t;
            n--;
            sink(arr, 0, n);
        }
    }
    public static void sink(int[] arr, int k, int n) {
        while (2 * k + 1 <= n) {
            int j = 2*k +1 ;
            if (j+1 <= n && arr[j] < arr[j + 1]) j++;
            if (arr[k] > arr[j]) break;
            int t = arr[j]; arr[j] = arr[k]; arr[k] = t;
            k = j;
        }
    }

 

個人認為 幾種排序的排名

理解難易度 選擇 < 冒泡 < 插入 < 歸併 < 快排 = 希爾 < 堆排

寫法難易度 選擇= 冒泡 < 插入 < 希爾 <快排 < 歸併 <= 堆排

歸併和堆排的寫法上小細節太多 容易出錯 

我在寫的時候就出了幾個小錯誤 導致錯誤的排序

注意點就好了

好了就到這裡.有興趣的搜一下演算法趕快get起來吧哈哈