1. 程式人生 > >簡單演算法——直接插入、冒泡、直接選擇

簡單演算法——直接插入、冒泡、直接選擇

排序的演算法有很多
這裡寫圖片描述
其中直接插入排序、直接選擇排序、氣泡排序屬於簡單排序,它們對空間的要求不高,但是時間效率卻不穩定;
本文將介紹三種簡單排序,下一篇會介紹三種簡單排序對應的高階排序快速排序、希爾排序、堆排序
首先做一個公用的元素交換實現函式, 下面的swap呼叫都是這個

 /**
     * 交換陣列元素
     * 交換思想很簡單 數字x y  =>  x=x+y;y=x-y;x=x-y;
     * 這種方法不使用臨時變數,能有效降低演算法空間複雜度,但也有缺點,比如可能存在越界風險
     * @param arr
     * @param a
     * @param
b */
public void swap(int []arr,int a,int b){ arr[a] = arr[a]+arr[b]; arr[b] = arr[a]-arr[b]; arr[a] = arr[a]-arr[b]; }

氣泡排序

這個演算法的名字由來是因為越大的元素會經由交換慢慢“浮”到數列的頂端,故名“氣泡排序”。
基本操作:
1、比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
2、對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一輪,最後的元素應該會是最大的數。
3、針對所有的元素重複以上的步驟,除了最後一個。
4、持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較
如:
原始陣列: 5 3 6 4
第一步:3 5 4 6
第二步:3 4 5 6 (實際到這裡排序已經結束,但是原始的氣泡排序會走完所有的迴圈)
第三步:3 4 5 6
第四步:3 4 5 6

程式實現

    int arr[] = {5,3,6,4};
    public void bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            //每次將最大的數字移到最後,下次迴圈長度-1,再將剩餘陣列中最大的數字移到剩餘陣列長度的後面
            for (int j = 0; j < arr.length - i -1; j++) {
                if(arr[j] > arr[j + 1]) {
                    swap(arr, j, j+1
); } } } // printArr(arr); }

也可以優化一下,如果排序已經完成,就停止迴圈:

    public void bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            boolean flag = true;//設定一個標記,若為true,則表示此次迴圈沒有進行交換,也就是待排序列已經有序,排序已然完成。
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr,j,j+1);
                    flag = false;
                }
            }
            if (flag) {
                break;
            }
        }
    }

直接插入排序

基本操作是將一條記錄插入到已排好的有序表中,從而得到一個新的、記錄數量增1的有序表。如:

原始陣列: 5 3 6 4
第一步:5 - - - 3 6 4
第二步:3 5 - - - 6 4 (3和5比較一次)
第三步:3 5 6 - - - 4(6和5比較一次)
第四步: 3 4 5 6 (4和3 5 6 各比較一次)

程式實現

    int arr[] = {5,3,6,4};
    /**
     * 採用直接插入排序 將陣列按升序排列
     * @param arr
     */
    private void directInsert(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            int j = i;
            while (j > 0 && arr[j] < arr[j - 1]){//兩層意思:1、如果是第一個元素就放著 不比較也不交換 2、如果後面一個數字小於前面那個 就進行交換
                swap(arr, j, j-1);
                j--;
            }
        }
    }

也可以這樣實現:

    int arr[] = {5,3,6,4};
    public void insertSort(int[] arr) {
        int j;
        for (int i = 0; i < arr.length; i++) {
            int tem = arr[i];
            for (j = i; j > 0 && tem < arr[j - 1]; j--) {
                arr[j] = arr[j - 1];
            }
            arr[j] = tem;
        }
        //printArr(arr);
    }

直接選擇排序

基本思想是:第一輪遍歷中從R[0]~R[n-1]的陣列中選取最小值,與R[0]交換;第二輪從陣列R[1]~R[n-1]中遍歷選取最小值,與R[1]交換,…..,第n-1次從R[n-2]~R[n-1]中選取最小值,與R[n-2]交換,總共通過n-1次,得到升序序列。如:
原始陣列: 5 3 6 4
第一輪:[ 3 ] 5 6 4 (選出最小值3 和第一個數字5交換)
第二輪:[ 3 4 ] 6 5 (選出最小值4 和第二個數字5交換)
第三輪:[ 3 4 5 ] 6 (選出最小值5 和第三個數字6交換 )
第四輪:[ 3 4 5 6 ]

程式實現

    public void straightSelection(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int tem = i;//存放較小元素下標
            for (int j = i + 1; j < arr.length; j++){
                if (arr[j] < arr[tem]) {
                    tem = j;
                }
            }
            if (tem != i) {
                swap(arr, i, tem);
            }
        }
        printArr(arr);
    }

以上三種排序都是簡單排序,都具有穩定性,時間複雜度為O(n^2)。平均空間複雜度為O(1)。