介于多重映射和向量之间的数据结构

发布于 2024-09-14 01:05:53 字数 947 浏览 2 评论 0 原文

可能的重复:
一个 std::map 跟踪顺序插入?

我正在寻找一个像 std::multimap 一样工作的 STL 容器,但我可以像向量一样按插入顺序访问成员。

例如:

  multimap<char,int> mymultimap;
  multimap<char,int>::iterator it;

  mymultimap.insert ( pair<char,int>('a',100) );
  mymultimap.insert ( pair<char,int>('z',150) ); 
  mymultimap.insert ( pair<char,int>('b',75) );
  mymultimap.insert ( pair<char,int>('a',75) );

  for ( it=mymultimap.begin() ; it != mymultimap.end(); it++ )
    cout << (*it).first << " => " << (*it).second << endl;

输出:

a => 100个

=> 75

b => 75

z => 150

预期输出:

a => 100z

=> 150

b => 75

一个=> 75

谢谢。

Possible Duplicate:
A std::map that keep track of the order of insertion?

I'm looking for a STL container that works like std::multimap but i can access the members in order of insertion like vector.

for example:

  multimap<char,int> mymultimap;
  multimap<char,int>::iterator it;

  mymultimap.insert ( pair<char,int>('a',100) );
  mymultimap.insert ( pair<char,int>('z',150) ); 
  mymultimap.insert ( pair<char,int>('b',75) );
  mymultimap.insert ( pair<char,int>('a',75) );

  for ( it=mymultimap.begin() ; it != mymultimap.end(); it++ )
    cout << (*it).first << " => " << (*it).second << endl;

output:

a => 100

a => 75

b => 75

z => 150

expected output:

a => 100

z => 150

b => 75

a => 75

thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夏天碎花小短裙 2024-09-21 01:05:53

您可以使用 std::vector; > 为此。另外,您可以使用 std::make_pair 函数来创建配对。这是示例代码:

vector<pair<char,int> > v;
    vector<pair<char,int> >::iterator it;

  v.push_back ( make_pair('a',100) );
  v.push_back ( make_pair('z',150) ); 
  v.push_back ( make_pair('b',75) );
  v.push_back ( make_pair('a',75) );

  for ( it=v.begin() ; it != v.end(); it++ )
    cout << (*it).first << " => " << (*it).second << endl;

You can use std::vector<std::pair<char,int> > for this. Also, you can use std::make_pair function to create a pair. Here is the sample code:

vector<pair<char,int> > v;
    vector<pair<char,int> >::iterator it;

  v.push_back ( make_pair('a',100) );
  v.push_back ( make_pair('z',150) ); 
  v.push_back ( make_pair('b',75) );
  v.push_back ( make_pair('a',75) );

  for ( it=v.begin() ; it != v.end(); it++ )
    cout << (*it).first << " => " << (*it).second << endl;
平定天下 2024-09-21 01:05:53

boost 库有一个灵活的多索引容器,可以执行您想要的操作以及更多操作: http://www.boost.org/doc/libs/1_43_0/libs/multi_index/doc/index.html

你可以构建可以顺序访问但也允许 O(log (N)) 快速查找。一开始语法有点不透明,但是一旦你得到了一些东西,这是一项值得的投资,因为该实现将经过 boost 人员和大量普通用户的彻底测试。

The boost libraries have a flexible multiple index container that does what you want and more: http://www.boost.org/doc/libs/1_43_0/libs/multi_index/doc/index.html

You can construct multi_index containers that can be accessed sequentially but also allow O(log(N)) fast lookup. The syntax is a little opaque to start off with, but once you get something working it's a worthwhile investment as the implementation will have been thoroughly tested by the boost guys and a large number of general users.

清旖 2024-09-21 01:05:53

除了 std::vector 之外> 正如已经建议的,也许 boost::bimap 对您来说是一个很好的解决方案。

Other than a std::vector<std::pair<char,int> > as already suggested, maybe boost::bimap would be a good solution for you.

绅士风度i 2024-09-21 01:05:53

