簡體   English   中英

如何將值輸入到以結構為鍵的映射中?

[英]How can I enter values into a map with a struct as key?

我有一個以struct為鍵的映射,我重載了<運算符,但映射將每個條目存儲為單獨的鍵,即使它們相同。 代碼如下:

#include <iostream>
#include <vector>
#include <map>

using namespace std;

struct vertex 
{
    int color;
    vertex *pi;
    int index;

    bool operator<(const vertex & v ) const {
        return this->index < v.index;
    }
    bool operator==(const vertex & v) const {
        return this->index == v.index;
    }
};

int main()
{
    int x, y, num_edges;
    vector<vertex* > v;
    vertex *temp1, *temp2, *temp;
    map<vertex*, vector<vertex*> > m;
    map<vertex*, vector<vertex*> >::iterator it;

    cout << "\nEnter no. of edges: ";
    cin >> num_edges;

    for( int i = 0; i < num_edges; i++ )
    {
        cout << "\nEnter source: ";
        cin >> x;
        cout << "\nEnter dest: ";
        cin >> y;

        temp1 = new vertex;
        temp2 = new vertex;
        temp1->index = x;
        temp2->index = y;

        m[temp1].push_back(temp2);
        m[temp2].push_back(temp1);
    }
    
    temp1 = new vertex;
    temp2 = new vertex;

    cout << "\nPrinting map: " << endl;
    for( it = m.begin(); it != m.end(); it++ )
    {
        temp = (*it).first;

        cout << temp->index << "\t";

        v = (*it).second;
        for( int i = 0; i < v.size(); i++ )
        {
            temp1 = v[i];
            cout << temp1->index << "\t";
        }
        cout << "\n";
        v.clear();
    }
    for( it = m.begin(); it != m.end(); it++ )
    {
        temp = (*it).first;
        v.push_back(temp);
    }
    return 0;
}

我現在得到的輸出是:

Enter no. of edges: 4

Enter source: 1

Enter dest: 3

Enter source: 4

Enter dest: 3

Enter source: 4

Enter dest: 2

Enter source: 2

Enter dest: 1

Printing map: 
1   3   
3   1   
4   3   
3   4   
4   2   
2   4   
2   1   
1   2   

但它應該是:

1 3 2  
2 4 1      
3 1 4  
4 3 2

我哪里錯了?

std::map 將比較您作為鍵( vertex* )提供的類型,但您在頂點上定義<運算符。

您可以使用結構本身作為鍵,或者 - 如果您必須使用指針 - 您必須為映射提供一種比較指針的方法。

現在, std::map使用std::less作為比較謂詞,它在< therm 中定義(這就是為什么使用結構本身,您可以通過重載<來實現結果)。

您可以:

o) 定義一個比較頂點*的謂詞:它可以是

template <class T> //assume T is a pointer or pointer-like class
struct redirected_less : public std::binary_function <T,T,bool> 
{
    bool operator() (const T& x, const T& y) const {return *x < *y;}
};

然后將您的地圖定義為

std::map<vertex*, vector<vertex*>,  redirected_less<vertex*> >

o) 將頂點 * 的 std::less 特化為

namespace std
{
     template <> 
     struct less<vertex*> : binary_function <vertex*,vertex*,bool> 
     {
         bool operator() (vertex* x, vertex* y) const {return *x < *y; }
     };
}

並將您的地圖聲明為

std::map<vertex*, vector<vertex*> >

照常。

我個人更喜歡第一個(提供更本地化的代碼,在以后的閱讀中更少“神秘”)

您不能使用指針作為鍵。 如果您有兩個結構,根據您的規則它們是“相同的”,但是它們是在堆上用new分配的,那么它們的指針將永遠不會相同。

使用結構而不是它們的指針作為鍵。

map<vertex*, vector<vertex*> > m;// its key type vertex*  

m 用途

bool operator < (vertex * const, vertex* const) ;

訂購時

所以你需要超載

bool operator < (vertex * const, vertex* const); 

我們這里有問題。 我們不能重載指針。 我們可以像這樣提供我們自己的比較函數:

struct cmp{ 
      bool operator ()(vertex * const first, vertex* const second)
      { return first.index < second->index;} 
 };
cmp _cmp;
map<vertex*, vector<vertex*>, cmp> m(_cmp);

C++11

Emilio Garavaglia 分析了您的代碼的問題以及如何很好地修復它 但是,如果您可以使用C++11功能,那么您可以稍微現代化一下您的解決方案。 例如,您可以使用lambda 表達式而不是為您的結構定義operator< ,並將其傳遞給映射的構造函數。 如果您無法修改要存儲在地圖中的結構,或者您想為不同的地圖提供不同的比較函數,則此方法很有用。 基於范圍的for循環使您不必處理迭代器,而占位符auto您不必指定冗長的容器元素類型。 我還想提一下,您無需為地圖指定operator==即可工作。

vertex為鍵的解決方案

為了清楚起見,我用硬編碼值替換了用戶輸入:

struct vertex {
    int color;
    vertex *pi;
    int index;
};

int main() {
    auto comp = [](const vertex& v1, const vertex& v2) { return v1.index < v2.index; };
    std::map<vertex, std::vector<vertex>, decltype(comp)> m(comp);

    // Replace user input.
    std::vector<std::pair<int, int>> edges = { {1, 3}, {4, 3}, {4, 2}, {2, 1} };

    // Fill the map.
    for(auto const &e : edges) {
        vertex temp1;
        vertex temp2;
        temp1.index = e.first;
        temp2.index = e.second;
        m[temp1].push_back(temp2);
        m[temp2].push_back(temp1);
    }

    // Print the map.
    std::cout << "Printing map:" << std::endl;
    for (auto const &kv : m) {
        std::cout << kv.first.index << " =>";
        for (auto const &v : kv.second)
            std::cout << " " << v.index;
        std::cout << std::endl;
    }

    return 0;
}

輸出:

打印地圖:
1 => 3 2
2 => 4 1
3 => 1 4
4 => 3 2

注意:如果您可以使用C++17 ,那么您可以通過使用 結構化綁定進一步縮短打印地圖的代碼,如Coliru 上所示

vertex*為鍵的解決方案

基本上,您必須用vertex*替換上述代碼中所有出現的vertex 此外,您必須確保 lambda 表達式不比較給定的指針,而是指針所指結構的內容:

auto comp = [](const vertex* pv1, const vertex* pv2) { return pv1->index < pv2->index; };
std::map<vertex*, std::vector<vertex*>, decltype(comp)> m(comp);

您還必須確保在最后刪除所有動態分配的頂點。 例如,您可以通過以下方式正確清空地圖:

for (auto const &kv : m)
    for (auto const pv : kv.second)
        delete pv;
m.clear();

Coliru 上的代碼

注意:為了簡化內存管理,您應該更喜歡在映射中存儲智能指針,例如std::unique_ptrstd::shared_ptr

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM