例如,使用动态数组实现C ++向量,其中每个元素使用连续的内存空间。
我知道C ++多图是一对多的关系,但内部结构是什么?
答案 0 :(得分:28)
C ++标准没有定义标准容器应该如何实现,它只给出了某些约束,就像你对矢量所说的那样。
multimaps具有一定的运行时复杂度(对于有趣的操作来说是O(lg n))和其他保证,并且可以实现为red-black trees。这就是它们在GNU标准C ++库中的实现方式。
答案 1 :(得分:8)
经常是red-black tree。参见例如来自Dobb博士的STL's Red-Black Trees。
答案 2 :(得分:3)
除了“首选”答案,因为SO不会让我发表评论:
给定具有值B,C,D的键,如果每个元素都有自己的节点,则迭代器的行为更容易实现。 Find()被定义为返回系列中的第一个结果,后续迭代将带您浏览其余元素。地图和多重地图之间的事实上的区别在于多地图使用<在整个value_type上,地图使用<仅使用key_type
更正:C ++ 11标准明确指出,在具有相同键的任何现有值的末尾插入新的(键,映射)对。这提出了一个我没有考虑过的问题:多图包含两个节点,其中密钥和映射的目标都是相同的。标准似乎没有对此采取明确的立场,但值得注意的是,映射类型不需要比较运算符。如果您编写测试程序,您会发现多图可以将X映射到1,2,1。即:“1”可以多次出现作为目标,而两个实例将不合并。对于一些缺陷的算法。
Dr. Dobbs的这个article讨论了常用的基础rb-tree实现。需要注意的要点是,重新平衡操作实际上并不关心密钥,这就是为什么你可以构建一个允许重复密钥的rb-tree。
答案 3 :(得分:-1)
多图,就像它更简单的版本,即std :: map,主要使用红黑树构建。 C ++标准本身没有指定实现。但在大多数情况下(我亲自检查SGI STL)使用红黑树。红黑树是高度平衡的树,因此对它们的获取/读取操作始终保证为O(log(n))时间。但是,如果您想知道如何存储密钥的值。每个key->pair
都保存为红黑树中的单独节点(即使相同的密钥可能多次出现,就像下面的密钥'b'
一样)。密钥用于查找/搜索rb-tree。找到密钥后,将返回存储在节点中的值。
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
最初我认为像&#39; b&#39; 这样的单个键的值可能存储在std :: vector中。
template <class K, class V>
struct Node {
K key;
std::vector<V> values;
struct Node* left;
struct Node* right;
}
但后来我意识到这会违反O(log(n))的保证提取时间。此外,打印出值的地址确认具有公共密钥的值不是连续的。
使用运算符&lt;来插入它们的键,因此具有相同键的值将按照它们的插入顺序存储。
所以如果我们先插入 (键=&#39; b&#39;,值= 20) 然后 (键=&#39; b&#39;,值= 10) 使用运算符&lt;运算符完成插入。 ,因为第二个&#39; b&#39;并不比第一个插入的&#39; b&#39;,它被插入二叉树的右分支&#39;。
我使用的编译器是gcc-5.1(C ++ 14)。