您可以将 multimaplist 结合起来。

下面是一个可以执行您想要的操作的容器。对象存储在 multimap 中,附加的 list 存储 multimap 迭代器(只要指向的元素位于容器中,它们就保持有效)。所有操作都具有与 multimap 中相同的复杂性,但 erase 方法除外,该方法的复杂度为 O(n*m),其中 n是所有元素的数量,m 是删除的元素数量。

#include <map>
#include <list>
#include <algorithm>

template <class Key, class T>
class my_map : public std::multimap<Key, T> {
public:
    typedef typename std::multimap<Key, T> multimap_type;

    typedef typename multimap_type::key_type   key_type;
    typedef typename multimap_type::value_type value_type;
    typedef typename multimap_type::size_type  size_type;
    typedef typename multimap_type::iterator   iterator;

    struct order_iterator : std::list<typename multimap_type::iterator>::iterator {
        typedef typename std::list<typename multimap_type::iterator>::iterator iterator_t;

        order_iterator() {}
        order_iterator(const iterator_t &iterator) : iterator_t(iterator) { }

        const std::pair<const Key, T>& operator *  () const { return ***(const iterator_t*)this; }
              std::pair<const Key, T>& operator *  ()       { return ***(      iterator_t*)this; }
        const std::pair<const Key, T>* operator -> () const { return &**this; }
              std::pair<const Key, T>* operator -> ()       { return &**this; }
    };

private:
    std::list<typename multimap_type::iterator> list;
    multimap_type *base() { return this; }

public:
    order_iterator order_begin() { return this->list.begin(); }
    order_iterator order_end() { return this->list.end(); }

    iterator insert(const value_type& x)
    {
        iterator ret = this->base()->insert(x);
        this->list.push_back(ret);
        return ret;
    }

    iterator insert(iterator position, const value_type& x)
    {
        iterator ret = this->base()->insert(position, x);
        this->list.push_back(ret);
        return ret;
    }

    template <class InputIterator>
    void insert(InputIterator first, InputIterator last)
    {
        while (last != first) this->insert(first++);
    }

    void erase(iterator first, iterator last)
    {
        if (first == this->end()) return;

        for (iterator it = first; it != last; ++it) {
            this->list.erase(std::find(this->list.begin(), this->list.end(), it));
        }
    }

    void erase(iterator position)
    {
        iterator last = position;
        this->erase(position, ++last);
    }

    size_type erase (const key_type& x)
    {
        iterator range_begin = this->lower_bound(x);
        if (range_begin == this->end()) return 0;

        size_type ret = 0;
        iterator range_end = range_begin;
        do range_end++, ret++; while (range_end != this->end() && range_end->first == x);

        this->base()->erase(range_begin, range_end);
        for (; range_begin != range_end; range_begin++) {
            this->list.erase(std::find(this->list.begin(), this->list.end(), range_begin));
        }

        return ret;
    }

    void clear()
    {
        this->list.clear();
        this->base()->clear();
    }
};

#include <iostream>
using namespace std;

my_map<char,int> mymultimap;

void dump()
{
    cout << "by insert:\n";
    for (
        my_map<char,int>::order_iterator it = mymultimap.order_begin();
        it != mymultimap.order_end();
        it++
    ) {
        cout << (*it).first << " => " << (*it).second << endl;
    }

    cout << "by key:\n";
    for (
        my_map<char,int>::iterator it = mymultimap.begin();
        it != mymultimap.end();
        it++
    ) {
        cout << (*it).first << " => " << (*it).second << endl;
    }

    cout << endl;
}

int main()
{
    mymultimap.insert(make_pair('a',100));
    mymultimap.insert(make_pair('z',150));
    mymultimap.insert(make_pair('b',75));
    mymultimap.insert(make_pair('a',75));
    dump();

    mymultimap.erase('a');
    dump();
}

如果按插入顺序迭代元素比按键查找更频繁地使用,那么“镜像”这个想法会更优化:将键/值对存储在 list 中(这样我们就可以在插入中迭代order)并具有额外的包含 list 元素迭代器的 multiset(用于按键查找目的)。

