算法之八大排序算法

這裏寫圖片描述

1、直接插入排序

插入排序是一種最簡單直觀的排序算法,它的工作原理是通過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。
這裏寫圖片描述

public static void InsertSort(int[] array){
        if(array == null || array.length == 0)
            return ;
        for(int i = 0;i < array.length; i++){
            int value = array[i];
            int j;
            for( j = i - 1; j >= 0; j--){
                if(value < array[j]){
                    array[j + 1] = array[j];
                }else{
                    break;
                }
            }
            array[j + 1] = value;
        }
    }

2、 希爾排序

希爾排序示意圖

這裏寫圖片描述
希爾排序,也稱遞減增量排序算法,是插入排序的一種更高效的改進版本。但希爾排序是非穩定排序算法。

希爾排序是基於插入排序的以下兩點性質而提出改進方法的:

插入排序在對幾乎已經排好序的數據操作時, 效率高, 即可以達到線性排序的效率
但插入排序一般來說是低效的, 因爲插入排序每次只能將數據移動一位
希爾排序的基本思想是:先將整個待排序的記錄序列分割成爲若干子序列,對所有的子序列同時分別進行直接插入排序,待整個序列中的記錄“基本有序”時,再對全體記錄進行依次直接插入排序。

算法步驟:

1)選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;

2)按增量序列個數k,對序列進行k 趟排序;

3)每趟排序,根據對應的增量ti,將待排序列分割成若干長度爲m 的子序列,分別對各子表進行直接插入排序。僅增量因子爲1 時,整個序列作爲一個表來處理,表長度即爲整個序列的長度。

 public static void ShellSort(int[] array){
        if(array == null || array.length == 0)
            return ;
        for(int gap = (array.length/2); gap > 0; gap/=2){
            for(int i = gap; i < array.length; i++)
                for(int j = i-gap; j>=0 && array[j]>array[j+gap]; j -= gap) {
                    int temp = array[j];
                    array[j] = array[j+gap];
                    array[j+gap] = temp;
                }
        }
    }

3、直接選擇排序

步驟:每次從未排序序列中選擇最小(最大)元素放在已排序序列的尾部
這裏寫圖片描述

public static void SelectSort(int[] array){
        if(array == null || array.length == 0)
            return ;
        for(int i = 0;i < array.length; i++){
            int minindex = array[i];
            for(int j = i; j < array.length; j++){
                if(array[j] < minindex)
                    minindex = j;
            }
            if(minindex != i){
                int temp = array[i];
                array[i] = array[minindex];
                array[minindex] = temp;
            }
        }
    }

4、堆排序

這裏寫圖片描述

堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆積是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。
這裏寫圖片描述

同時,我們對堆中的結點按層進行編號,將這種邏輯結構映射到數組中就是下面這個樣子
這裏寫圖片描述

該數組從邏輯上講就是一個堆結構,我們用簡單的公式來描述一下堆的定義就是:

大頂堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

小頂堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

算法步驟:

1)創建一個堆H[0..n-1]

2)把堆首(最大值)和堆尾互換

3)把堆的尺寸縮小1,並調用shift_down(0),目的是把新的數組頂端數據調整到相應位置

