堆是什麼?堆是一種特殊的完全二叉樹,就像下面這棵樹一樣:這棵樹有乙個很顯著的特點,那就是所有父結點都要比子結點要小。符合這樣要求的完全二叉樹我們成為「最小堆」。反之,如果所有父結點都要比子結點大,這樣的完全二叉樹被稱為」最大堆「。
如果我們現在要刪除掉最小的數字,並重新插入乙個數字,再從中找出最小的數字。目前只能夠先掃瞄所有的數字,找到最小的數,插入新的數字後再掃瞄所有的數字。這樣子的時間複雜復是o(n²),那麼有沒有更好的方法呢?」堆「的結構恰好能夠很好地解決了這個問題。首先將數字按照最小堆的要求放進一顆完全二叉樹,就像下面這棵樹一樣。然後用陣列h儲存這些數字。
很顯然最小的數就在堆頂,假設儲存這個堆的陣列是h,那麼最小的數字就是h[1]。接下來將堆頂的數字刪除。將新增的數字28放入堆頂。此時顯然不滿足小頂堆的特性,我們需要將新增的數字調整到合適的位置。如何調整呢?
向下調整!我們需要將這個數字與它的兩個兒子2和5比較,選擇較小的乙個和它交換,交換之後如下:
我們發現此時還是不符合最小堆的特性,因此還需要繼續向下調整。於是繼續將28與兩個兒子12和7比較,選擇較小的乙個進行交換
此時還是不滿足,繼續向下調整:
現在我們已經找到符合最小堆的特性了。綜上所述,當新增加乙個數被放到頂堆時候,如果發現不符合最小堆的特性,就必須要向下調整,直到找到合適的位置位置。使其重新符合最小堆的特性。
向下調整的**如下:
void shiftdown(int i)
else
if(i*2+1<=n) //如果有右兒子,再對右兒子進行討論
return ;
}
堆還有乙個作用就是堆排序,與快速排序一樣,堆排序的時間複雜度是o(nlogn)。堆排序的實現很簡單,比如說我們現在要進行從小到大的排序,可以先建立最小堆,然後每次刪除頂部元素並將頂部元素輸出或者放入乙個新的陣列中,直到堆為空為止。最終輸出或者存放在新陣列中的數就已經是排序好了的。
當然堆排序還有一種更好的辦法。從小到大排序的時候不建立」最小堆「而是建立」最大堆「!int deletemin() //刪除方法的堆排序
最大堆建立好之後,最大的元素是h[1],因為我們需要從小到大排序,希望最大的數放在最後,那麼我們將h[1]和h[n]交換,此時h[n]就是陣列中最大的元素。最大的元素歸位後,將堆的大小減1,n--,並將交換後的新h[1]向下調整維持特性。如此遞迴,直到堆的大小是1位置。此時陣列h已經是排好序了。
void heapsort() //交換思維的堆排序
}
#include #include #include #include #include using namespace std;
int h[1111]; //用來儲存二叉樹的陣列。
int n;//堆的大小
void swap(int x,int y)
void shiftdown(int i)
return ;
}void heapsort() //交換思維的堆排序
}int main()
n=num;
create();//建堆
heapsort();//排序
for (int i=1;i<=num;i++)
cout << endl;
return 0;
}
大頂堆 小頂堆 堆排序
堆的定義 n個元素的序列當且僅當滿足下列關係之一時,稱之為堆。大頂堆 k i k 2i 且k i k 2i 1。小頂堆 k i k 2i 且k i k 2i 1。堆序列可以理解成乙個完全二叉樹,該樹任意乙個結點的關鍵字的值都小於或等於它的孩子結點的關鍵字。例如 堆排序 若在輸出堆頂的最小值之後,使得...
Java 堆排序 大頂堆 小頂堆
引用 堆排序 heapsort 是指利用堆這種資料結構所設計的一種排序演算法。堆積是乙個近似完全二叉樹的結構,並同時滿足堆積的性質 即子結點的鍵值或索引總是小於 或者大於 它的父節點。堆排序的平均時間複雜度為 nlogn 演算法步驟 1.建立乙個堆h 0.n 1 2.把堆首 最大值 和堆尾互換 3....
排序演算法 堆排序(大頂堆 小頂堆)
堆排序的思想這裡就先不講了,以後有時間再補上,下面是分別採用大頂堆和小頂堆實現的堆排序。注意 下面例子中排序的數字是。大頂堆方式 include include using namespace std 堆調整 將nums s.m 調整為大頂堆,其中除了nums s 之外均滿足大頂堆的定義 void ...