堆,是一種類似於二叉樹的結構,或者說就是二叉樹的一種。堆的每乙個結點都有乙個數值,並且有這樣的性質:根節點比要比兩個孩子節點都要大(至少也是相等),這樣的堆叫做大頂堆,同樣也有小頂堆的概念。
首先宣告,我們不需要創造乙個二叉樹來儲存函式傳遞過來的陣列資訊,因為陣列本身就可以構成乙個二叉樹,而且是完全二叉樹。之前的關於陣列儲存二叉樹的文章
然後,我們需要整理這個陣列使其成為乙個大頂堆。
(這裡是以大頂堆為例,小頂堆同理)
遍歷二叉樹的每乙個結點,對於非葉子節點,將左孩子、右孩子(如果有的話)和根節點拿出來,選擇最大的乙個作為根節點。當遍歷結束後,整個樹也就是乙個大頂堆了。
我們還知道,給出的陣列下標就是層次遍歷二叉樹的結果,所以我們不需要什麼先序中序的。
另外,也是最重要的一部分,那就是我們整理的過程一定是從下到上的,因為一旦有大的資料在很下面,開始就整理根節點是不能實現大頂堆的。
for i<
-a.length/
2 downto 1
對每乙個結點進行交換操作。
那和排序用有什麼關係呢?至少我們知道二叉搜尋樹還是左孩子小於根節點小於右孩子的,直接遍歷就行,那麼如何來用堆排序呢?
我們的大頂堆的根節點已經有了,而且是降序的第一位,所以我們只需要將這個結點拿出來,然後對剩下的樹整理、取數……直到樹為空。
有乙個細節上的就是我看到的官方教程都是i從a.length到2,建立堆之後將a[1]和a[i]進行交換,然後重新構造最小堆,但是本人的想法是將最大的直接放在那,然後從第二個開始接著做成樹,繼續處理(貌似都差不多其實)
**:
void
exchange
(int a,
int i,
int length)
}elseif(
2*i+
2< length)
else
if(temp_place!=i)
exchange
(a,temp_place,length);}
}}void
build
(int a,
int length)
//構建大頂堆
}void
heap
(int a,
int length)
}
exchange函式中的引數是防止在尋找過程中發生了下標越界。
在這個函式中最懵的可能就是那個對交換後的位置繼續呼叫交換函式了,示例:
在交換了4和9之後,很明顯47不符合大頂堆的定義,所以我們還是需要交換的,這時應該交換的就是4(根節點)被交換到的位置。
在每一次取元素之後,只有堆頂是經過交換的,所以我們只需要處理一下頂端即可,不需要對整體進行構建。
堆排序的本質還是構建二叉樹來處理,也屬於基於比較、交換的方式排序。
首先,我們要知道exchange函式就是在把一棵二叉樹從指定結點一直走到乙個葉子,所以時間複雜度為o(logn),其中build函式呼叫了n/2次,接下來的迴圈又是n-1次,所以整體的時間複雜度還是o(logn),也就是比較類排序的極限了。
堆排序中第一步整理堆的代價是o(n)
排序演算法 堆排序
1 什麼是堆 首先它是一顆完全二叉樹,並且父結點的值大於子節點的值 最大堆 或父結點的值小於子結點的值 最小堆 小根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最小者的堆稱為小根堆,又稱最小堆。大根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最大者,稱為大根堆,又稱最大堆。2 堆...
排序演算法 堆排序
花了一晚上時間研究堆排序,這個排序困擾了哥很久,終於搞清楚了。一 堆的定義 1.父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值 2 每個結點的左子樹和右子樹都是乙個二叉堆 都是最大堆或最小堆 二 已知結點 i 則它的子結點 為2 i 1 與 2 i 2 父節點為 i 1 2 三 堆排序...
排序演算法 堆排序
由於不經常使用,之前學習看過的演算法都給忘了。現在把他們寫下來,記錄下來,以方便以後查閱。本篇文章的 即為堆排序的 主函式中是對輸入檔案中的序列進行排序,並將結果輸出到乙個檔案中。這是一種形式類似於google codejam的測試方法。include include using namespace...