一文讀懂堆排序

2021-02-18 算法愛好者
(點擊上方公眾號,可快速關注)

轉自:劉毅

https://61mon.com/index.php/archives/202/

好文投稿, 請點擊 → 這裡了解詳情

堆排序是利用堆的性質進行的一種選擇排序。下面先討論一下堆。

堆實際上是一棵完全二叉樹,其滿足性質:任何一結點大於等於或者小於等於其左右子樹結點。

堆分為大頂堆和小頂堆,滿足 「任何一結點大於等於其左右子樹結點」 的稱為大頂堆,滿足 「任何一結點小於等於其左右子樹結點」 的稱為小頂堆。

由上述性質可知:大頂堆的堆頂肯定是最大的,小頂堆的堆頂是最小的。

下面舉個例子(資源來自堆排序 - 海子)來說明堆排序的過程(以升序為例):

給定整型數組:{16, 7, 3, 20, 17, 8},根據該數組 「構建」 完全二叉樹(並不是真的寫代碼去構建,只是把數組看成完全二叉樹去操作)。

程序從最後一個非葉子結點開始,即 3。判斷其左右孩子:8,8 比 3 大,把 8 調整上去。

3 結點下無孩子,判斷結束。

繼續往前一步,至 7 結點,判斷其左右孩子:20 和 17,20 是最大的,將其調整上去。

7 結點下無孩子,判斷結束。

繼續往前一步,至 16 結點,判斷其左右孩子:20 和 8,20 是最大的,將其調整上去。

判斷 16 結點下左右孩子:7 和 17,17 是最大的,將其調整上去。

16 結點下無孩子,判斷結束。

遍歷已至頭部,結束。

至此數組已經滿足大頂堆的性質,接下來的操作就很簡單了。

看完上面所述的流程你至少有兩個疑問:

1、如何確定最後一個非葉子結點?

其實這是有一個公式的,設二叉樹結點總數為 n,則最後一個非葉子結點是第 ⌊n2⌋ 個。

2、數組當中如何確定當前結點的左右孩子位置?

設當前結點下標是 i,則其左孩子的下標是 2i,右孩子的下標是 2i+1。請注意:這是建立在數組下標從 1 開始的情況。若數組下標從 0 開始,則其左右孩子下標還各需多加一個 1。

以下代碼默認數組下標從 1 開始,請讀者注意。

/* 已知 array[left]...array[right] 的值除 array[left] 之外均滿足堆的定義,

本函數調整 array[left],使 array[left]...array[right] 成一個大頂堆 */

void HeapAdjust(int array[], int left, int right)

{

    int index = left;

  

    for (int i = left * 2; i <= right; i = i * 2)

    {

        if (i < right && array[i] < array[i + 1])  // 找到孩子中較大者

            i++;

        if (array[index] > array[i])

            return;

        swap(array[index], array[i]);

        index = i;

    }

}

void HeapSort(int array[], int left, int right)

{

    int len = right - left + 1;

  

    for (int i = len / 2; i >= left; i--)  // 把數組調整成大頂堆

        HeapAdjust(array, i, right);

  

    for (int i = right; i > left; i--)     // 排序

    {

        swap(array[left], array[i]);

        HeapAdjust(array, left, i - 1);

    }

}

時間複雜度為 O(nlogn),證明如下。

首先計算建堆的時間,也就是下面的代碼,

for (int i = len / 2; i >= left; i--)  // 把數組調整成大頂堆

    HeapAdjust(array, i, right);

接下來就是排序的時間,即下面的代碼:

for (int i = right; i > left; i--)  // 排序

{

    swap(array[left], array[i]);

    HeapAdjust(array, left, i - 1);

}

HeapAdjust( ) 耗時 logn,共 n 次,故排序時間為 O(nlogn)。

綜上所述,堆排序時間複雜度為 T(n)=O(n)+O(nlogn)=O(nlogn)。

覺得本文有幫助?請分享給更多人

關注「算法愛好者」,修煉編程內功

淘口令:複製以下紅色內容,再打開手淘即可購買

範品社,使用¥極客T恤¥搶先預覽(長按複製整段文案,打開手機淘寶即可進入活動內容)

