0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

常見排序算法分類

科技綠洲 ? 來源:一起學(xué)嵌入式 ? 作者:一起學(xué)嵌入式 ? 2023-06-22 14:49 ? 次閱讀

本文將通過動態(tài)演示+代碼的形式系統(tǒng)地總結(jié)十大經(jīng)典排序算法。

排序算法

算法分類 —— 十種常見排序算法可以分為兩大類:

  • 比較類排序:通過比較來決定元素間的相對次序,由于其時間復(fù)雜度不能突破O(nlogn),因此也稱為非線性時間比較類排序。
  • 非比較類排序:不通過比較來決定元素間的相對次序,它可以突破基于比較排序的時間下界,以線性時間運行,因此也稱為線性時間非比較類排序。

圖片

算法復(fù)雜度

排序算法 平均時間復(fù)雜度 最差時間復(fù)雜度 空間復(fù)雜度 數(shù)據(jù)對象穩(wěn)定性
冒泡排序 O(n2) O(n2) O(1) 穩(wěn)定
選擇排序 O(n2) O(n2) O(1) 數(shù)組不穩(wěn)定、鏈表穩(wěn)定
插入排序 O(n2) O(n2) O(1) 穩(wěn)定
快速排序 O(n*log2n) O(n2) O(log2n) 不穩(wěn)定
堆排序 O(n*log2n) O(n*log2n) O(1) 不穩(wěn)定
歸并排序 O(n*log2n) O(n*log2n) O(n) 穩(wěn)定
希爾排序 O(n*log2n) O(n2) O(1) 不穩(wěn)定
計數(shù)排序 O(n+m) O(n+m) O(n+m) 穩(wěn)定
桶排序 O(n) O(n) O(m) 穩(wěn)定
基數(shù)排序 O(k*n) O(n2) 穩(wěn)定

1. 冒泡排序

算法思想:

  • (1)比較相鄰的元素。如果第一個比第二個大,就交換它們兩個;
  • (2)對每一對相鄰元素作同樣的工作,從開始第一對到結(jié)尾的最后一對,這樣在最后的元素應(yīng)該會是最大的數(shù);
  • (3)針對所有的元素重復(fù)以上的步驟,除了最后一個;
  • (4)重復(fù)步驟1~3,直到排序完成。

圖片

代碼:

void bubbleSort(int a[], int n)
{
  for(int i =0 ; i< n-1; ++i)
  {
    for(int j = 0; j < n-i-1; ++j)
    {
      if(a[j] > a[j+1])
      {
        int tmp = a[j] ;  //交換
        a[j] = a[j+1] ;
        a[j+1] = tmp;
      }
    }
  }
}

2. 選擇排序

算法思想:

  • (1)在未排序序列中找到最小(大)元素,存放到排序序列的起始位置;
  • (2)從剩余未排序元素中繼續(xù)尋找最?。ù螅┰?,然后放到已排序序列的末;
  • (3)以此類推,直到所有元素均排序完畢;

圖片

代碼:

