程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> O(n^2)類型的幾種排序算法,排序

O(n^2)類型的幾種排序算法,排序

編輯:JAVA綜合教程

O(n^2)類型的幾種排序算法,排序


一、冒泡排序

1.原理

(1)比較相鄰的元素。如果第一個比第二個大,就交換他們兩個;

(2)對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數;

(3)針對所有的元素重復以上的步驟,除了最後一個;

(4)持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。

2.一個直接但是低效的實現

public void sort(int[] array) {
  //外層循環從第0個元素遍歷到倒數第二個元素,主要是用來控制內層循環的次數
  //因為外層循環每跑一次,最大的數就會到最後面
    for (int i = 0; i < array.length - 1; i++) {
    //內層循環,遍歷數組的每一個數(每一趟遍歷的數量都在減小,因為最後面的是不需要比較的)
    //如果前面的比後面的大,就交換這倆個數
        for (int j = 0; j < array.length - i - 1; j++) {
            if (array[j] > array[j+1]) {
                int temp = array[j+1];
                array[j+1] = array[j];
                array[j] =temp;
            }
        }
    }
}

 

3.優化版本(優化的地方是,如果遍歷了一次,發現沒有任何交換,那麼說明已經排好序了,後面就可以不用排了)

public void sort(int[] array) {
    boolean swaped;
    int n = array.length;
    do {
        swaped = false;
        for (int i = 1; i < n; i++) {
            if (array[i - 1] > array[i]) {
               //如果這趟有兩個元素換過位置,那麼是否排過序設置成true
               //一旦有某一趟沒有任何兩個元素換過位置,說明已經排好了,整個排序過程可以停止了
                int temp = array[i - 1];
                array[i - 1] = array[i];
                array[i] = temp;
                swaped = true;
            }
        }
        n--;
    } while (swaped);
}

二、選擇排序

1.原理:

選擇排序是對冒泡排序的改進,因為冒泡排序每次比較後都要互換兩個元素位置,而互換的過程會有幾次賦值,特別耗費時間。

選擇排序的思路:

是每一次從待排序的數據元素中選出最小的一個元素,存放在序列的起始位置,直到全部待排序的數據元素排完

2.一個簡單的實現:

 public void sort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            //找到最小元素的索引位置
            int minIndex = i;
            for (int j = i + 1; j < array.length; j++) {
                if (array[j] < array[minIndex]) {
                    minIndex = j;
                }
            }
            int temp = array[i];
            array[i] = array[minIndex];
            array[minIndex] = temp;
        }
    }

3.小結:

選擇排序因為每一次遍歷都要從元素中選擇最小的,所以每次都要遍歷完整個數組,也是一個效率特別低的排序。

三、插入排序

1.原理:

插入排序的原理和打牌的時候理牌比較像,就是每步將一個待排序的紀錄,將其插入前面已經排序的序列的適當位置上,直到全部插入完為止。

2.實現代碼版本1:

 

 public void sort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            //從外層循環的位置開始從前面找,如果j-1位置的數比j位置數大,那麼交換
            for (int j = i; j > 0 ; j--) {
                if (array[j] < array[j - 1]) {
                    int temp = array[j - 1];
                    array[j - 1] = array[j];
                    array[j] = temp;
                }
                //這個else是插入排序比較高效的關鍵,因為如果第i位置的前面的元素都排好序了,所以如果i位置比i-1位置小,就表示這趟排好序了 
                else{
                    break;
                }
            }
        }
}

 

可以看到,插入排序,是把當前i元素插入到之前合適的位置裡,整個遍歷的過程中,有break過程。

它不像選擇排序,為了找到最小的數,必須遍歷完整個數組

3.但是上面的程序稍顯累贅,修改下

public void sort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            //把break條件放到for循環裡面來,看起來很清爽
            for (int j = i; j > 0 && array[j] < array[j - 1]; j--) {
                int temp = array[j - 1];
                array[j - 1] = array[j];
                array[j] = temp;
            }
        }
    }

4.上面的程序仍然有問題,可以看到,每次交換都需要交換三個值,可以進一步修改一下

 public void sort(int[] array) {
        for (int i = 1; i < array.length; i++) {
//            改進後的
            int e = array[i];
            int j;
            for (j = i; j > 0 && array[j - 1] > e; j--) {
                array[j] = array[j - 1];
            }
            array[j] = e;
        }
    }

稍微解釋一下:

在內層循環中,把第i位置的數存下來,再依次遍歷,如果第j-1位置的數比第j位置的數大,那麼直接把j-1位置的數覆蓋到第j位置

直到找到i位置合適的位置為止,也就是array[j-1] < e 為止。

最後才把剛剛存下來的數,賦值給找到的位置

這樣可以省去很多不必要的賦值過程,效率略顯提高

5.小結:

對於插入排序,還想多說一句,插入排序雖然時間復雜度是O(n^2),但是在一定的場合,它的效率非常高。比如,在一個基本上有序的序列中,只有那麼幾個數,它的順序不對,那麼這時候,插入排序的效率非常高

四、希爾排序

1.希爾排序是插入排序一個強力改進版,思路是:

先將整個待排元素序列分割成若干個子序列(由相隔某個“增量”的元素組成的)分別進行直接插入排序,然後依次縮減增量再進行排序,待整個序列中的元素基本有序(增量足夠小)時,再對全體元素進行一次直接插入排序。

因為直接插入排序在元素基本有序的情況下(接近最好情況),效率是很高的,因此希爾排序在時間效率上比前兩種方法有較大提高。

2.實現:

public void sort(int[] arr) {
        int n = arr.length;
        int h = 1;
        while (h < n / 3) {
            h = 3 * h + 1;
        }
        // 計算 increment sequence: 1, 4, 13, 40, 121, 364, 1093...

        while (h >= 1) {
            // h-sort the array
            for (int i = h; i < n; i++) {
                // 對 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序
                int e = arr[i];
                int j;
                for (j = i; j >= h && e < arr[j - h]; j -= h) {
                    arr[j] = arr[j - h];
                }
                arr[j] = e;
            }
            h /= 3;
        }
    }

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved