一、定义:
所有的父节点都小于子节点的完全二叉树。叫做小根堆。
二、性质:
- 节点个数为N的小根堆,其高度为logN。
- N/2之后的节点都是叶子结点。
- 第i个节点的左儿子的序号是ix2,右儿子的序号是ix2+1,父亲节点的序号为i/2
三、如何存储?
用一维数组存储。申请一个长度为N+1的数组,
四、建堆的两种方式:
- 直接用一个数组存储数,然后,从后往前依次调整数的位置,使以当前位置为根的二叉树为小根堆直到数组的第一个数。
- 插入法,依次读入每个数,把它插入小根堆,并调整位置,使插入数后二叉树继续保持为小根堆
方式一代码 文末代码中create1方法
方式二代码 文末代码中create2方法
五、排序时间复杂度为 NlogN
文末代码中heapSort方法
六、从堆顶删除一个数?
文末代码中deleteMin方法
七、增加一个数?
文末代码中addOneNum方法
class SmallPriorityQueue {
vector<int> h;
int N;
public:
SmallPriorityQueue(vector<int> & arr, int K) {
N = K;
h = arr;
h.insert(h.begin(), 0);
}
void create1() {
for(int i = N/2;i >= 1;i--) {
shiftDown(i);
}
}
void create2() {
for(int i = 1;i <= N;i++) {
shiftUp(i);
}
}
int deleteMin() {
int tmp = h[1];
h[1] = h[N];
N--;
shiftDown(1);
return tmp;
}
void addOneNum(int num) {
N++;
h.emplace_back(num);
shiftUp(N);
}
vector<int> heapSort() {
create1();
vector<int> ans;
while (N != 0) {
int min = deleteMin();
ans.emplace_back(min);
}
return ans;
}
void shiftDown(int i) {
int t = 0;
while (i * 2 <= N) {
if (h[i*2] < h[i]) {
t = i*2;
}
else {
t = i;
}
if (i*2+1 <= N) {
if (h[i*2+1] < h[t]) {
t = i*2+1;
}
}
if (t != i) {
swap(t, i);
i = t;
}
else {
break;
}
}
}
void shiftUp(int i) {
if (i == 1) {
return;
}
while (i != 1) {
if (h[i/2] > h[i]) {
swap(i/2, i);
i /= 2;
}
else {
break;
}
}
}
void swap(int x, int y) {
int tmp = h[x];
h[x] = h[y];
h[y] = tmp;
}
};