完全二叉树的逻辑结构是树结构, 但由于其特殊性, 数据结构中常用数组来存储.
访问父节点, 左子结点, 右子节点都很方便
数组存储以1为起点
假设有某一结点u
A[u/2]为其父节点, 当且仅当u>1
A[u* 2]为其左子结点, 当且仅当u*2 <= n
A[u* 2 +1]为其右子节点, 当且仅当u*2+1 <= n
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
int *q = new int [n+1];
q[0] = -1;
for(int i = 1; i <= n; ++i) {
cin >> q[i];
}
for(int i = 1; i <= n; ++i) {
cout << "node " << i << ':' << "key:" << q[i] << '\n';
cout << "parent:" << q[i/2] << ' ';
if(2*i <= n) cout << "left son:" << q[i*2] << ' ';
if(2*i+1 <= n) cout << "right son:" << q[i*2+1];
cout << endl << endl;
}
}
/*
5
7 8 1 2 3
*/
二叉堆以完全二叉树的结构表示
最大堆性质: 结点的键值小于等于其父节点的键值
最小堆性质: 结点的键值大于等于其父节点的键值
满足最大堆性质的二叉堆称为最大堆
同理最小堆
下面代码将一个普通数组按最大堆性质更新
/*
建立一个最大堆
*/
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 1<<30
int n;
void getChange(int *dui, int i)
{
int l = 2*i, r = l+1, large = i;
if(l <= n && dui[l] > dui[large]) large = l;
if(r <= n && dui[r] > dui[large]) large = r;
if(large != i) {
swap(dui[i], dui[large]);
getChange(dui, large);
}
}
int main()
{
cin >> n;
int *dui = new int [n+1];
for(int i = 1; i <= n; ++i)
cin >> dui[i]; //输入一个混乱的堆
for(int i = n/2; i >= 1; --i)
getChange(dui,i);
for(int i = 1; i <= n; ++i) {
cout << dui[i] << ' ';
}
}
/*
5
7 8 1 2 3
*/
以下代码建立一个具有最小堆性质的优先级队列
/*
建立一个最小堆, 获得以小为优先级的优先级队列
*/
#include <iostream>
#include <algorithm>
using namespace std;
int n;
void getChange(int *p, int i)
{
int l = i*2, r = i*2+1, mm = i;
if(l <= n && p[l] < p[mm]) mm = l;
if(r <= n && p[r] < p[mm]) mm = r;
if(mm != i) {
swap(p[mm], p[i]);
getChange(p, mm);
}
}
int pop(int *p)
{
int m = p[1];
p[1] = p[n--];
getChange(p, 1);
return m;
}
int main()
{
cin >> n;
int *priQueue = new int [n+1];
for(int i = 1; i <= n; ++i)
cin >> priQueue[i];
for(int i = n/2; i >= 1; --i)
getChange(priQueue, i);
for(int i = 1; i <= n; ++i) {
cout << priQueue[i] << ' ';
}
for(int i = n; i >= 1; --i) {
cout << "\n已弹出!\n";
cout << "弹出值为:" << pop(priQueue) << '\n' << '\n';
}
}
/*
5
7 8 1 2 3
*/
下面代码是从无到有建立一个优先级队列, 由插入操作, 弹出优先级最大操作
/*
从无到有地建立最大堆优先队列
*/
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX (1<<16)
int n = 0, que[MAX+1];
void Change(int u)
{
int l = u*2, r = u*2+1, large = u;
if(l <= n && que[large] < que[l]) large = l;
if(r <= n && que[large] < que[r]) large = r;
if(large != u) {
swap(que[large], que[u]);
Change(large);
}
}
int pop()
{
int m = que[1];
que[1] = que[n--];
Change(1);
return m;
}
void insert(int x)
{
que[++n] = x;
int u = n;
while(u > 1 && que[u/2] < que[u]) { //向上调整
swap(que[u], que[u/2]);
u /= 2;
}
}
int main()
{
int x;
string str;
while(1) {
cin >> str;
if(str == "end") break;
if(str == "insert") {
cin >> x;
insert(x);
} else if(str == "extract") {
cout << "弹出:" << pop() << endl << endl;
}
}
}
/*
insert 8
insert 2
extract
insert 10
extract
insert 11
extract
extract
end
*/