堆數(shù)據(jù)結(jié)構(gòu)是一種數(shù)組對象,它可以被視為一棵完全二叉樹結(jié)構(gòu),所以堆也叫做二叉堆。
環(huán)縣網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),環(huán)縣網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為環(huán)縣上千多家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)公司要多少錢,請找那個售后服務(wù)好的環(huán)縣做網(wǎng)站的公司定做!二叉堆滿足二個特性:
1.父結(jié)點的鍵值總是大于或等于(小于或等于)任何一個子節(jié)點的鍵值。
2.每個結(jié)點的左子樹和右子樹都是一個二叉堆(都是大堆或最小堆)。
當(dāng)父結(jié)點的鍵值總是大于或等于任何一個子節(jié)點的鍵值時為大堆。當(dāng)父結(jié)點的鍵值總是小于或等于 任何一個子節(jié)點的鍵值時為最小堆。
大堆和最小堆是堆數(shù)據(jù)結(jié)構(gòu)的重點。堆排序中使用特別的多。
堆的存儲一般是用一個數(shù)組實現(xiàn)的,當(dāng)然也可以用鏈?zhǔn)酱鎯?,但是特別麻煩。
如下我們給出一個數(shù)組:
int* Arry={10,16,18,12,11,13,15,17,14,19};
現(xiàn)在我們要根據(jù)這個數(shù)組來建一個不是真正意義上的堆。
現(xiàn)在的堆并不是真正的堆,它不滿足大堆或者最小堆,所以它是無意義的,我們要調(diào)整這個“堆”讓它變成大堆或者最小堆,這一步操作就是調(diào)整堆。
調(diào)整堆:首先我們要明確調(diào)整堆的目的就是讓整棵樹中的雙親節(jié)點都大于孩子節(jié)點(這里以大堆為例),所以我們要從葉子結(jié)點開始調(diào)整,直到調(diào)整到根節(jié)點結(jié)束,可能調(diào)整好這棵樹后,子樹又不符合大堆規(guī)則,轉(zhuǎn)而調(diào)整子樹,所以我們把這種方式叫下調(diào)(AdjustDown)
#pragma once #include#include #include using namespace std; template struct Less { bool operator()(const T& l, const T& r) { return l < r; } }; template struct Greater { bool operator()(const T& l, const T& r) { return l > r; } }; template class Continer = Greater>//默認(rèn)為大堆 class Heap { public: Heap(){}; Heap(const T* a, size_t size, Continer con); Heap(const vector & v); void Push(const T& x); void Pop(); T& GetTop(); bool Empty(); size_t Size(); void HeapSort(T* a, size_t size); protected: void _AdjustDown(size_t parent); void _AdjustUp(size_t child); protected: vector _a; Continer _con; }; template class Continer = Less> Heap ::Heap(const T* a,size_t size ,Continer con) { _a.reserve(size); for (size_t i = 0; i < size; ++i) { _a.push_back(a[i]); } //建堆 for (int i = (_a.size() - 2) / 2; i >= 0; i--) //從第一個非葉子結(jié)點開始下調(diào),葉子結(jié)點可以看作是一個大堆或小堆 { _AdjustDown(i); } } template class Continer = Less> void Heap ::_AdjustDown(size_t parent) { size_t child = parent * 2 + 1; size_t size = _a.size(); while (child < size) { if (child + 1 < size&&_con(_a[child+1],_a[child])) //注意這必須是child+1更大或更小,所以把child+1放在前面 ++child; if (_con(_a[child],_a[parent])) { swap(_a[parent], _a[child]); parent = child; child = parent * 2 + 1; } else break; } }
在這里是使用的類去封裝堆結(jié)構(gòu),并且用了仿函數(shù)的方式去復(fù)用大堆和最小堆的代碼。在這里默認(rèn)把堆調(diào)整為大堆。
以下是堆的調(diào)用:
int array[] = { 10, 16, 18, 12, 11, 13, 15, 17, 14, 19 }; size_t size = sizeof(array) / sizeof(int); Greaterger; Heap h(array, size, ger);//因為默認(rèn)為大頂堆,所以可以省略Greater
我們的調(diào)整堆的操作是從二叉樹的第一個非葉子結(jié)點開始調(diào)整。有的讀者會問為什么不從最后一個結(jié)點調(diào)整呢?因為所有葉子結(jié)點我們都可以看作一個大堆或者最小堆,我們完全不需要去調(diào)整。
要調(diào)整為一個最小堆的話只要修改一下調(diào)用即可:
int array[] = { 10, 16, 18, 12, 11, 13, 15, 17, 14, 19 }; size_t size = sizeof(array) / sizeof(int); Lessles; Heap h2(array, size, les);
向一個大堆(最小堆中插入一個數(shù)據(jù)),讓堆仍為大堆(最小堆)。
Push操作:向堆中插入一個數(shù)據(jù),也就是往數(shù)組中插入一個數(shù)據(jù),插入數(shù)據(jù)以后一般都不是大堆(最小堆),我們得去調(diào)整。
上調(diào)(AdjustUP):把新插入的結(jié)點大于(小于)雙親節(jié)點則往上調(diào),直到滿足大堆(最小堆)。
templateclass Continer = Less> void Heap ::Push(const T& x) { _a.push_back(x); _AdjustUp(_a.size() - 1); } template class Continer = Less> void Heap ::_AdjustUp(size_t child) { size_t parent = (child - 1) / 2; while (child > 0) { if (_con(_a[child] , _a[parent])) { swap(_a[child], _a[parent]); child = parent; parent = (child - 1) / 2; } else break; } }
刪除大堆(最小堆)中的根結(jié)點。
我們把根節(jié)點刪除以后剩下的結(jié)點就不構(gòu)成一棵樹結(jié)構(gòu)了,所以我們可以換一種思路讓堆保持原來的結(jié)構(gòu)。
方法就是把根節(jié)點和最后一個結(jié)點交換,刪除最后一個結(jié)點,這樣就不會破環(huán)結(jié)構(gòu)了。
把結(jié)點刪除后,堆肯定不滿足大堆(最小堆)了,所以我們還要調(diào)整堆。這次我們要從根節(jié)點往葉子結(jié)點調(diào),這樣很快,因為原來的堆根節(jié)點的左右子樹都已經(jīng)滿足大小堆了。利用下調(diào)來調(diào)整:
templateclass Continer = Less> void Heap ::Pop() { assert(!_a.empty()); size_t size = _a.size(); swap(_a[0], _a[size - 1]); _a.pop_back(); _AdjustDown(0); }
堆和棧是計算機(jī)內(nèi)存最常用的結(jié)構(gòu)。
有了大堆和最小堆,我們可以利用他們的特性來實現(xiàn)堆排序。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。