1. 程式人生 > >九種經典排序演算法詳解(氣泡排序,插入排序,選擇排序,快速排序,歸併排序,堆排序,計數排序,桶排序,基數排序)

九種經典排序演算法詳解(氣泡排序,插入排序,選擇排序,快速排序,歸併排序,堆排序,計數排序,桶排序,基數排序)

綜述

最近複習了各種排序演算法,記錄了一下學習總結和心得,希望對大家能有所幫助。本文介紹了氣泡排序、插入排序、選擇排序、快速排序、歸併排序、堆排序、計數排序、桶排序、基數排序9種經典的排序演算法。針對每種排序演算法分析了演算法的主要思路,每個演算法都附上了虛擬碼和C++實現。

電梯直達

演算法分類

原地排序(in-place):沒有使用輔助資料結構來儲存中間結果的排序**演算法。
非原地排序(not-in-place / out-of-place):使用了輔助資料結構來儲存中間結果的排序演算法
穩定排序:數列值(key)相等的元素排序後相對順序維持不變
不穩定排序:不屬於穩定排序的排序演算法

演算法複雜度

1. 氣泡排序(Bubble Sort)

思路

不斷地遍歷數列,比較相鄰元素,每次把無序部分最大的元素放到最後,遍歷n-1次後,數列就是有序的了。

虛擬碼

BUBBLE_SORT(A, n)
    for( i from 0 to n-2) //遍歷n-1次
        for(j from 0 to n-2-i) //比較無序部分的所有相鄰元素
            if(A[j] > A[j+1]) //如果前面的元素大,放到後面去
                swap(A[i],A[j+1])
                swapped = true
if(not swapped) //如果以第j個數為起點遍歷,沒有發生交換,說明後面已經有序了 break;

最好情況

輸入數列有序,第一次遍歷結束就會完成排序,時間複雜度最好為Ω(n)

C++實現

void bubbleSort(vector<int> &arr)
{
    for(int i = 0; i < arr.size() - 1; i++)
    {
        bool swapped = false;
        for(int j = 0; j < arr.size() - 1
- i; j++) { if(arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; swapped = true; } } if(!swapped) { break; } } }

2. 插入排序(Insertion Sort)

思路

把數列分為有序和無序部分,每次從無序部分拿出第一個元素,然後從後向前掃描有序部分,找到相應位置並插入,具體來說就是對於比當前元素大的元素,往後移動一位。直到找到比當前元素小的,在該元素後面插入當前元素

虛擬碼

INSERTION_SORT(A,n)
    for(i from 1 to n-1) //從1開始遍歷無序陣列
        temp = A[i] //取出當前元素
            j = i-1 
                while(j >= 0 and temp < A[j]) //比temp大的元素後移
            A[j+1] = A[j]
            j -= 1
        arr[j+1] = temp;  //temp 放入第0個或者第一個不比temp大的元素

最好情況

輸入數列有序,每次插入都是直接插在了有序部分的後面,時間複雜度最好為Ω(n)

C++實現

void insertionSort(vector<int> &arr)
{
    for(int i=1; i<arr.size(); i++)
    {
        int temp = arr[i];
        int j = i -1;
        while(j >=0 && temp < arr[j])
        {
            arr[j+1] = arr[j];
            j--;
        }
        arr[j+1] = temp;
    }
}

3. 選擇排序(Selection Sort)

思路

數列分為有序部分和無序部分,重複下列過程n次:找到無序部分中最小的數,放到有序部分的最後面(即和無序部分的第一個置換)

虛擬碼

SELECTION_SORT(A, n)
    for(i from 0 to n-2) //i指向無序部分的開頭,n-2為倒數第二個元素的索引
        for(j from i to n-1) // 找到無序部分最小的元素
            minLoc = findMin()
        swap(A[i],A[minLoc]) //最小的元素置換到i位置上(加入了有序部分)

C++實現

void selectionSort(vector<int> &arr)
{
    for(int i=0; i<arr.size()-1; i++)
    {
        int min = INT_MAX;
        int minLoc = -1;
        for(int j=i; j<arr.size(); j++)
        {
            if(arr[j] < min)
            {
                min = arr[j];
                minLoc = j;
            }
        }
        arr[minLoc] = arr[i];
        arr[i] = min;
    }
}

