二叉堆_完全二叉树_优先队列

本文介绍了完全二叉树的数据结构特点及其数组存储方式,并详细解释了如何通过数组访问父节点、左子节点及右子节点。此外,还探讨了二叉堆的概念,包括最大堆与最小堆的性质,并提供了将普通数组转换为最大堆和最小堆的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

完全二叉树的逻辑结构是树结构, 但由于其特殊性, 数据结构中常用数组来存储.

访问父节点, 左子结点, 右子节点都很方便

数组存储以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
*/ 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值