1. 程式人生 > >常用內部排序演算法之四:簡單選擇排序、直接插入排序和氣泡排序

常用內部排序演算法之四:簡單選擇排序、直接插入排序和氣泡排序

前言

之所以把這三類演算法放在一塊,是因為除此之外的演算法都是在這三類演算法的基礎上進行優化的。簡單選擇排序的思想是每一趟ni+1(i=1,2,...,n1)個記錄中選擇最小的記錄作為有序序列的第i個記錄。直接插入排序的思想是將一個記錄插入到已經排好序的有序序列中,從而得到一個新的、記錄數增加1的有序表。氣泡排序的演算法思想是不斷在交換,通過交換完成最終的排序,每一趟的交換就會把最大的記錄取出來,下一趟則會把第二大的記錄取出來,這樣每進行一趟交換就把一個記錄取出來的過程稱為冒泡。

簡單選擇排序演算法

簡單選擇的排序的演算法思想是:通過ni次關鍵字間的比較,從ni+1個記錄中選出關鍵字最小的記錄,並和第i

(1in)個記錄交換之。其演算法程式碼如下:

package com.rhwayfun.algorithm.sort;

public class SelectSort {

    public void selectSort(int[] a){
        int i,j,min;
        for (i = 0; i < a.length; i++) {
            //假設第一個位置的值是最小值
            min = i;
            for(j = i + 1; j < a.length; j++){
                if
(a[min] > a[j]){ min = j; } } //如果min不等於i,說明找到最小值的下標 if(min != i){ swap(a,i,min); } } for(i = 0; i < a.length; i++){ System.out.println(a[i]); } } private
void swap(int[] a, int i, int min) { int temp = a[i]; a[i] = a[min]; a[min] = temp; } public static void main(String[] args) { new SelectSort().selectSort(new int[]{9,1,5,8,3,7,4,6,2}); } }

觀察程式碼可以發現,第i趟排序需要比較ni次關鍵字的比較,所以總共需要比較n1i=1(ni)=n1+n2+...+1=n(n1)2次。最好的情況下,交換0次,最差的情況是交換n1次,所以最終的時間複雜度是O(n2)

直接插入排序演算法

直接插入排序演算法的思想是:將一個記錄插入到已經排序的有序表中,從而得到一個新的、記錄數增加1的有序表。其處理過程是,在排序剛開始的時候,把第一個元素當做是排序的記錄,當依次插入後面的元素的時候,就獲得其插入的位置,然後形成一個新的有序表。其演算法程式碼如下:

package com.rhwayfun.algorithm.sort;

public class InsertSort2 {

    public void insertSort(int[] a) {
        int i,j,temp;
        for(i = 1; i < a.length; i++){
            if(a[i] < a[i-1]){
                temp = a[i];
                for(j = i - 1; j >= 0 && a[j] > temp; j--){
                    a[j+1] = a[j];
                }
                a[j+1] = temp;
            }
        }

        for(i = 0;i < a.length; i++){
            System.out.println(a[i]);
        }
    }

    public static void main(String[] args) {
        new InsertSort2().insertSort(new int[]{9,1,5,8,3,7,4,6,2});
    }
}

從空間上分析,直接插入排序演算法只需要一個輔助空間。
從時間複雜度上分析,最好的情況是排序的記錄本身是有序的,所以時間複雜度是O(n);在最壞的情況,待排序的記錄是逆序的,那麼此時的時間複雜度是O(n24)。所以雖然量級仍然是n2,但是直接插入排序演算法的時間複雜度是優於氣泡排序演算法和簡單選擇排序的。

氣泡排序

氣泡排序的基本思想是兩兩比較相鄰記錄的關鍵字,如果反序就交換,直到沒有反序的關鍵字為止。下面是一種實現思路:

package com.rhwayfun.algorithm.sort;

public class BubbleSort3 {

    public void bubbleSort(int[] a){
        int i,j;
        for(i = 0; i < a.length; i++){
            for(j = i + 1; j < a.length; j++){
                if(a[i] > a[j]){
                    swap(a,i,j);
                }
            }
        }

        for(i = 0; i < a.length; i++){
            System.out.println(a[i]);
        }
    }

    private void swap(int[] a, int i, int j) {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

    public static void main(String[] args) {
        new BubbleSort3().bubbleSort(new int[]{9,1,5,8,3,7,4,6,2});
    }
}

這種版本也是我第一時間寫出來的,但是可以發現一個問題,在排好第一個和第二個為止之後,數字3反而被排到了最後面。下面是針對這種情況的改良版程式碼:

public void bubbleSort2(int[] a){
        int i,j;
        for(i = 0; i < a.length; i++){
            for(j = a.length - 2; j >= i; j--){
                if(a[j] > a[j + 1]){
                    swap(a,j,j+1);
                }
            }
        }

        for(i = 0; i < a.length; i++){
            System.out.println(a[i]);
        }
    }

這裡的改進主要把第二個for迴圈由從前往後比較改成由後往前進行比較了,這樣的好處是可以把本來較小的元素放在儘可能前一點的位置,這種差異性在資料量較大的時候能夠體現出來。以上改良版的氣泡排序使用於基本無序的序列,如果是基本有序的序列再使用上述的演算法進行排序就會出現一個問題:那就是可能在進行完前幾次的冒泡之後就已經是有序的了,那麼後面的冒泡都是多餘的。下面得程式碼是針對這種情況進行的優化:

public void bubbleSort3(int[] a){
        int i,j;
        boolean flag = true;
        for(i = 0; i < a.length && flag; i++){
            flag = false;
            for(j = a.length - 2; j >= i; j--){
                if(a[j] > a[j + 1]){//如果不進行資料交換,說明是有序的
                    swap(a,j,j+1);
                    flag = true;
                }
            }
        }

        for(i = 0; i < a.length; i++){
            System.out.println(a[i]);
        }
    }

如果在面試中要求寫出氣泡排序演算法的程式碼,寫最後一種情況就可以了。

下面分析氣泡排序演算法的時間複雜度:在最壞的情況就是待排序的記錄是逆序的,此時的時間複雜度是O(n2);最好的情況是,排序表本身就是有序的,那麼在這種情況下,時間複雜度是O(n)