1. 程式人生 > >各種排序演算法及其C++實現

各種排序演算法及其C++實現

一、插入排序(Insertion Sort)

  1. 基本思想:每次將一個待排序的資料元素,插入到前面已經排好序的數列中的適當位置,使數列依然有序;直到待排序資料元素全部插入完為止。

二、選擇排序(Selection Sort)

  1. 基本思想:每一趟從待排序的資料元素中選出最小(或最大)的一個元素,順序放在已排好序的數列的最後,直到全部待排序的資料元素排完為止。

三、氣泡排序(Bubble Sort)

  1. 基本思想:兩兩比較待排序資料元素的大小,發現兩個資料元素的次序相反時即進行交換,直到沒有反序的資料元素為止。
  2. 排序過程:設想被排序的陣列A[1..N]垂直豎立,將每個資料元素看作有重量的氣泡,根據輕氣泡不能在重氣泡之下的原則,從下往上掃描陣列A,凡掃描到違反本原則的輕氣泡,就使其向上"漂浮",如此反覆進行,直至最後任何兩個氣泡都是輕者在上,重者在下為止。

四、快速排序(Quick Sort)

  1. 基本思想:在當前無序區A[1..H]中任取一個數據元素作為比較的"基準"(不妨記為X),用此基準將當前無序區劃分為左右兩個較小的無序區:A[1..I-1]和A[I+1..H],且左邊的無序子區中資料元素均小於等於基準元素,右邊的無序子區中資料元素均大於等於基準元素,而基準X則位於最終排序的位置上,即A[1..I-1]≤X.Key≤A[I+1..H](1≤I≤H),當A[1..I-1]和A[I+1..H]均非空時,分別對它們進行上述的劃分過程,直至所有無序子區中的資料元素均已排序為止。

五、堆排序(Heap Sort)

  1. 基本思想:堆排序是一樹形選擇排序,在排序過程中,將A[1..N]看成是一顆完全二叉樹的順序儲存結構,利用完全二叉樹中雙親結點和孩子結點之間的內在關係來選擇最小的元素。
  2. 堆的定義: N個元素的序列K1,K2,K3,...,Kn.稱為堆,當且僅當該序列滿足特性:
      K[i]≤K[2i]  K[i]≤K[2i+1]  (1≤ i≤ [N/2])

    堆實質上是滿足如下性質的完全二叉樹:樹中任一非葉子結點的關鍵字均大於(或小於)等於其孩子結點的關鍵字。如果一個堆中根結點(稱為堆頂)的關鍵字最小,我們把它稱為小根堆。反之,若完全二叉樹中任一非葉子結點的關鍵字均大於等於其孩子的關鍵字,則稱之為大根堆。

  3. 排序過程:堆排序正是利用小根堆(或大根堆)來選取當前無序區中關鍵字最小(或最大)的記錄實現排序的。我們不妨利用大根堆來排序。每一趟排序的基本操作是:將當前無序區調整為一個大根堆,選取關鍵字最大的堆頂記錄,將它和無序區中的最後一個記錄交換。這樣,正好和直接選擇排序相反,有序區是在原記錄區的尾部形成並逐步向前擴大到整個記錄區。