void selectionSort(int arr[], int n) {
    int minIndex, temp;
    for (int i = 0; i < n - 1; i++) {
        minIndex = i;
        for (var j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {     // 尋找最小的數(shù)
                minIndex = j;                 // 將最小數(shù)的索引保存
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    for (int k = 0; i < n; i++) {
        printf("%d ", arr[k]);
    }
}

3. 插入排序

算法思想:

  • (1)從第一個元素開始,該元素可以認為已經(jīng)被排序;
  • (2)取出下一個元素,在已經(jīng)排序的元素序列中從后向前掃描;
  • (3)如果該元素(已排序)大于新元素,將該元素移到下一位置;
  • (4)重復(fù)步驟3,直到找到已排序的元素小于或者等于新元素的位置;
  • (5)將新元素插入到該位置后;
  • (6)重復(fù)步驟2~5。

圖片

代碼:

void print(int a[], int n ,int i){
  cout< ":";
  for(int j= 0; j< 8; j++){
    cout< " ";
  }
  cout<

算法分析:插入排序在實現(xiàn)上,通常采用in-place排序(即只需用到O(1)的額外空間的排序),因而在從后向前掃描過程中,需要反復(fù)把已排序元素逐步向后挪位,為最新元素提供插入空間。

4. 快速排序

快速排序的基本思想是通過一趟排序?qū)⒋庞涗浄指舫瑟毩⒌膬刹糠郑渲幸徊糠钟涗浀年P(guān)鍵字均比另一部分的關(guān)鍵字小,則可分別對這兩部分記錄繼續(xù)進行排序,以達到整個序列有序。

算法思想:

  • (1)選取第一個數(shù)為基準(zhǔn)
  • (2)將比基準(zhǔn)小的數(shù)交換到前面,比基準(zhǔn)大的數(shù)交換到后面
  • (3)遞歸地(recursive)把小于基準(zhǔn)值元素的子數(shù)列和大于基準(zhǔn)值元素的子數(shù)列排序

圖片

代碼:

void QuickSort(vector< int >& v, int low, int high) {
    if (low >= high)  // 結(jié)束標(biāo)志
        return;
    int first = low;  // 低位下標(biāo)
    int last = high;  // 高位下標(biāo)
    int key = v[first];  // 設(shè)第一個為基準(zhǔn)

    while (first < last)
    {
        // 將比第一個小的移到前面
        while (first < last && v[last] >= key)
            last--;
        if (first < last)
            v[first++] = v[last];

        // 將比第一個大的移到后面
        while (first < last && v[first] <= key)
            first++;
        if (first < last)
            v[last--] = v[first];
    }
    //
    v[first] = key;
    // 前半遞歸
    QuickSort(v, low, first - 1);
    // 后半遞歸
    QuickSort(v, first + 1, high);
}

5. 堆排序

堆排序(Heapsort)是指利用堆這種數(shù)據(jù)結(jié)構(gòu)所設(shè)計的一種排序算法。堆積是一個近似完全二叉樹的結(jié)構(gòu),并同時滿足堆積的性質(zhì):即子節(jié)點的鍵值或索引總是小于(或者大于)它的父節(jié)點。

算法思想:

  • (1)將初始待排序關(guān)鍵字序列(R1,R2….Rn)構(gòu)建成大頂堆,此堆為初始的無序區(qū);
  • (2)將堆頂元素R[1]與最后一個元素R[n]交換,此時得到新的無序區(qū)(R1,R2,……Rn-1)和新的有序區(qū)(Rn),且滿足R[1,2…n-1]<=R[n];
  • (3)由于交換后新的堆頂R[1]可能違反堆的性質(zhì),因此需要對當(dāng)前無序區(qū)(R1,R2,……Rn-1)調(diào)整為新堆,然后再次將R[1]與無序區(qū)最后一個元素交換,得到新的無序區(qū)(R1,R2….Rn-2)和新的有序區(qū)(Rn-1,Rn)。不斷重復(fù)此過程直到有序區(qū)的元素個數(shù)為n-1,則整個排序過程完成。

圖片

代碼:

#include 
#include 
using namespace std;

// 堆排序:(最大堆,有序區(qū))。從堆頂把根卸出來放在有序區(qū)之前,再恢復(fù)堆。

void max_heapify(int arr[], int start, int end) {
    //建立父節(jié)點指標(biāo)和子節(jié)點指標(biāo)
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) { //若子節(jié)點在范圍內(nèi)才做比較
        if (son + 1 <= end && arr[son] < arr[son + 1]) //先比較兩個子節(jié)點指標(biāo),選擇最大的
            son++;
        if (arr[dad] > arr[son]) //如果父節(jié)點大于子節(jié)點代表調(diào)整完成,直接跳出函數(shù)
            return;
        else { //否則交換父子內(nèi)容再繼續(xù)子節(jié)點與孫節(jié)點比較
            swap(arr[dad], arr[son]);
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

void heap_sort(int arr[], int len) {
    //初始化,i從最后一個父節(jié)點開始調(diào)整
    for (int i = len / 2 - 1; i >= 0; i--)
        max_heapify(arr, i, len - 1);
    //先將第一個元素和已經(jīng)排好的元素前一位做交換,再從新調(diào)整(剛調(diào)整的元素之前的元素),直到排序完成
    for (int i = len - 1; i > 0; i--) {
        swap(arr[0], arr[i]);
        max_heapify(arr, 0, i - 1);
    }
}

int main() {
    int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };
    int len = (int) sizeof(arr) / sizeof(*arr);
    heap_sort(arr, len);
    for (int i = 0; i < len; i++)
        cout < < arr[i] < < ' ';
    cout < < endl;
    return 0;
}

6. 歸并排序

歸并排序是建立在歸并操作上的一種有效的排序算法。該算法是采用分治法(Divide and Conquer)的一個非常典型的應(yīng)用。將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合并成一個有序表,稱為2-路歸并。

算法思想:

  • (1)把長度為n的輸入序列分成兩個長度為n/2的子序列;
  • (2)對這兩個子序列分別采用歸并排序;
  • (3)將兩個排序好的子序列合并成一個最終的排序序列。

圖片

代碼:

void print(int a[], int n){
  for(int j= 0; j< n; j++){
    cout<

7. 希爾排序

1959年Shell發(fā)明,第一個突破O(n2)的排序算法,是簡單插入排序的改進版。它與插入排序的不同之處在于,它會優(yōu)先比較距離較遠的元素。希爾排序又叫縮小增量排序。

算法思想:

  • (1)選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;
  • (2)按增量序列個數(shù)k,對序列進行k 趟排序;
  • (3)每趟排序,根據(jù)對應(yīng)的增量ti,將待排序列分割成若干長度為m 的子序列,分別對各子表進行直接插入排序。僅增量因子為1 時,整個序列作為一個表來處理,表長度即為整個序列的長度。

圖片

代碼:

void shell_sort(T array[], int length) {
    int h = 1;
    while (h < length / 3) {
        h = 3 * h + 1;
    }
    while (h >= 1) {
        for (int i = h; i < length; i++) {
            for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {
                std::swap(array[j], array[j - h]);
            }
        }
        h = h / 3;
    }
}

8. 計數(shù)排序

計數(shù)排序不是基于比較的排序算法,其核心在于將輸入的數(shù)據(jù)值轉(zhuǎn)化為鍵存儲在額外開辟的數(shù)組空間中。作為一種線性時間復(fù)雜度的排序,計數(shù)排序要求輸入的數(shù)據(jù)必須是有確定范圍的整數(shù)。

算法思想:

  • (1)找出待排序的數(shù)組中最大和最小的元素;
  • (2)統(tǒng)計數(shù)組中每個值為i的元素出現(xiàn)的次數(shù),存入數(shù)組C的第i項;
  • (3)對所有的計數(shù)累加(從C中的第一個元素開始,每一項和前一項相加);
  • (4)反向填充目標(biāo)數(shù)組:將每個元素i放在新數(shù)組的第C(i)項,每放一個元素就將C(i)減去1。

圖片

代碼:

#include 
#include 
#include 

using namespace std;

// 計數(shù)排序
void CountSort(vector< int >& vecRaw, vector< int >& vecObj)
{
    // 確保待排序容器非空
    if (vecRaw.size() == 0)
        return;

    // 使用 vecRaw 的最大值 + 1 作為計數(shù)容器 countVec 的大小
    int vecCountLength = (*max_element(begin(vecRaw), end(vecRaw))) + 1;
    vector< int > vecCount(vecCountLength, 0);

    // 統(tǒng)計每個鍵值出現(xiàn)的次數(shù)
    for (int i = 0; i < vecRaw.size(); i++)
        vecCount[vecRaw[i]]++;
    
    // 后面的鍵值出現(xiàn)的位置為前面所有鍵值出現(xiàn)的次數(shù)之和
    for (int i = 1; i < vecCountLength; i++)
        vecCount[i] += vecCount[i - 1];

    // 將鍵值放到目標(biāo)位置
    for (int i = vecRaw.size(); i > 0; i--) // 此處逆序是為了保持相同鍵值的穩(wěn)定性
        vecObj[--vecCount[vecRaw[i - 1]]] = vecRaw[i - 1];
}

int main()
{
    vector< int > vecRaw = { 0,5,7,9,6,3,4,5,2,8,6,9,2,1 };
    vector< int > vecObj(vecRaw.size(), 0);

    CountSort(vecRaw, vecObj);

    for (int i = 0; i < vecObj.size(); ++i)
        cout < < vecObj[i] < < "  ";
    cout < < endl;

    return 0;
}

9. 桶排序

將值為i的元素放入i號桶,最后依次把桶里的元素倒出來。

算法思想:

  • (1)設(shè)置一個定量的數(shù)組當(dāng)作空桶子。
  • (2)尋訪序列,并且把項目一個一個放到對應(yīng)的桶子去。
  • (3)對每個不是空的桶子進行排序。
  • (4)從不是空的桶子里把項目再放回原來的序列中。

圖片

代碼:

void Bucket_Sort(int a[], int n, int max) {
    int i, j=0;
    int *buckets = (int*)malloc((max+1)*sizeof(int));
    // 將buckets中的所有數(shù)據(jù)都初始化為0
    memset(buckets, 0, (max+1) * sizeof(int));
    // 1.計數(shù)
    for (i = 0; i < n; i++) {
        buckets[a[i]]++;
        printf("%d : %d\\n", a[i], buckets[a[i]]);
    }
    printf("\\n");
    // 2.排序
    for (i = 0; i < max+1; i++) {
        while ((buckets[i]--) > 0) {
            a[j++] = i;
        }
    }
}
 
int main() {
    int arr[] = { 9,5,1,6,2,3,0,4,8,7 };
    Bucket_Sort(arr, 10,9);
    for (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    printf("\\n");
 
    return 0;
}

10. 基數(shù)排序

一種多關(guān)鍵字的排序算法,可用桶排序?qū)崿F(xiàn)。

算法思想:

  • 取得數(shù)組中的最大數(shù),并取得位數(shù);
  • arr為原始數(shù)組,從最低位開始取每個位組成radix數(shù)組;
  • 對radix進行計數(shù)排序(利用計數(shù)排序適用于小范圍數(shù)的特點)

圖片

代碼:

int maxbit(int data[], int n) //輔助函數(shù),求數(shù)據(jù)的最大位數(shù)
{
    int maxData = data[0];  ///< 最大數(shù)
    /// 先求出最大數(shù),再求其位數(shù),這樣有原先依次每個數(shù)判斷其位數(shù),稍微優(yōu)化點。
    for (int i = 1; i < n; ++i)
    {
        if (maxData < data[i])
            maxData = data[i];
    }
    int d = 1;
    int p = 10;
    while (maxData >= p)
    {
        //p *= 10; // Maybe overflow
        maxData /= 10;
        ++d;
    }
    return d;
/*    int d = 1; //保存最大的位數(shù)
    int p = 10;
    for(int i = 0; i < n; ++i)
    {
        while(data[i] >= p)
        {
            p *= 10;
            ++d;
        }
    }
    return d;*/
}
void radixsort(int data[], int n) //基數(shù)排序
{
    int d = maxbit(data, n);
    int *tmp = new int[n];
    int *count = new int[10]; //計數(shù)器
    int i, j, k;
    int radix = 1;
    for(i = 1; i <= d; i++) //進行d次排序
    {
        for(j = 0; j < 10; j++)
            count[j] = 0; //每次分配前清空計數(shù)器
        for(j = 0; j < n; j++)
        {
            k = (data[j] / radix) % 10; //統(tǒng)計每個桶中的記錄數(shù)
            count[k]++;
        }
        for(j = 1; j < 10; j++)
            count[j] = count[j - 1] + count[j]; //將tmp中的位置依次分配給每個桶
        for(j = n - 1; j >= 0; j--) //將所有桶中記錄依次收集到tmp中
        {
            k = (data[j] / radix) % 10;
            tmp[count[k] - 1] = data[j];
            count[k]--;
        }
        for(j = 0; j < n; j++) //將臨時數(shù)組的內(nèi)容復(fù)制到data中
            data[j] = tmp[j];
        radix = radix * 10;
    }
    delete []tmp;
    delete []count;
}
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 線性
    +關(guān)注

    關(guān)注

    0

    文章

    194

    瀏覽量

    25079
  • 排序算法
    +關(guān)注

    關(guān)注

    0

    文章

    51

    瀏覽量

    10042
收藏 人收藏

    評論

    相關(guān)推薦

    Python實現(xiàn)的常見內(nèi)部排序算法

    排序算法可以分為內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進行排序,而外部
    發(fā)表于 07-06 12:35 ?314次閱讀
    Python實現(xiàn)的<b class='flag-5'>常見</b>內(nèi)部<b class='flag-5'>排序</b><b class='flag-5'>算法</b>

    FPGA排序-冒泡排序介紹

    排序算法是圖像處理中經(jīng)常使用一種算法,常見排序算法有插入
    發(fā)表于 07-17 10:12 ?963次閱讀
    FPGA<b class='flag-5'>排序</b>-冒泡<b class='flag-5'>排序</b>介紹

    十大排序算法總結(jié)

    排序算法是最經(jīng)典的算法知識。因為其實現(xiàn)代碼短,應(yīng)該廣,在面試中經(jīng)常會問到排序算法及其相關(guān)的問題。一般在面試中最常考的是快速
    的頭像 發(fā)表于 12-20 10:39 ?985次閱讀

    嵌入式stm32實用的排序算法 - 交換排序

    合很多,我這里就不再一一舉例說明,掌握排序的基本算法,到時候遇到就有用武之地。Ⅱ、排序算法分類1.按存儲
    發(fā)表于 04-12 13:14

    各種排序算法的時間空間復(fù)雜度、穩(wěn)定性

    各種排序算法的時間空間復(fù)雜度、穩(wěn)定性一、排序算法分類:二、排序
    發(fā)表于 12-21 07:48

    基于文本分類的網(wǎng)頁排序算法

             隨著web 技術(shù)的發(fā)展,好的網(wǎng)頁排序算法越來越重要。本文主要討論了網(wǎng)頁排序應(yīng)當(dāng)考慮的因素如網(wǎng)頁更新時間等。在對這些因素進行分析之后
    發(fā)表于 09-12 11:29 ?8次下載

    C語言教程之幾種排序算法

    數(shù)據(jù)結(jié)構(gòu)的排序算法有很多種。 其中, 快速排序 、希爾排序、堆排序、直接選擇排序不是穩(wěn)定的
    發(fā)表于 11-16 10:23 ?1708次閱讀

    基于排序學(xué)習(xí)的推薦算法

    排序學(xué)習(xí)技術(shù)嘗試用機器學(xué)習(xí)的方法解決排序問題,已被深入研究并廣泛應(yīng)用于不同的領(lǐng)域,如信息檢索、文本挖掘、個性化推薦、生物醫(yī)學(xué)等.將排序學(xué)習(xí)融入推薦算法中,研究如何整合大量用戶和物品的特
    發(fā)表于 01-16 15:50 ?0次下載
    基于<b class='flag-5'>排序</b>學(xué)習(xí)的推薦<b class='flag-5'>算法</b>

    數(shù)據(jù)結(jié)構(gòu)常見的八大排序算法

    本文總結(jié)了數(shù)據(jù)結(jié)構(gòu)常見的八大排序算法。詳細分析請看下文
    發(fā)表于 02-05 15:26 ?1808次閱讀
    數(shù)據(jù)結(jié)構(gòu)<b class='flag-5'>常見</b>的八大<b class='flag-5'>排序</b><b class='flag-5'>算法</b>

    常用的排序算法總覽

    我們通常所說的排序算法往往指的是內(nèi)部排序算法,即數(shù)據(jù)記錄在內(nèi)存中進行排序。
    的頭像 發(fā)表于 06-13 18:18 ?2718次閱讀
    常用的<b class='flag-5'>排序</b><b class='flag-5'>算法</b>總覽

    實用的排序算法 - 交換排序

    實用的排序算法 - 交換排序
    的頭像 發(fā)表于 03-20 09:53 ?1667次閱讀
    實用的<b class='flag-5'>排序</b><b class='flag-5'>算法</b> -  交換<b class='flag-5'>排序</b>

    排序算法分享:歸并排序說明

    我們今天繼續(xù)給大家分享排序算法里面的另外一種排序算法:歸并排序!
    的頭像 發(fā)表于 12-24 14:34 ?701次閱讀

    淺談希爾排序算法思想以及如何實現(xiàn)

    01 希爾排序算法思想 希爾排序也是一種插入排序,是簡單插入排序改進后的一個更高效版本,同時也是首批突破O(n^2)
    的頭像 發(fā)表于 06-30 10:05 ?1947次閱讀

    排序算法的基本邏輯

    排序是數(shù)據(jù)結(jié)構(gòu)與算法里面最基礎(chǔ)最入門的內(nèi)容,雖然簡單,但是深入研究的話里面還是有很多內(nèi)容的,今天我們來全面詳細的講一講各種排序算法分類、原
    的頭像 發(fā)表于 08-31 09:16 ?3070次閱讀

    動圖演示C語言10大經(jīng)典排序算法(含代碼)

    本文將通過 動態(tài)演示+代碼 的形式系統(tǒng)地總結(jié)十大經(jīng)典排序算法。 排序算法 算法分類 十種
    的頭像 發(fā)表于 02-07 01:24 ?602次閱讀