1.关联式容器
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。
键值对
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值, value表示与key对应的信息
2.树形结构的关联式容器
树形结构的关联式容器有四种:map, set , multimap, multiset
共同点是:使用平衡搜索树(红黑树)
set
- set是按照一定次序存储元素的容器
- 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
- 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
注意
1 . 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的<value, value>构成的键值对
2 .set中插入元素时,只需插入value即可,不需构造键值对
3 .set中的元素不可以重复(因此可以使用set进行去重)
4 .set中的元素默认按照小于来比较
5 .set中要查找某个元素,时间复杂度为:log2N;
6 .set中的元素不许修改
set的构造:
set 的迭代器:
iterator begin() 返回set中起始位置的迭代器
iterator end() 返回set中最后一个元素后面的迭代器
const_iterator cbegin() const 返回set中起始位置元素的const迭代器
const_iterator cend() const 返回set中最后一个元素后面的const迭代器
reverse_iterator rbegin() 返回set第一个元素的反向迭代器,即end
reverse_iterator rend() 返回set最后一个元素下一个位置的反向迭代器,即rbegin()
const_reverse_iterator crbegin() const 返回set第一个元素的反向const迭代器,即cend
const_reverse_iterator crend() const 返回set最后一个元素下一个位置的反向const迭代器,即crbegin()
set 的容量
bool empty() const 检测set是否为空,空返回true,否则返回false
size_type size() const 返回set中有效元素的个数
set 的举例
void TestSet()
{
int array[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
set<int> s(array, array + sizeof(array) / sizeof(array[0]));
cout << s.size() << endl;
//正向打印set中的元素,打印结果看来 set可以去重
for (auto& e : s)
cout << e << " ";
cout << endl;
//使用迭代器逆向打印set中的元素
for (auto it = s.rbegin(); it != s.rend(); ++it)
cout << *it << " ";
cout << endl;
//set中值为3 的元素出现了几次
cout << s.count(3) << endl;
}
map的介绍
map的模板参数说明
key: 键值对中的key的类型
T: 键值对中value的类型
2.map的构造
map() 构造一个空的map
3.map 的容量与元素访问
bool empty () const 检测map中的元素是否为空,是返回true,否则返回false
size_type size() const 返回map 中有效元素个数
mapped_type& operator[](const key_type& k) 返回key对应的value
4.map中元素的修改
void Testmap()
{
map<string, string> m;
m.insert(pair<string, string>("peach", "梨"));
m.insert(make_pair("banana", "香蕉"));
m["apple"] = "苹果";
cout << m.size() << endl;
for (auto& e : m)
cout << e.first <<"----- "<<e.second<<endl;
cout << endl;
auto ret = m.insert(make_pair("peach", "桃色"));
if (ret.second)
cout << "<peach,桃色>不在map中,已插入" << endl;
else
cout << "键值为peach的元素已经存在:" << ret.first->first << "--->" << ret.first->second << "插入失败" << endl;
//删除key为"apple"的元素
m.erase("apple");
if (1 == m.count("apple"))
cout << "apple还在" << endl;
else
cout << "apple被吃了" << endl;
}
int main()
{
Testmap();
system("pause");
return 0;
}
运行结果:
总结:
map中元素是键值对
map中的key是唯一的,并且不能修改
默认按照小于的方式对key进行比较
map中的元素如果使用迭代器进行遍历,可以的到一个有序序列
map中的底层为平衡搜索树,查找效率比较高O(log2N)
multiset的介绍
注意:
multiset在底层存储的是<value,value>的键值对
multiset的插入接口只需要插入即可
与set的区别是,multiset的元素可以重复,set中value是唯一的
使用迭代器对multiset中的元素进行遍历,可以得到有序序列
multiset中的元素不能修改
在multiset中找某个元素,时间复杂度为O(log2N)
multiset的作用:可以对元素进行排序
multiset的使用
void Testset()
{
int array[] = { 2, 1, 3, 9, 6, 0, 5, 8, 4, 7 };
//在底层multiset在底层实际存储的是<int,int>的键值对
multiset<int>s(array, array + sizeof(array) / sizeof(array[0]));
for (auto e : s)
cout << e << "";
cout << endl;
}
multimap的介绍
注意:multimap和map的唯一不同是:map中的key是唯一的,而multimap的key是可以重复的
底层结构:
这几个容器共同点:底层都是二叉搜索树实现的
AVL树
AVL树的概念:
当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整)
它的左右子树都是AVL树
左右子树高度只差(简称平衡因子)的绝对值不超过1(-1/0/1)
如果一颗二叉搜索树的高度是平衡的,他就是 AVL树。如果他有n个节点,其高度可以保持在O(log2n),搜索时间复杂度O(log2n).