4. 快速排序 (Quick Sort)

思路

使用分治演算法,每次以pivot為基準將數列分成兩部分,左邊的都小於等於基準,右邊的都大於基準,然後分別遞迴地對左右兩部分進行快速排序(終止條件是元素個數為1個或者0個)。演算法的核心在於分割槽(把數列分成兩部分)
分割槽時,從數列中選擇一個元素作為pivot(一般選最後一個,翻譯為“基準”或者“哨兵”),使用兩個指標,第一個指標始終指向左邊部分的結尾(初始位置為-1),第二個指標用於遍歷數列(初始位置為0),發現小於等於pivot的就和右部分第一個數字互換(相當於把數加入了左邊部分),比pivot大的數就跳過(相當於把數加入了右邊部分)

虛擬碼

QUICK_SORT(A,head,tail) //輸入數列A,[head, tail),不包含tail
    if(tail - head > 1) //元素個數低於1個,有序,停止遞迴
        pivot = PARTITION(A,head,tail) //分割槽,獲得pivot索引
        QUICK_SORT(A,head,pivot)//遞迴
        QUICK_SORT(A,pivot+1,tail)//遞迴,pivot已經在正確的位置上了,不參與後續排序

PARTITION(A,head,tail) //分割槽,[head,tail)
    i = head - 1 //i初始化為head-1,代表著左半邊現在沒有元素
    pivot = A[tail-1] //選擇最後一個元素作為pivot
    for(j from head to tail-2) //遍歷全部元素(除了最後一個 tail-1)
        if(A[j] <= pivot)//發現小於等於pivot的元素,置換(大於的話,j就直接後移了)
            i += 1 //i此時指向了大於pivot的區的第一個元素
            swap(A[i],A[j])
    swap(A[i+1],A[tail-1]) //最後把pivot放到中間位置
    return i+1 //返回pivot

最壞情況

  • 輸入的數列是有序數列,這樣每次分割槽選到的pivot都是當前最大值,每次分割槽的結果都是左邊n-1個數,右邊0個數,需要進行n-1分割槽,遞迴深度為n,時間複雜度為O(n^2)
  • 輸入的數列是逆序數列,與上面的情況類似,時間複雜也也為O(n^2)

最好情況

每次分割槽的結果都是均勻的分成了左右兩部分,那麼時間複雜度就是Θ(n log(n))

C++實現

void quickSort(vector<int> &arr)
{
    quickSort(arr, 0, arr.size());
}

void quickSort(vector<int> &arr, int head, int tail)
{
    if(tail - head > 1)
    {
        int pivot = partition(arr, head, tail);
        quickSort(arr, head, pivot);
        quickSort(arr, pivot+1, tail);
    }
}


