1. 程式人生 > 其它 >優先佇列儲存自定義型別物件的指標

優先佇列儲存自定義型別物件的指標

一開始我想用優先佇列來實現構造哈夫曼樹,並以指標方式儲存每個結點的左右兒子的地址
很自然的想到如下的程式碼

#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;
}