优先队列存储自定义类型对象的指针

一开始我想用优先队列来实现构造哈夫曼树,并以指针方式存储每个结点的左右儿子的地址
很自然的想到如下的代码

#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

const int MAX_N = 500;

struct node {
    int v;
    node *le, *ri;
    node(int _v) : v(_v) { le = NULL, ri = NULL; }
    node(const node& x) { v = x.v, le = x.le, ri = x.ri; }
    bool operator < (const node& x) const {
        return v > x.v;
    }
};

priority_queue<node> q;

void dfs(node *cur, int& ans, int lev) {
    if ((!cur->le) && (!cur->ri)) {
        ans += cur->v * lev;
        return;
    }
    if (cur->le)
        dfs(cur->le, ans, lev + 1);
    if (cur->ri)
        dfs(cur->ri, ans, lev + 1);
}

int main() {

    int n, ans = 0;
    cin >> n;

    node *root = NULL, *newnode = NULL;
    while (n--) {
        int tmp;
        cin >> tmp;
        newnode = new node(tmp);
        q.push(*newnode);
    }

    while (q.size() > 1) {
        node a = q.top();
        q.pop();
        node b = q.top();
        q.pop();
        newnode = new node(a.v + b.v);
        newnode->le = &a;
        newnode->ri = &b;
        q.push(*newnode);
        root = newnode;
    }

    q.pop();

    dfs(root, ans, 0);

    cout << ans << endl;

    return 0;
}

结果发现 \(RE\) 了,树的父子关系根本没有得到有效的保存
调试与思考了很久以后发现,这是因为STL 容器中存放的元素是拷贝而不是引用

对于内建类型(int float char等),容器的工作方式是纯粹的位拷贝。
而当你向容器中添加一个自定义的对象(比如通过insert或push_back等),进入容器的是你指定的对象的拷贝。容器中存放的对象不是你给它们的那个对象,因为两个对象在内存中的位置不一样。
此外,当你从容器中获取一个对象时,你所得到的对象也不是容器里的那个对象。取而代之的是容器中对象的拷贝。
拷进去,拷出来。拷贝是STL的方式。

那么为了解决这个问题,我们可以将对象的引用或者指针传入容器。而容器是不支持容纳对象的引用的
因此我们采用传入对象的指针来解决这个问题,同时需要自定义优先队列中的比较器
一般采取传入函数对象的方式,可以参考这个博客
那么改正后的代码如下:

#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

const int MAX_N = 500;

struct node {
    int v;
    node *le, *ri;
    node(int _v) : v(_v) { le = NULL, ri = NULL; }
    node(const node& x) { v = x.v, le = x.le, ri = x.ri; }
};

struct cmp {   // 函数指针类型比较器
    bool operator()(const node* a, const node* b) const {
        return a->v > b->v;
    }
};

priority_queue<node*, vector<node*>, cmp > q;

void dfs(node *cur, int& ans, int lev) {
    if ((!cur->le) && (!cur->ri)) {
        ans += cur->v * lev;
        return;
    }
    if (cur->le)
        dfs(cur->le, ans, lev + 1);
    if (cur->ri)
        dfs(cur->ri, ans, lev + 1);
}

int main() {

    int n, ans = 0;
    cin >> n;

    node *root = NULL, *newnode = NULL;
    while (n--) {
        int tmp;
        cin >> tmp;
        newnode = new node(tmp);
        q.push(newnode);
    }

    while (q.size() > 1) {
        node* a = q.top();
        q.pop();
        node* b = q.top();
        q.pop();
        newnode = new node(a->v + b->v);
        newnode->le = a;
        newnode->ri = b;
        q.push(newnode);
        root = newnode;
    }

    q.pop();

    dfs(root, ans, 0);

    cout << ans << endl;

    return 0;
}
posted @ 2022-05-28 11:29  四季夏目天下第一  阅读(45)  评论(0编辑  收藏  举报