4) 重複步驟2,直到堆的尺寸爲1

   //本函數功能是:根據數組array構建大根堆
    //從第i個元素開始向下調整
    public static void adjustHeap(int []arr,int i,int length){
        for(int k=i*2+1;k<length;k=k*2+1){//從i結點的左子結點開始,也就是2i+1處開始
            if(k+1<length && arr[k]<arr[k+1]){//如果左子結點小於右子結點,k指向右子結點
                k++;
            }
            if(arr[k] >arr[i]){//如果子節點大於父節點,將子節點值賦給父節點(不用進行交換)
                int temp = arr[i];
                arr[i] = arr[k];
                i = k;
                arr[k] = temp;
            }else{
                break;
            }
        }
    }
    //堆排序算法
    public static void  HeapSort(int array[]){
        //1.構建大頂堆,目的只是保證堆頂元素值最大
        //保證堆從上到下大致有序看,任意從節點到葉子節點的路徑上元素是有序的
        for(int i=array.length/2-1;i>=0;i--){
            //從第一個非葉子結點(即array.length/2 - 1)從下至上,從右至左調整結構
            adjustHeap(array,i,array.length);
        }
        //2.調整堆結構+交換堆頂元素與末尾元素,
        for(int j=array.length-1;j>0;j--){
            array[j] = array[0] ^ array[j];//將堆頂元素與末尾元素進行交換
            array[0] = array[0] ^ array[j];
            array[j] = array[0] ^ array[j];
            adjustHeap(array,0,j);//重新對堆進行調整
        }
    }

5、冒泡排序

這裏寫圖片描述
冒泡排序(Bubble Sort)也是一種簡單直觀的排序算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個算法的名字由來是因爲越小的元素會經由交換慢慢“浮”到數列的頂端。

public static void BubbleSort(int[] array){
        if(array == null || array.length == 0)
            return ;
        for(int i = array.length - 1;i > 0; i--){
            for(int j = 0 ;j < i;j++ ){
                if(array[j] > array[j+1]){
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                 }
            }
        }
    }

6、 快速排序

這裏寫圖片描述
快速排序是由東尼·霍爾所發展的一種排序算法。在平均狀況下,排序 n 個項目要Ο(n log n)次比較。在最壞狀況下則需要Ο(n2)次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他Ο(n log n) 算法更快,因爲它的內部循環(inner loop)可以在大部分的架構上很有效率地被實現出來。

快速排序使用分治法(Divide and conquer)策略來把一個串行(list)分爲兩個子串行(sub-lists)。

public static void Qsort(int[] array,int start,int end) {
        if(array == null || array.length == 0)
            return ;
        if(start > end)
            return ;
        else{
            int i = start;
            int j = end;
            int flag = array[end];
            while(i < j){
                while(array[i] <= flag && i<j){
                    i++;
                }
                if(array[i] > flag && j > i){
                    array[j] = array[i];
                    array[i] = flag;
                    j--;
                }
                while(array[j] >= flag && j>i){
                    j--;
                }
                if(array[j] < flag && i<j){
                    array[i] = array[j];
                    array[j] = flag;
                    i++;
                }
            }
            array[i] = flag;
            Qsort(array,start,i - 1);
            Qsort(array,i + 1,end);
        }
    }

7、歸併排序

這裏寫圖片描述
歸併排序(Merge sort)是建立在歸併操作上的一種有效的排序算法。該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。

算法步驟:

  1. 申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列

  2. 設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置

  3. 比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置

  4. 重複步驟3直到某一指針達到序列尾

  5. 將另一序列剩下的所有元素直接複製到合併序列尾

public static void MergeSort(int[] copy,int[] array,int start,int end){
        if(array == null || array.length == 0)
            return ;
        if(start >= end)
            return ;
        int middle = (end - start )/2;
        MergeSort(copy,array,start,start + middle);
        MergeSort(copy,array,start + middle + 1,end);

        int i = start + middle;
        int j = end;
        int index = end;
        while(i >= start && i <= (start + middle) && j >= (start + middle + 1) && j <= end){
            if(copy[i] > copy[j]){
                array[index--] = copy[i--];
            }else{
                array[index--] = copy[j--];
            }
        }
        while(i >= start && i <= (start + middle) && index >= start){
            array[index--] = copy[i--];
        }
        while(j >= (start + middle + 1) && j <= end && index >= start){
            array[index--] = copy[j--];
        }
        for(int m = start;m <= end;m++){
            copy[m] = array[m];
        }
    }

8、基數排序 (即桶排序)

典型的以空間換時間,時間複雜度爲線性時間

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章