int partition(vector<int> &arr, int head, int tail)
{
    int i = head - 1;
    int pivot = arr[tail - 1];
    for(int j = head; j < tail - 1; j++)
    {
        //這裡不能用<,陣列為[3,3]這樣時,i沒有移動過,一直為-1,quickSort在右半部分永久進行遞迴[0,2)
        if(arr[j] <= pivot)
        {
            i++;
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    arr[tail - 1] = arr[i + 1];
    arr[i + 1] = pivot;
    return i + 1;
}

5. 歸併排序(Merge Sort)

思路

使用分治演算法,把數列均勻地分成左右兩部分,分別進行歸併排序(遞迴終止條件為只有一個或者0個元素),然後將左右兩個有序數列合併到一起。

虛擬碼

MERGE_SORT(A,head,tail)
    if(tail - head < 2) //元素個數小於2個就停止了
        return
    mid = (head + tail)/2 
    MERGE_SORT(A,head,mid) //左邊歸併排序
    MERGE_SORT(A,mid,tail) //右邊歸併排序
    copy A[head,mid) to B //複製A的左半部分到B,B有序
    copy A[mid,tail) to C //複製A的右半部分到C,C有序
    merge B,C to A //合併B和C兩個有序數列,將結果放在A中

C++實現

void mergeSort(vector<int> &arr)
{
    mergeSort(arr, 0, arr.size());
}

void mergeSort(vector<int> &arr, int head, int tail)
{
    if(tail - head < 2)
    {
        return;
    }
    int mid = (head + tail) / 2;
    mergeSort(arr, head, mid);
    mergeSort(arr, mid, tail);
    vector<int> left(arr.begin() + head, arr.begin() + mid);
    vector<int> right(arr.begin() + mid, arr.begin() + tail);
    int i = 0, j = 0, k = head;
    while(i < left.size() && j < right.size() && k < tail) //這裡k判斷條件是小於tail,不是arr.size()!!
    {
        if(left[i] < right[j])
        {
            arr[k++] = left[i++];
        } else
        {
            arr[k++] = right[j++];
        }
    }
    if(i == left.size())
    {
        while(j < right.size() && k < tail)
        {
            arr[k++] = right[j++];
        }
    } else if(j == right.size())
    {
        while(i < left.size() && k < tail)
        {
            arr[k++] = left[i++];
        }
    }
}

6. 堆排序(Heap Sort)

思路

構建大頂堆(降序構建小頂堆),然後交換root節點和最後一個節點,此時將堆的大小減1,並利用堆化演算法把堆重新調整為大頂堆,重複上述過程,直到大小為1,堆排序完成,因為每次都是把堆當前最大的數放到堆後面,所以數列最終變成有序了。
堆化演算法針對root的左右孩子均為大頂堆,但是root自己可能比左右孩子小的情況,演算法比較root和左右孩子,選擇最大的和root進行置換(如果root最大就不用置換了),置換後以被置換的孩子為root繼續執行堆化演算法,直到當前root比左右孩子大了或者已經是葉子節點了。
這是一個大頂堆

虛擬碼

//堆化演算法,左右孩子均為大頂堆,root可能比左右孩子小,違反大頂堆性質
MAX_HEAPIFY(A,i) //i是當前root的索引
    left = i*2+1
    right = i*2 + 2
    //找到左、右孩子,root中的最大值
    max = i
    if(left < heapSize and A[left] > A[i])
        max = left;
    if(right <headpSize and A[right] > A[max])
        max = right
    if(max != i) //最大值不是root節點,交換之,並繼續堆化被破壞的子堆
        swap(A[i],A[max])
        MAX_HEAPIFY(A,max)

//自底向上構建大頂堆
BUILD_MAX_HEAP(A,n)
    //從最後一個父節點開始(n-1)為最後一個元素的索引,自底向上執行堆化演算法
    for(i from ((n-1)-1)/2 to 0)
        MAX_HEAPIFY(A,i)

///堆排序演算法,不斷把root置換到堆的後面,heapSize減一併執行堆化演算法
HEAP_SORT(A,n)
    BUILD_MAX_HEAP(A,n)
    for(i from n-1 to 1)
        swap(A[i],A[0])
        heapSize -= 1
        MAX_HEAPIFY(A,0)

C++實現

void heapSort(vector<int> &arr)
{
    buildMaxHeap(arr);
    int heapSize = arr.size();
    for(int i = arr.size() - 1; i > 0; i--)
    {
        int temp = arr[i];
        arr[i] = arr[0];
        arr[0] = temp;
        heapSize--;
        maxHeapify(arr,heapSize,0);
    }
}

void buildMaxHeap(vector<int> &arr)
{
    for(int i = ((arr.size() - 1) - 1) / 2; i >= 0; i--)
    {
        maxHeapify(arr,arr.size(),i);
    }
}

void maxHeapify(vector<int> &arr, int heapSize, int root)
{
    int left = root * 2 + 1;
    int right = root * 2 + 2;
    int max = root;
    if(left < heapSize && arr[left] > arr[max])
    {
        max = left;
    }
    if(right < heapSize && arr[right] > arr[max])
    {
        max = right;
    }
    if(max != root)
    {
        int temp = arr[max];
        arr[max] = arr[root];
        arr[root] = temp;
        maxHeapify(arr,heapSize,max);
    }
}

7. 計數排序(Counting Sort)

思路

計數排序是一種非比較排序,對數列中每個元素X,通過統計數列中小於等於X的元素個數來計算X所處的位置進行排序。使用陣列統計元素個數, counts[i]記錄的是小於等於 i 的元素個數。

虛擬碼

COUNTING_SORT(A,n)
    for(i from 0 to n-1) //計數
        counts[A[i]]++
    for(i from 1 to n-1) //累加,以便進行反向填充
        counts[i] += counts[i-1] 
    for(i from n-1 to 0) //反向填充是為了保證排序是穩定的
        B[counts[A[i]]-1] = A[i]
        counts[A[i]] -= 1
    A = B

C++實現:使用陣列計數

void countingSort(vector<int> &arr)
{
    int max = 0;
    for(int i = 0; i < arr.size(); i++)
    {
        if(arr[i] > max)
        {
            max = arr[i];
        }
    }
    vector<int> counts(max + 1, 0);
    for(int i = 0; i < arr.size(); i++)
    {
        counts[arr[i]]++;
    }
    for(int i = 1; i <= max; i++)
    {
        counts[i] += counts[i - 1];
    }
    vector<int> tempArr(arr.size(), -1);
    for(int i = arr.size() - 1; i >= 0; i--)
    {
        tempArr[counts[arr[i]] - 1] = arr[i];
        counts[arr[i]]--;
    }
    arr = move(tempArr);
}

8. 桶排序(Bucket Sort)

思路

把數列中元素的值範圍分割成多個長度相等的區間,稱為桶,把元素按值所在區間分別放到不同的桶中。然後桶內分別進行排序(比如使用插入排序),最終獲得有序數列

虛擬碼

#下面的假設值範圍為0~999,桶數目BNUM為100
INDEX_OF(j)
    return j/10 //這裡根據實際的資料情況和執行環境可以調整桶的分配方式
BUCKET_SORT(A,n)
    list B //桶們
    for(i from 0 to n-1) //分桶
        insert A[i] to B[INDEX_OF[A[i]]]
    for(i from 0 to BUMN-1) 
        INSERTION_SORT(B[i]) //分別桶內排序
    A = B[0] + B[1] + ... + B[BNUM-1] //按序連線各個桶

C++實現

#define BUCKETS_NUM 100
int indexOf(int num)
{
    return num/10;
}

void bucketSort(vector<int> &arr)
{
    vector<vector<int>> buckets(BUCKETS_NUM);
    for(int i=0; i<arr.size(); i++)
    {
        buckets[indexOf(arr[i])].push_back(arr[i]);
    }
    for(int i=0; i<BUCKETS_NUM; i++)
    {
        insertionSort(buckets[i]);
    }

    int k =0;
    for(int i=0; i<BUCKETS_NUM; i++)
    {
        for(int j=0; j<buckets[i].size(); j++)
        {
            arr[k++] = buckets[i][j];
        }
    }
}

9. 基數排序(Radix Sort)

思路

把元素按照位置分割成不同的數字,從最低位部分開始,一直到最高位部分,分別對每部分進行入桶操作,入桶時桶內元素的相對順序不變,然後將桶按順序連線起來,進行下一部分的入桶排序。對整數來說,位數較短的前面補0,下面敘述假定數列元素都是非負整數

為什麼多次入桶後數列就有序了

因為進行高位入桶時是按序入桶的,所以高位相同的數字,低位的順序仍然保留下來了。只有高位不同的數字,低位的順序才會被打亂,高位不同肯定是按照高位的順序排的,所以打亂沒有影響。
下面舉個例子說明一下。
假設待排序數列為 01, 88, 13, 78, 56, 79, 07 , 28, 76 這裡為了方便理解,位數不夠的前面已經補0了。
第一次按照最低位(個位數)入桶

桶編號 0 1 2 3 4 5 6 7 8 9
- 01 13 56 07 78 79
- 76 88
- 28

將桶按順序連線起來,形成新的數列01, 13, 56, 76, 07, 78, 88, 28, 79

第二次按照次最低位(十位數)入桶

桶編號 0 1 2 3 4 5 6 7 8 9
01 13 28 56 76 88
07 78
79

將桶按順序連線起來,得到新的數列01, 07, 13, 28, 56, 76, 78, 79, 88,排序完成

為什麼要從最低位開始

以非負整數為例,每次從最低位開始的話,每次入桶都有10個桶。如果從最高位開始的話,第一次10個桶,第二次如果還是10個桶,那麼如果低位不同,高位的相對順序就會被打亂,這顯然是錯誤的。那麼為了保證高位的順序不被打亂。就必須要在高位的桶內進行排序,即每個桶裡面要再分10個桶。第二位總共需要10*10=100個桶。以此類推n位就需要10^個桶,雖然也可以實現,但是開銷太大,所以不從最高位開始。

虛擬碼

//以對非負整數進行基數排序為例
RADIX_SORT(A,n)
    for(i from d-1 to 0) //d是數字的位數,進行d次入桶(排序)
        for(j from 0 to n-1) 
            put A[j] into B[D[A[j]]] //D[x]是x第i位的值。
        A = B[0] + B[1] + ... + B[9] //按序連線桶

C++實現

void radixSort(vector<int> &arr)
{
    vector<vector<int>> buckets(10);
    int radix = 1;
    for(int i=0; i<10; i++) //INT_MAX為10位數,所以最多進行10次入桶
    {
        for(int j = 0; j < arr.size(); j++)
        {
            buckets[(arr[j] / radix) % 10].push_back(arr[j]);
        }
        int k = 0;
        for(int i = 0; i < 10; i++)
        {
            for(int j = 0; j < buckets[i].size(); j++)
            {
                arr[k++] = buckets[i][j];
            }
            if(buckets[i].size() == arr.size())//全部在一個桶裡了,提前結束
            {
                return;
            }
            buckets[i].clear();
        }
        radix*=10;
    }
}

THE END

相關推薦

經典排序演算法氣泡排序插入排序選擇排序快速排序歸併排序排序計數排序排序基數排序

綜述 最近複習了各種排序演算法,記錄了一下學習總結和心得,希望對大家能有所幫助。本文介紹了氣泡排序、插入排序、選擇排序、快速排序、歸併排序、堆排序、計數排序、桶排序、基數排序9種經典的排序演算法。針對每種排序演算法分析了演算法的主要思路,每個演算法都附上了虛擬

快速排序演算法原理、實現和時間複雜度

快速排序是對氣泡排序的一種改進,由 C.A.R.Hoare(Charles Antony Richard Hoare,東尼·霍爾)在 1962 年提出。 快速排序的基本思想是:通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料比另一部分的所有資料要小,再按這種方法對這兩部分資料分別進行快速排

插入排序演算法C++實現

插入排序 輸入:n個數(a1,a2,...,an)。 輸出:輸入序列的一個排列(a1',a2',...,an'),使得a1'到an'為有序序列。 待排序的數稱為關鍵字key。 插入排序與平時生活中打牌時,整理手中牌的順序相似。最開始手中沒有牌,我們從桌上摸起一張牌,將它

各類排序演算法java版

摘要 整理了一些有關於排序演算法的資料,用java手寫了一些,有些博主懶得寫程式碼了就直接copy了網上的程式碼。在文章的最後還給出排序演算法穩定性的定義以及哪些是穩定的排序演算法。 目錄 一、快速排序 二、堆排序 三、插入排序 四、氣泡排序

常用的排序演算法C#版

只要是搞程式設計的演算法、資料結構、作業系統、計算機組成原理這些東西都會有用到,就像醫生給人治病一樣,只有瞭解了人的內部機理、運作機制,才能很好的做到對症下藥,藥到病除。而上面所說的那些計算機理論課就好像人的內部機理一樣,我們往往都把這些東西給忽略了,而把更多的精力放在具體的程式語言實現上,當然我也是這樣,

經典排序演算法1——氣泡排序演算法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

經典排序演算法4——折半插入排序演算法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

必須知道的八大排序演算法【java實現】 歸併排序演算法排序演算法

一、歸併排序演算法 基本思想:   歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然後再把有序子序列合併為整體有序序列。 歸併排序示例:   合併方法: 設r[i…n]由兩個有序子表r[i…m]和r[m+1…n]組

經典排序演算法6——直接選擇排序演算法

直接選擇排序(Straight Select Sort)是一種典型的選擇排序演算法,通過不斷選擇序列中最大(小)的元素。 一、演算法基本思想 (1)基本思想 直接選擇排序的基本思想就

這是我見過最詳細的十大排序演算法介紹了沒有之一十大排序演算法

> **作者:** C you again,從事軟體開發 努力在IT搬磚路上的技術小白 > **公眾號:** 【**[C you again](https://cyouagain.cn/)**】,分享計算機類畢業設計原始碼、IT技術文章、遊戲原始碼、網頁模板、程式人生等等。公眾號回覆 【**粉絲

排序方法選擇排序氣泡排序插入排序快速排序

由於本帖只是闡述幾種排序方法的原理、如何區分以及編寫幾種排序的簡單程式碼,所以直接給定陣列是 a[ ]={6,2,8,5,1},需要把以上5個數字按升序排列 1. 選擇排序法 (如果不想看解釋分析,直接往後拉看程式碼) 實質: 第一輪:通過對比陣列中前一個元素和後一個元素

經典排序演算法——氣泡排序演算法

一、演算法基本思想 (1)基本思想 氣泡排序的基本思想就是:從無序序列頭部開始,進行兩兩比較,根據大小交換位置,直到最後將最大(小)的資料元素交換到了無序佇列的隊尾,從而成為有序序列的一部分;下一次繼續這個過程,直到所有資料元素都排好序。 演算法的核心在於每次通過兩兩比較交換位置,選

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

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

深度學習 --- BP演算法誤差反向傳播演算法

本節開始深度學習的第一個演算法BP演算法,本打算第一個演算法為單層感知器,但是感覺太簡單了,不懂得找本書看看就會了,這裡簡要的介紹一下單層感知器: 圖中可以看到,單層感知器很簡單,其實本質上他就是線性分類器,和機器學習中的多元線性迴歸的表示式差不多,因此它具有多元線性迴歸的優點和缺點。

SELECT INTO 和 INSERT INTO SELECT 兩表複製語句SQL資料庫和Oracle資料庫的區別

https://www.cnblogs.com/mq0036/p/4155136.html 我們經常會遇到需要表複製的情況,如將一個table1的資料的部分欄位複製到table2中,或者將整個table1複製到table2中,這時候我們就要使用SELECT INTO 和 INSER

深度學習 --- 模擬退火演算法Simulated Annealing SA

上一節我們深入探討了,Hopfield神經網路的性質,介紹了吸引子和其他的一些性質,而且引出了偽吸引子,因為偽吸引子的存在導致Hopfield神經網路正確率下降,因此本節致力於解決偽吸引子的存在。在講解方法之前我們需要再次理解一些什麼是偽吸引子,他到底是如何產生的? 簡單來說說就是網路動態轉

深度學習 --- BP演算法BP演算法的優化

上一節我們詳細分析了BP網路的權值調整空間的特點,深入分析了權值空間存在的兩個問題即平坦區和區域性最優值,也詳細探討了出現的原因,本節將根據上一節分析的原因進行改進BP演算法,本節先對BP存在的缺點進行全面的總結,然後給出解決方法和思路,好,下面正式開始本節的內容: BP演算法可以完成非線性

深度學習 --- BP演算法流程圖、BP主要功能、BP演算法的侷限性

上一節我們詳細推倒了BP演算法的來龍去脈,請把原理一定要搞懂,不懂的請好好理解BP演算法詳解,我們下面就直接把上一節推匯出的權值調整公式拿過來,然後給出程式流程圖,該流程圖是嚴格按照上一節的權值更新過程寫出的,因此稱為標準的BP演算法,標準的BP演算法中,每輸入一個樣本,都要回傳誤差並調整權值,

常用Java排序演算法

  一、最小堆排序(MinHeapSort) 基本原理:對於給定的n個記錄,初始時把這些記錄看作一顆順序儲存的二叉樹,然後將其調整為一個小頂堆,然後將堆的最後一個元素與堆頂元素進行交換後,堆的最後一個元素即為最小記錄;接著講前(n-1)個元素重新調整為一個小頂堆,再將堆頂元素與當前

C語言實現八大排序演算法及其效能之間的

概述 排序是資料結構中的重要一節,也是演算法的重要組成部分。主要分為內部排序以及外部排序,今天我們講內部排序,也就是八大排序。 插入排序 直接插入排序 演算法思想 演算