C++多映射容器是如何实现的
How is the C++ multimap container implemented?
例如,C++向量使用动态数组实现,其中每个元素使用连续的内存空间。
我知道C++多映射是一对多的关系,但内部结构是什么?
C++标准没有定义标准容器应该如何实现,它只给出了某些约束,比如你说的向量约束。
multimaps具有一定的运行时复杂性(对于感兴趣的操作为O(lgn))和其他保证,并且可以实现为红黑树。这就是它们在GNU标准C++库中的实现方式。
通常情况下,一个红黑树。参见Dr.Dobb的STL的红黑树。
添加到"首选"答案,因为SO不让我评论:
给定一个值为B、C、D的键,如果每个元素都有自己的节点,迭代器的行为就会更容易实现。Find()被定义为返回序列中的第一个结果,随后的迭代将遍历其余元素。映射和多映射之间的事实上的区别在于多映射使用<在整个value_type上,其中映射使用<仅通过key_type
更正:C++11标准明确规定,在具有相同密钥的任何现有值的末尾插入新的(密钥、映射)对。这引发了一个我没有考虑过的问题:多映射是否可以包含两个节点,其中键和映射的目标都相同。标准似乎对此没有明确的立场,但值得注意的是,映射类型上不需要比较运算符。如果你编写一个测试程序,你会发现多映射可以将X映射到1,2,1。也就是说:"1"可以多次作为目标出现,并且这两个实例将不会合并。对于某些算法来说,这是一个缺陷。
Dobbs博士的这篇文章讨论了常用的底层rb树实现。需要注意的主要一点是,重新平衡操作实际上根本不关心密钥,这就是为什么您可以构建一个允许重复密钥的rb树。
多映射就像它的简单版本一样,即std::map,主要是使用红黑树构建的。C++标准本身并没有指定实现。但在大多数情况下(我亲自检查了SGI STL)都使用红黑树。红黑树是高度平衡的树,因此对它们的获取/读取操作总是保证为O(log(n))时间。但若您想知道密钥的值是如何存储的。每个CCD_ 1被保存为红黑树中的单独节点(即使同一密钥可能像下面的密钥CCD_。关键字用于查找/搜索rb树。一旦找到密钥,就会返回存储在节点中的值。
std::multimap<char,int> mmp;
mmp.insert(std::pair<char,int>('a',10));
mmp.insert(std::pair<char,int>('b',20));
mmp.insert(std::pair<char,int>('b',10));
mmp.insert(std::pair<char,int>('b',15));
mmp.insert(std::pair<char,int>('b',20));
mmp.insert(std::pair<char,int>('c',25));
mmp.insert(std::pair<char,int>('a',15));
mmp.insert(std::pair<char,int>('a',7));
for (std::multimap<char,int>::iterator it=mmp.begin(); it!=mmp.end(); ++it){
std::cout << (*it).first << " => " << (*it).second << " . Address of (*it).second = " << &((*it).second) << 'n';
}
输出:
a => 10 . Address of (*it).second = 0x96cca24
a => 15 . Address of (*it).second = 0x96ccae4
a => 7 . Address of (*it).second = 0x96ccb04
b => 20 . Address of (*it).second = 0x96cca44
b => 10 . Address of (*it).second = 0x96cca64
b => 15 . Address of (*it).second = 0x96cca84
b => 20 . Address of (*it).second = 0x96ccaa4
c => 25 . Address of (*it).second = 0x96ccac4
最初,我认为'b'这样的单个键的值可能存储在std::vector中。
template <class K, class V>
struct Node {
K key;
std::vector<V> values;
struct Node* left;
struct Node* right;
}
但后来我意识到这将违反O(log(n))的保证获取时间。此外,打印出值的地址可以确认具有公共键的值是不连续的。
使用运算符<插入这些键;,因此具有相同关键字的值按照它们被插入的顺序被存储。
所以如果我们先插入(键="b",值=20)然后(键="b",值=10)插入是使用运算符<由于第二个"b"不小于第一个插入的"b",因此它被插入到"二叉树的右分支"中。
我使用的编译器是gcc-5.1(C++14)。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 如何实现内部实现依赖于模板参数的类
- 我的 PRNG 实现与我尝试复制的实现有何不同?