相關焦點

  • 詳解堆排序
    (點擊上方公眾號,可快速關注)轉自:靜默虛空http://www.cnblogs.com/jingmoxukong/p/4303826.html好文投稿
  • 快速排序和堆排序
    龜哥今天和大家分享下快速排序,堆排序算法。首先快速排序的思想,給定一個無序的數組,首先用兩個指針left和right分別指向數組的頭部和尾部,將數組的第一個元素array[0]作為和left,right指針比較的元素。
  • 堆排序就這麼簡單
    一、堆排序介紹來源百度百科:堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序算法,它是選擇排序的一種。可以利用數組的特點快速定位指定索引的元素。堆分為大根堆和小根堆,是完全二叉樹。前面我已經有二叉樹入門的文章了,當時講解的是二叉查找樹,那上面所說的完全二叉樹是怎麼樣的一種二叉樹呢??
  • 一文帶你讀懂排序算法(三):堆排序算法
    完全二叉樹一棵深度為k的有n個結點的二叉樹,對樹中的結點按從上至下、從左到右的順序進行編號,如果編號為i(1≤i≤n)的結點與滿二叉樹中編號為i的結點在二叉樹中的位置相同,則這棵二叉樹稱為完全二叉樹。完全二叉樹的一個「優秀」的性質是,除了最底層之外,每一層都是滿的,這使得堆可以利用數組來表示(普通的一般的二叉樹通常用鍊表作為基本容器表示),每一個結點對應數組中的一個元素。
  • 堆排序與拓撲排序(Java模板)
    1.堆排序思想(1) 以升序排序為例,我們需要構建一個小根堆。第一種方法:用數組模擬小根堆。忘記了的朋友可以看看之前的文章《堆模板(Java)》認真複習一下~第二種方法:使用 java.util.PriorityQueue ,相當於一個堆結構。
  • 堆排序算法
    堆是一種數據結構,一種叫做完全二叉樹的數據結構。堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆;或者每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆。大頂堆:a[i] >=a[2i+1] && ar[i] >= a[2i+2] 小頂堆:a[i] <= a[2i+1] && a[i] <= a[2i+2] 堆排序的基本思想:
  • 第二篇,選擇排序算法:簡單選擇排序、堆排序
    此為第二篇,選擇排序算法:簡單選擇排序、堆排序。
  • 動畫 | 什麼是堆排序?
    而堆排序因為二叉堆的性質,堆頂就是最大的元素,查找次數只有一次,但是將無序轉成有序中間還需要一個預處理過程:構造堆有序。 堆有序並不代表數組有序,堆有序是滿足 二叉堆 性質的: 1.父節點的鍵值總是優先於任何一個子節點的鍵值; 2.左右子樹都是一個二叉堆。
  • 圖解:什麼是堆排序?
    堆排序 要學習今天的堆排序(Heap Sort),我們以一個數組  arr = [5、1、4、2、8、4] 開始(這個數組我們之前講排序算法常用的):我們首先以這個數組建立一個大頂堆,插入結點 5 作為根結點
  • 優先級隊列與堆排序
    本文首先介紹優先級隊列的定義,有序和無序數組以及堆數據結構實現優先級隊列,最後介紹了基於優先級隊列的堆排序(Heap Sort)一 定義優先級隊列和通常的棧和隊列一樣,只不過裡面的每一個元素都有一個」優先級」,在處理的時候,首先處理優先級最高的。如果兩個元素具有相同的優先級,則按照他們插入到隊列中的先後順序處理。
  • 堆排序原理及實現
    小白們也很熟悉的:冒泡,歸併,簡單選擇,歸併,堆排序。那它們區別是什麼呢?需要好好梳理一下了。今天咱們就先瞅瞅感覺比較抽象的堆算法吧。什麼是堆?堆是具有下列性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆;或者每個結點的值都小於或等於其左右子結點的值,稱為小頂堆。
  • 到底什麼是堆排序 PHP
    每個節點的值都大於等於子樹中每個節點值的堆叫最大堆,反之為最小堆。堆排序的時間複雜度為O(nlogn)。堆是一種特殊的二叉樹,它滿足以下兩點:1. 堆是一個完全二叉樹2. 堆中每個節點都必須大於等於(或小於等於) 其子樹的每個節點
  • 獨家 | 一文讀懂Hadoop(三):Mapreduce
    讀者可以通過閱讀「一文讀懂Hadoop」系列文章,對Hadoop技術有個全面的了解,它涵蓋了Hadoop官網的所有知識點,並且通俗易懂,英文不好的讀者完全可以通過閱讀此篇文章了解Hadoop。本期獨家內容「一文讀懂Hadoop」系列文章先介紹Hadoop,繼而分別詳細介紹HDFS、MAPREDUCE、YARN的所有知識點,分為四期內容在近幾天推送。敬請關注後續內容。
  • 八十四、堆排序解決TopK問題
    「@Author:Runsen」上次介紹了堆排序,這次介紹堆排序常見的應用場景TopK問題。利用堆求TopK問題TopK問題是一個堆排序典型的應用場景。至於為什麼TopK問題最佳的答案是堆排序?其實在空間和時間的複雜度來考量,雖說快排是最好的排序算法,但是對於100億個元素從大到小排序,然後輸出前 K 個元素值。可是,無論我們掌握的是快速排序算法還是堆排序算法,在排序的時候,都需要將全部的元素讀入到內存中。
  • 堆排序算法C語言詳解
    在學習堆排序之前,首先需要了解堆的含義:在含有 n 個元素的序列中,如果序列中的元素滿足下面其中一種關係時,此序列可以稱之為堆。
  • ...選擇,插入,希爾,歸併,快排,堆排序,計數排序,桶排序,基數排序)
    一、前言傳統的計算機算法和數據結構領域,都是基於java或者c/c++等。沒用javascript實現過或是沒仔細看過相關算法的原理,導致寫起來浪費很多時間。對於一個前端來說,尤其是筆試面試的時候,算法方面考的其實不難(十大排序算法或是和十大排序算法同等難度的)。
  • 一文讀懂電容傳感器
    藍色標題,獲取文章】 10、一文讀懂光纖傳感器 11、一文讀懂溫溼度傳感器 12
  • 獨家 | 一文讀懂Adaboost
    【集成學習】系列往期回顧:獨家 | 一文讀懂集成學習(附學習資源) 參考資料:1. 李航.《統計學習方法》2. 周志華.《機器學習》3. 曹瑩,苗啟廣,劉家辰,高琳. AdaBoost 算法研究進展與展望.
  • 一文讀懂磁傳感器(必須收藏)
    【點擊藍色標題,獲取文章】 >、一文讀懂接近傳感器 3、一文讀懂磁傳感器 4、一文讀懂流量傳感器
  • 一文讀懂「2020限塑令」!
    一文讀懂「2020限塑令」!06 16:58 來源:澎湃新聞·澎湃號·政務 一張圖讀懂限塑令新規