arraylist從大到小排序 快速入門堆排序

2021-10-11 05:56:28 字數 2377 閱讀 7995

堆排序是一種原地、時間複雜度

首先堆是一種樹,一種滿足以下特質的樹結構:

接下來看看同一組資料的不同堆的形態:

對於乙個adt,我們需要知道它有哪些操作方法、以及資料儲存的方式。

儲存乙個完全二叉樹,最適合使用陣列,因為它相比鍊錶不需要儲存左、右子樹的指標,更加節省記憶體空間,通過陣列索引即可以隨機訪問到對應元素。

【陣列第乙個位置留空,方便計算】

假設你知道某個節點下標為

當我們往堆裡面插入乙個元素後,我們需要對新的堆進行調整,使其能夠滿足上述的兩個特性,那麼這個過程我們稱為堆化。

堆化實際上有兩個操作,乙個是從下往上、乙個是從上往下。

從下往上堆化就是指把該元素與其父節點對比、滿足條件後交換位置、繼續對比、交換,直到不能交換了。

我們都知道大頂堆、小頂堆的堆頂位置儲存的分別是最大值、最小值。

假設我們構造的是乙個大頂堆,當我們刪除堆頂元素後,我們需要把之前堆內第二大元素移到堆頂位置,依次類推,我們依次刪除第二大節點、第三大節點、直到葉子節點。

上面的思路其實就是:當我們刪除堆頂元素時候,直接把最後乙個節點放到堆頂位置,然後從上往下進行堆化。如果父節點的值小於其子節點的值,則進行交換、繼續往下對比。

接下來我們分析下堆的插入元素操作【從下往上堆化】、刪除堆頂元素操作【從上往下堆化】的時間複雜度:

由於乙個完全二叉樹的高度不會超過

堆排序如此優秀,那麼它是如何做到的呢?其過程包括兩點:建堆、排序。

我們把無序陣列構建成乙個二叉堆:

如果你需要對無序陣列進行從小到大排序,那麼你應該構建為大頂堆;

如果你需要對無序陣列進行從大到小排序,那麼你應該構建為小頂堆。

假設我們對無序陣列[4, 4, 6, 5, 3, 2, 8, 1]進行公升序排序。

當建堆結束後,會得到這樣乙個大頂堆。

8

/

5 6

/ /

4 3 2 4/1

分析堆化操作時間複雜度:我們可以畫出每一層完全二叉樹的高度以及該層的節點個數【這裡去除了葉子節點】

每個節點堆化的過程中,它需要對比、互動的次數與這個節點所在高度成正比,因此我們只需要計算出每個節點所在高度之和就是時間複雜度了。

建堆結束之後,陣列中的資料已經是按照大頂堆的特性來組織的。

陣列中的第乙個元素就是堆頂,也就是最大的元素。我們把它跟最後乙個元素交換,那最大元素就放到了下標為 n 的位置。這個過程有點類似上面講的「刪除堆頂元素」的操作,當堆頂元素移除之後,我們把下標為 n 的元素放到堆頂,然後再通過堆化的方法,將剩下的 n−1 個元素重新構建成堆。

堆化完成之後,我們再取堆頂的元素,放到下標是 n−1 的位置,一直重複這個過程,直到最後堆中只剩下標為 1 的乙個元素,排序工作就完成了。

/**
整個堆排序的過程,都只需要極個別臨時儲存空間,所以堆排序是原地排序演算法。堆排序包括建堆和排序兩個操作,建堆過程的時間複雜度是 o(n),排序過程的時間複雜度是 o(nlogn),所以,堆排序整體的時間複雜度是 o(nlogn)。

堆排序不是穩定的排序演算法,因為在排序的過程,存在將堆的最後乙個節點跟堆頂節點互換的操作,所以就有可能改變值相同資料的原始相對順序。

對於同樣的資料,堆排序對於資料的交換次數要多於快排,因為堆排序第一步是建堆,這個過程會打亂資料的有序度。

記錄冒泡演算法,從大到小排序(C語言)

學了些c語言,記錄下學習過程,通過乙個常見的面試題來複習下c語言的使用 氣泡排序 上 輸入 排序中.輸出k 運算次數 include define n 5 void swap int fst,int scd 交換兩個數的函式,在不引入第三個變數的情況下實現功能 void swap int a,int...

排序入門練習題2 從大到小排序 題解

題目出處 資訊學奧賽一本通 例2.1 題目描述 輸入 n 個數,將 n 個數按從大到小的順序輸出 n le 10000 輸入格式 輸入的第一行包含乙個整數 n le 10000 用於表示元素個數。接下來一行包含 n 個int範圍內的整數。輸出格式 輸出佔一行,用於表示 n 個整數從小到大排的結果,兩...

多種方法實現陣列元素從大到小排序 氣泡排序

實現陣列由大到小排列 實現一 陣列 最小數冒泡到最右邊 int sort int a,int n int main bubble sort p for i 0 i 10 i printf n 接下來詳細介紹下氣泡排序,詳細參考 假如我們得到一堆數 10 1 35 61 89 36 55 這些數字都放...