六、幾種排序演算法的比較和選擇

  1. 選取排序方法需要考慮的因素:
    (1) 待排序的元素數目n;
    (2) 元素本身資訊量的大小;
    (3) 關鍵字的結構及其分佈情況;
    (4) 語言工具的條件,輔助空間的大小等。
  2. 小結:
    (1) 若n較小(n <= 50),則可以採用直接插入排序或直接選擇排序。由於直接插入排序所需的記錄移動操作較直接選擇排序多,因而當記錄本身資訊量較大時,用直接選擇排序較好。
    (2) 若檔案的初始狀態已按關鍵字基本有序,則選用直接插入或氣泡排序為宜。
    (3) 若n較大,則應採用時間複雜度為O(nlog2n)的排序方法:快速排序、堆排序或歸併排序。快速排序是目前基於比較的內部排序法中被認為是最好的方法。
    (4) 在基於比較排序方法中,每次比較兩個關鍵字的大小之後,僅僅出現兩種可能的轉移,因此可以用一棵二叉樹來描述比較判定過程,由此可以證明:當檔案的n個關鍵字隨機分佈時,任何藉助於"比較"的排序演算法,至少需要O(nlog2n)的時間。
    #include "Sort.h"
    #include <iostream>
    using namespace std;
    
    
    Sort::Sort(void)
    {
    }
    
    
    Sort::~Sort(void)
    {
    }
    //氣泡排序
    //原理:每趟排序是通過比較兩兩相鄰的元素,大的向後移動,一趟
    //完後,最大的移動到最後,共需要size-1趟排序,特殊情況下,某趟未
    //移動任何元素,則說明序列已然有序,則排序完畢,此時趟數<size-1
    void Sort::maoPao(int data[],int size)
    {
        //換序標誌,如果本趟沒任何交換,表示已有序,退出
        bool flag = true;
        //需要size-1趟排序
        for (int i = 0; i < size - 1; i++)
        {
            //已有序,退出
            if (!flag)
                break;
            //先設為已有序,
            flag = false;
            for (int j = 0; j < size - i - 1; j++ )
            {
                //換序
                if (data[j] > data[j + 1])
                {
                    swap(data,j,j + 1);
                    //需要下一趟
                    flag = true;
                } 
            }
        }
        print(data,size);
    }
    //選擇排序
    //原理:每次選擇都是從序列中選擇最小的元素,放到序列前面,共需size-1次選擇
    void Sort::xuanZe(int data[],int size)
    {
        //需要size-1次選擇
        for (int i = 1; i < size; i++)
        {
            //記錄最小值下標
            int k = i - 1;
            for (int j = i; j < size; j++)
            {
                if (data[j] < data[k])
                    k = j;
            }
            if (k != i - 1)
                swap(data,k,i - 1);
        }
        print(data,size);
    }
    //直接插入排序
    //原理:將序列分為有序和無序兩部分,每次排序需要將無序區的一個元素
    //插入到有序區的合適位置,需要size-1次排序
    void Sort::chaRu(int data[],int size)
    {
        //data[0]為有序區,[1,size-1]為無序區,
        //一次遍歷無序區元素插入到有序區
        for (int i = 1; i < size; i++)
        {
            int temp = data[i];
            int j = i - 1;
            for (; j >=0 && data[j] > temp; j--)
            {
                swap(data,j,j+1);
            }
            data[j + 1] = temp;
        }
        print(data,size);
    }
    //歸併排序
    //原理:一次歸併可描述為,將一個序列分成兩組,將這兩組歸併為一個有序的新序列,
    //歸併排序就是遞迴的進行上述操作(遞迴棧的最底部是將序列分成了[一個元素]、[一個元素]
    //這樣的兩組),我的表達能力也就到這了
    void Sort::guiBing(int data[],int size)
    {
        mergeSort(data,0,size - 1);
        print(data,size);
    }
    void Sort::mergeSort(int data[],int first,int last)
    {
        //遞迴出口,只歸併長度大於1的陣列
        if (first < last)
        {
            int mid = (first + last)/2;
            //遞迴左半組
            mergeSort(data,first,mid);
            //遞迴右半組
            mergeSort(data,mid + 1,last);
            //左右半組都排好後,再對著兩組排序
            merge(data,first,mid,last);
        }
        
    }
    //歸併兩個陣列[first,mid]、[mid+1,last],最後合併為一個有序的陣列[first,last]
    void Sort::merge(int data[],int first,int mid,int last)
    {
        int *temp = new int[last - first + 1];
        int k = 0;
        int index1 = first;
        int index2 = mid + 1;
        while (index1 <= mid && index2 <= last)
        {
            if (data[index1] <= data[index2])
                temp[k++] = data[index1++];
            else
                temp[k++] = data[index2++];
        }
        while (index1 <= mid)
            temp[k++] = data[index1++];
        while (index2 <= last)
            temp[k++] = data[index2++];
        for (int i = 0; i < k; i++)
            data[first + i] = temp[i];
        delete[] temp;
    }
    //快速排序
    //原理:一次快排可描述為,將序列分成三部分[左邊組都小於中間數]、[中間數]、[右邊組都大於中間數]
    //快排就是再遞迴的對左邊組和右邊組進行上述操作
    void Sort::kuaiPai(int data[],int size)
    {
        quickSort(data,0,size - 1);
        print(data,size);
    }
    void Sort::quickSort(int data[],int left,int right)
    {
        //遞迴出口
        if (left < right)
        {
            int mid = partion(data,left,right);
            quickSort(data,left,mid - 1);
            quickSort(data,mid + 1,right);
        }
    }
    //一趟分組,執行完後分為左右兩組,左組都小於中間數,右組都大於中間數
    int Sort::partion(int data[],int left,int right)
    {
        //第一個數做中間值
        int temp = data[left];
        int leftIndex = left;
        int rightIndex = right;
        //相等時退出
        while (leftIndex < rightIndex)
        {
            //從右邊找到數值<temp的數
            while (leftIndex < rightIndex && data[rightIndex] >= temp)
                rightIndex--;
            //把找到的數放到中間數位置,此時data[rightIndex]相當於中間數位置
            if (leftIndex < rightIndex)
                data[leftIndex++] = data[rightIndex];
            //從左邊找到數值>temp的數
            while (leftIndex < rightIndex && data[leftIndex] < temp)
                leftIndex++;
            //把找到的數放到中間數位置
            if (leftIndex < rightIndex)
                data[rightIndex--] = data[leftIndex];
        }
        //最後將中間數放到真正的中間位置,此時leftIndex=rightIndex
        data[leftIndex] = temp;
        //返回中間數下標,以便對左右兩組繼續排序
        return leftIndex;
    }
    //希爾排序
    //原理:屬於一種改進的插入排序,將序列按照特定的步長分成若干個子序列,
    //對各個子序列進行插入排序,然後再按照更小的步長分成若干子序列,對子序列排序,
    //......最後一步的步長為1,這樣最後一步則“等於”直接插入排序了,此時的序列是
    //基本有序的,直接插入排序對有序序列的排序效率是很高的
    void Sort::xiEr(int data[],int size)
    {
        int temp;
        for (int d = size/2; d >=1; d = d/2)
        {
            for (int i = d; i < size; i++)
            {
                int j = i - d;
                temp = data[i];
                while (j >= 0 && data[j] > temp)
                {
                    data[j + d] = data[j];
                    j -= d;  
                }
                if (j != i - d)
                    data[j + d] = temp;  
            }
        }
        print(data,size);
    }
    //交換陣列中兩個元素
    void Sort::swap(int data[],int i,int j)
    {
        int temp = data[i];
        data[i] = data[j];
        data[j] = temp;
    }
    void Sort::print(int data[],int size)
    {
        for (int i = 0; i < size; i++)
        {
            cout<<data[i]<<"  ";
        }
        cout<<endl;
    }
    


    (5) 當記錄本身資訊量較大時,為避免耗費大量時間移動記錄,可以用連結串列作為儲存結構。