You can combine multimap with list.

Below is a container that do what you want. Objects are stored in a multimap and additional list stores multimap iterators (they stay valid as long as pointed element is in the container). All operations have the same complexity like in multimap except erase methods which are O(n*m) where n is number of all elements and m is number of elements removed.

#include <map>
#include <list>
#include <algorithm>

template <class Key, class T>
class my_map : public std::multimap<Key, T> {
public:
    typedef typename std::multimap<Key, T> multimap_type;

    typedef typename multimap_type::key_type   key_type;
    typedef typename multimap_type::value_type value_type;
    typedef typename multimap_type::size_type  size_type;
    typedef typename multimap_type::iterator   iterator;

    struct order_iterator : std::list<typename multimap_type::iterator>::iterator {
        typedef typename std::list<typename multimap_type::iterator>::iterator iterator_t;

        order_iterator() {}
        order_iterator(const iterator_t &iterator) : iterator_t(iterator) { }

        const std::pair<const Key, T>& operator *  () const { return ***(const iterator_t*)this; }
              std::pair<const Key, T>& operator *  ()       { return ***(      iterator_t*)this; }
        const std::pair<const Key, T>* operator -> () const { return &**this; }
              std::pair<const Key, T>* operator -> ()       { return &**this; }
    };

private:
    std::list<typename multimap_type::iterator> list;
    multimap_type *base() { return this; }

public:
    order_iterator order_begin() { return this->list.begin(); }
    order_iterator order_end() { return this->list.end(); }

    iterator insert(const value_type& x)
    {
        iterator ret = this->base()->insert(x);
        this->list.push_back(ret);
        return ret;
    }

    iterator insert(iterator position, const value_type& x)
    {
        iterator ret = this->base()->insert(position, x);
        this->list.push_back(ret);
        return ret;
    }

    template <class InputIterator>
    void insert(InputIterator first, InputIterator last)
    {
        while (last != first) this->insert(first++);
    }

    void erase(iterator first, iterator last)
    {
        if (first == this->end()) return;

        for (iterator it = first; it != last; ++it) {
            this->list.erase(std::find(this->list.begin(), this->list.end(), it));
        }
    }

    void erase(iterator position)
    {
        iterator last = position;
        this->erase(position, ++last);
    }

    size_type erase (const key_type& x)
    {
        iterator range_begin = this->lower_bound(x);
        if (range_begin == this->end()) return 0;

        size_type ret = 0;
        iterator range_end = range_begin;
        do range_end++, ret++; while (range_end != this->end() && range_end->first == x);

        this->base()->erase(range_begin, range_end);
        for (; range_begin != range_end; range_begin++) {
            this->list.erase(std::find(this->list.begin(), this->list.end(), range_begin));
        }

        return ret;
    }

    void clear()
    {
        this->list.clear();
        this->base()->clear();
    }
};

#include <iostream>
using namespace std;

my_map<char,int> mymultimap;

void dump()
{
    cout << "by insert:\n";
    for (
        my_map<char,int>::order_iterator it = mymultimap.order_begin();
        it != mymultimap.order_end();
        it++
    ) {
        cout << (*it).first << " => " << (*it).second << endl;
    }

    cout << "by key:\n";
    for (
        my_map<char,int>::iterator it = mymultimap.begin();
        it != mymultimap.end();
        it++
    ) {
        cout << (*it).first << " => " << (*it).second << endl;
    }

    cout << endl;
}

int main()
{
    mymultimap.insert(make_pair('a',100));
    mymultimap.insert(make_pair('z',150));
    mymultimap.insert(make_pair('b',75));
    mymultimap.insert(make_pair('a',75));
    dump();

    mymultimap.erase('a');
    dump();
}

If iterating elements in insertion order is more intensively used then lookup by a key then it would be more optimal to "mirror" the idea: store key/value pairs in a list (so we can iterate in insertion order) and have additional multiset containing iterators to list elements (for by-key-lookup purposes).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文