堆原理简介
堆是一种特殊的树结构,即完全二叉树。堆分为大顶堆和小顶堆,大顶堆为根节点的值大于两个子节点的值;小顶堆为根节点的值小于两个子节点的值,同时根节点的两个子树也分别是一个堆。
通俗来讲,二叉树在按层序遍历时在遇到第一个 nullptr 指针即作为结尾的二叉树
就可以称之为完全二叉树。
假设根节点下标为 0,若父节点相应数组下标为 i,则其左孩子相应数组下标为 2i+1,右孩子为 2i+2。
注意:如果我们现在处理第 i 个序号的结点的数,那么他的父结点序号就是 (i-1)/2;它的孩子结点就为 2i+1 与 2i+2,反推 2i+1-1 和 2i+2-1 除以 2 可以得到 i。当前 n 个节点的堆,根节点从 0 开始,则最后一个叶节点的下标为 n-1,其父节点是第一个非叶节点,下标为 ((n-1)-1)/2 = n/2-1。
程序代码
自定义实现 priority_queue——用 vector、堆实现 code c++
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <vector>
using namespace std;
class IQueue { // 实现 priority_queue, 接口定义
public :
virtual void push(int) = 0;
virtual void pop() = 0;
virtual bool empty() = 0;
virtual int top() = 0;
virtual int size() = 0;
};
class vector_queue : public IQueue, public vector<int> { // 用 vector 实现
public :
void push(int x) override {
this->vector<int>::push_back(x);
return ;
}
void pop() override {
if (this->vector<int>::empty()) return ;
vector<int>::iterator p = this->begin();
for (auto iter = begin(); iter != end(); ++iter) {
if (*iter > *p) p = iter;
}
this->vector<int>::erase(p);
return ;
}
bool empty() override {
return this->size() == 0;
}
int top() override {
if (this->empty()) return 0;
int ans = at(0);
for (int i = 1; i < size(); ++i) {
ans = max(at(i), ans);
}
return ans;
}
int size() override {
return this->vector<int>::size();
}
};
class heap_queue : public IQueue, public vector<int> { // 用堆实现
public :
void push(int x) override {
push_back(x);
up_maintain(size());
return ;
}
void pop() override {
std::swap(at(0), at(size() - 1));
pop_back();
down_maintain(1);
return ;
}
bool empty() override {
return size() == 0;
}
int top() override {
if (empty()) return 0;
return at(0);
}
int size() override {
return this->vector<int>::size();
}
private:
void up_maintain(int ind) {
while (ind > 1 && at(ind - 1) > at((ind / 2) - 1)) {
std::swap(at(ind - 1), at((ind / 2) - 1));
ind /= 2;
}
return ;
}
void down_maintain(int ind) {
int temp = ind;
while (ind * 2 <= size()) {
int temp = ind;
if (at(ind * 2 - 1) > at(temp - 1)) temp = ind * 2;
if (ind * 2 + 1 <= size() && at(ind * 2) > at(temp - 1)) temp = ind * 2 + 1;
if (temp == ind) break;
std::swap(at(temp - 1), at(ind - 1));
ind = temp;
}
return ;
}
};
void quick_sort(int *arr, int l, int r) { // 快排
if (l >= r) return ;
int x = l, y = r, z = arr[(l + r) >> 1];
do {
while (arr[x] < z) ++x;
while (arr[y] > z) --y;
if (x <= y) {
swap(arr[x], arr[y]);
++x, --y;
}
} while (x <= y);
quick_sort(arr, x, r);
quick_sort(arr, l, y);
return ;
}
int main() {
// 快排测试
int arr[10] = {1, 5, 9, 6, 8, 7, 4, 3, 2, 13};
quick_sort(arr, 0, 9);
for (int i = 0; i < 10; ++i) {
cout << arr[i] << " ";
}
cout << endl;
// 自定义 priority_queue 测试
srand(time(0));
vector_queue q1;
heap_queue q2;
for (int i = 0; i < 10; ++i) {
int val = rand() % 100;
q1.push(val);
cout << "push q1 : " << val << endl;
}
while (!q1.empty()) {
cout << q1.top() << " ";
q1.pop();
}
cout << endl;
for (int i = 0; i < 10; ++i) {
int val = rand() % 100;
q2.push(val);
cout << "push q2 : " << val << endl;
}
while (!q2.empty()) {
cout << q2.top() << " ";
q2.pop();
}
cout << endl;
return 0;
}
运行结果
1 2 3 4 5 6 7 8 9 13
push q1 : 13
push q1 : 17
push q1 : 83
push q1 : 36
push q1 : 60
push q1 : 11
push q1 : 58
push q1 : 38
push q1 : 11
push q1 : 17
83 60 58 38 36 17 17 13 11 11
push q2 : 35
push q2 : 94
push q2 : 98
push q2 : 60
push q2 : 59
push q2 : 21
push q2 : 98
push q2 : 72
push q2 : 18
push q2 : 16
98 98 94 72 60 59 35 21 18 16
结论
代码示例,有问题留言。