一般用陣列來表示堆,下標從0開始。則下標為 i 的節點的父節點下標為(i-1)/2
,其左右子節點分別為(2i + 1)
、(2i + 2)
。
下標從1開始 左右節點2i 、 2i+1
i / 2
。
利用大頂堆(小頂堆)堆頂記錄的是最大(小)關鍵字這一特性,每次從無序陣列中選出最大(最小)值。
1、將待排序序列造成乙個最大堆,此時根節點為最大值down:把數往下沉,從而再次變成堆的操作,要考慮和兩個左右子節點比較。2、依次將根節點與待排序序列最後乙個元素交換
3、維護從根節點到該元素的前乙個節點為最大堆
up:底下的數往上走,再次變成堆的操作,只要和父節點比較就可以。
插入乙個數:heap[++size], up(size)
刪除最小值:把最後乙個元素覆蓋到堆頂,heap[1] = heap[size], size--, down(1)
刪除任意乙個元素:heap[k]=heap[size];size--;down(k);up(k)
;dwon和up只會執行乙個
修改任意元素:heap[k]=x;down();up()
時間複雜度:nlog n
堆排序:每次取出堆頂後,把最後乙個數放到堆頂,進行下沉操作,直到堆最後只剩乙個元素為止。
模板
模擬堆#include#includeusing namespace std;
const int n = 100010;
int h[n], mysize;
int n, m;
void down(int u)
}int main()
return 0;
}
維護乙個集合,初始時集合為空,支援如下幾種操作:
i x
,插入乙個數 x;
pm
,輸出當前集合中的最小值;
dm
,刪除當前集合中的最小值(資料保證此時的最小值唯一);
d k
,刪除第 k 個插入的數;
c k x
,修改第 k個插入的數,將其變為 x;
現在要進行 n次操作,對於所有第 22 個操作,輸出當前集合的最小值。
定義兩個陣列:分別是 hp 和 ph
hp-->
堆陣列中下標 -> 第k個插入
heap pointer
ph-->
第k個插入 -> 堆陣列中下標
pointer heap
這兩個函式是互為反函式的。
當在堆中交換兩個元素時,那麼第k個插入的數的下標要變化、下標對應的數是第幾個也要變化。swap操作傳入需要交換的堆陣列的下標int h[n], mysize, cnt; // cnt記錄第k次插入
int ph[n], hp[n];
// ph[k]: 第k個插入 --> 下標
// hp[k]: 下標k -->第幾個插入
// 交換堆中的兩個數,那麼下標和第幾次插入的關係也要變化
void swap_heap(int a, int b)
void down(int i)
}void up(int i)
}// 插入乙個數,在最後插入
void insert(int x)
// 刪除第k個插入數
void del(int k)
// 刪除最小值,堆頂
void del()
// 修改第k個插入的數
void change(int k, int x)
int main() else if(op == "pm") else if(op == "d") else if(op == "dm") else
}return 0;
}
堆排序 模擬堆排序
838.堆排序 輸入乙個長度為n的整數數列,從小到大輸出前m小的數。輸入格式 第一行包含整數n和m。第二行包含n個整數,表示整數數列。輸出格式 共一行,包含m個整數,表示整數數列中前m小的數。資料範圍 1 m n 1051 m n 105,1 數列中元素 1091 數列中元素 109 輸入樣例 5 ...
排序 4 堆排序
將待排序的序列構成乙個大頂堆。此時,序列的最大值就是堆頂的根結點。將它移走 就是,將其與堆陣列的末尾元素交換,此時末尾的元素就是最大值 然後將剩餘的n 1個序列重新構成乙個堆,如此反覆。其中關鍵問題 1 如何將無序序列構成乙個堆 2 輸出堆頂元素後,如何調整公升序元素為乙個堆 4.堆排序 堆調整 v...
排序二 堆排序
子結點的鍵值或索引總是小於 或者大於 它的父節點。堆通過一維陣列實現。在起始陣列為 0 的情形中 父節點i的左子節點在位置 2 i 1 父節點i的右子節點在位置 2 i 2 子節點i的父節點在位置 floor i 1 2 堆中的最大值總是位於根節點。堆中定義以下幾種操作 1 最大堆調整 max he...