相關推薦

各種排序演算法及其C++實現

一、插入排序(Insertion Sort) 基本思想:每次將一個待排序的資料元素,插入到前面已經排好序的數列中的適當位置,使數列依然有序;直到待排序資料元素全部插入完為止。 二、選擇排序(Selection Sort) 基本思想:每一趟從待排序的資料元素中選出最小(或最

各種排序演算法及其C++程式碼實現

概念一:排序演算法是否是穩定的 給定序列{3,15,8,8,6,9} 若排序後得到{3,6,8,8,9,15}, 則該排序演算法是不穩定的,原本後面的8(加粗)現在位於前面了。 概念二: 內部排序、外部排序 內部排序是指將待排序的資料存放在記憶體中進行排序的過程。 外部排序是指待排序

各種排序演算法C++實現

好久沒複習過這些東西了,為以後跳槽面試做個知識儲備,也為資料結構初學者提供一個參考,程式碼中若存在錯誤還望指出,演算法持續增加中。。。。。。 #include "Sort.h" #include <iostream> using namespace std;

歸併排序演算法及其C語言具體實現

本節介紹一種不同於插入排序和選擇排序的排序方法——歸併排序,其排序的實現思想是先將所有的記錄完全分開,然後兩兩合併,在合併的過程中將其排好序,最終能夠得到一個完整的有序表。 例如對於含有 n 個記錄的無序表,首先預設表中每個記錄各為一個有序表(只不過表的長度都為 1),然後進行兩兩合併,使 n 個有序表變為

各種排序演算法C++實現(不斷更新中)

      和很多計算機系的同學們一樣,我在大學二年級時也學了《資料結構》這門課。當時我的老師是一箇中科大的博士,現在已經是教授了。他在課上曾經這樣評價這門課:《資料結構》幾乎是所有計算機課程的基礎課,如果把這門課學好了,其他的專業課就不成問題了。還有,IT公司的面試經常涉及

全排列演算法及其C++實現(轉)

第十六章、全排列問題53.字串的排列。題目:輸入一個字串,打印出該字串中字元的所有排列。例如輸入字串abc,則輸出由字元a、b、c 所能排列出來的所有字串abc、acb、bac、bca、cab 和cba。    分析:此題最初整理於去年的微軟面試100題中第53題,第二次整理於微軟、Google等公司非常好的

高斯影象模糊演算法及其 C 實現

高斯模糊的基本思路是根據二維 正太分佈 正態分佈 (感謝 xhr 大牛指正錯別字) 公式生成一個高斯矩陣, 求新影象中的每一點時, 將高斯矩陣的中心對準舊影象的這一點, 並將所有點根據高斯矩陣上對應的點加權平均. 二維正態分佈公式如下: u, v 分別為水平、豎直距離. 觀察可得, 當 r>3σ

各種排序演算法及其複雜度

穩定的   氣泡排序(bubble sort) — O(n^2)   雞尾酒排序(Cocktail sort,雙向的氣泡排序) — O(n^2)   插入排序(insertion sort)— O(n^2)   桶排序(bucket sort)— O(n); 需要 O

8種主要排序演算法C#實現 (二)

歸併排序 歸併排序也是採用“分而治之”的方式。剛發現分治法是一種演算法正規化,我還一直以為是一種需要意會的思想呢。 不好意思了,孤陋寡聞了,哈哈! 原理:將兩個有序的數列,通過比較,合併為一個有序數列。 維基入口 為方便理解,此處實現用了List<in

資料結構與演算法:常見排序演算法及其python實現

0、 綜合分析 0.1 排序演算法的種類及時間限制 常見排序演算法一般分為非線性時間比較類排序和線性時間非比較類排序。 比較類排序演算法時間複雜度的下限為O(nlog⁡n)O(n\log n)O(nlogn),非比較類排序演算法不受比較式排序演算法的時間下

單鏈表實現氣泡排序演算法C實現

本實現主要採用交換指標的方法,其中附加有單鏈表及其相關的實現 #include <stdio.h> struct Node; typedef struct Node *PtrToNode; typedef PtrToNode List; typedef Pt

7種常見排序演算法c++實現

今天心血來潮複習了一下基本的排序演算法,實現了一下,就順便發上來咯。。在程式碼裡做了註釋了-。-也就不多說了,直接上程式碼吧。。// order_algorithm.cpp: 定義控制檯應用程式的入口點。 //author: netbin #include "stdafx.

排序演算法C++實現與效能分析(插入排序、歸併排序、快速排序、STOOGE排序、堆排序

選擇排序、快速排序、希爾排序、堆排序不是穩定的排序演算法 氣泡排序、插入排序、歸併排序和基數排序都是穩定的排序演算法。 總結: (1)如果資料量非常小,那麼適合用簡單的排序演算法:氣泡排序,選擇排序和插入排序。因為他們雖然比較次數多,但是移動次數少。比如,如果記錄的關鍵

各種排序演算法思想即實現

下面的演算法都會給出例子與分析,只寫主要思想,有不懂的或者覺得我寫的有錯誤可以留言,我都會關注的,謝謝~ 選擇排序: public void selectSort(int[] a) { for(int i = 0;i<a.le

SHA1雜湊演算法及其C++實現

這裡重點說一下SHA1演算法的實現步驟與程式碼,由於本人水平有限,不過多討論SHA1的數學原理以及應用場景。 SHA1簡介 In cryptography, SHA-1 (Secure Hash Algorithm 1) is a cryptographic

排序演算法及其Java實現(以大根堆為例)

(二叉)堆資料結構是一種陣列物件,如圖所示(下標從0開始),它完全可以被視為一棵完全二叉樹。 接下來要出現的幾個詞語,這裡介紹一下: length[A]: 陣列A中元素的個數 heap-size[A]: 存放在陣列A中堆的元素的個數,是要排序的元素的個

各種排序演算法實現及其比較(c++實現

轉載自: http://lib.csdn.net/article/datastructure/9028     CSDN資料結構與演算法 排序演算法是筆試和麵試中最喜歡考到的內容,今晚花了好幾個小時的時間把之前接觸過的排序演算法都重新實現了一遍。 主要是作為複習用。當

各種排序演算法詳解C++實現

1.氣泡排序 時間複雜度 O ( n

氣泡排序演算法(起泡排序及其C語言實現

起泡排序,別名“氣泡排序”,該演算法的核心思想是將無序表中的所有記錄,通過兩兩比較關鍵字,得出升序序列或者降序序列。 例如,對無序表{49,38,65,97,76,13,27,49}進行升序排序的具體實現過程如圖 1 所示: 圖 1 第一次起泡 如圖 1 所示是對無序表的第一次起泡排序,最終將無序

各種排序演算法的場景以及c++實現(插入排序,希爾排序,氣泡排序,快速排序,選擇排序,歸併排序

對現有工作並不是很滿意,所以決定找下一個坑。由工作中遇到排序場景並不多,大都是用氣泡排序,太low,面試又經常問到一些排序演算法方面的東西。剛好讓小學妹郵的資料結構也到了。就把各種排序演算法重新總結一下,以作留存。 排序分為內部排序和外部排序,內部排序是在記憶體中排序。外