最近做编程题发现关联容器忘得多,翻翻以前写的代码,mark一下,勉励自己
目录
基本概念
map multi_map
- map是标准的关联式容器,一个map是一个键值对序列,即(key,value)对。它提供基于key的快速检索能力。
- map中key值是唯一的。集合中的元素按一定的顺序排列。元素插入过程是按排序规则插入,所以不能指定插入位置。
- map的具体实现采用红黑树变体的平衡二叉树的数据结构。在插入操作和删除操作上比vector快。
- map可以直接存取key所对应的value,支持[]操作符,如map[key]=value。
- multimap与map的区别:map支持唯一键值,每个键只能出现一次;而multimap中相同键可以出现多次。multimap不支持[]操作符。
unordered_set unordered_map
无序容器 使用hash函数和==运算
桶管理:将具有相同hash值的元素保存在同一个桶中。无序容器的性能依赖于hash函数的性质和桶的大小和数量
成员函数和map set差不多,关于有序的函数没有,多了桶管理函数
具体成员函数API调用代码
#include<iostream>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<unordered_set>
#include<unordered_map>
#include<functional>
using namespace std;
//定义关联容器
void countre_init()
{
vector<int>v = { 1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2,1 };
set<int>s(v.begin(), v.end());//不允许重复
multiset<int>multi_s(v.begin(), v.end());
//列表初始化
map < string, string >m = { {"zhangsan", "wangbadan"}, { "lisi","wangjiudan" }, { "zhangsan", "wangbadan" } };
multimap < string, string >multi_m = { { "zhangsan", "wangbadan" },{ "lisi","wangjiudan" },{ "zhangsan", "wangbadan" } };
cout << v.size() << " " << s.size() << " " << multi_s.size() << endl;
cout << m.size() << " " << multi_m.size() << endl;
}
//使用关键字类型的比较函数 自定义<
bool compare(int a, int b)
{return a < b ? false:true;}//从大到小
//仿函数::又叫函数对象,一种行为类似函数的对象。调用者可以向函数一样使用该对象。
//实现:用户只需要实现一种新的类型,在类中进行重载(),参数根据用户索要进行的操作选择匹配
class Greater//或struct
{
public:
bool operator()(const string str1, const string str2)
{
return str1.size() < str2.size() ? true : false;
}
};
void key_function()
{
//set map 等有序集合 实现排序的时 默认使用<比较两个关键字
//自定义的操作类型在尖括号里紧跟元素类型
set<int, decltype(compare)*>s(compare);//必须指明指针类型 decltype推断函数类型
map<int, int,decltype(compare)*>m(compare);
for (int i = 0; i < 10; i++)
{
s.insert(i);
m.insert(make_pair(i+5, i));
}
for (auto c : s)
cout << c << " ";
cout << endl;
auto map_it = m.begin();
while (map_it != m.end())
{
cout << map_it->first << " " << map_it->second << endl;
map_it++;
}
//实现倒序 谓词 greater #include<functional>
//set<int,less<int> > setIntA; //该容器是按升序方式排列元素。
//set<int, greater<int>> setIntB; //该容器是按降序方式排列元素。
set<string, greater<string>>s2 = { "zhangsan","lisi","wangwu","maliu","luqi","wangba" };
for (auto c : s2)
cout << c << " " << endl;
//实现倒序 仿函数
set<string, Greater>s3 = { "zhangsan","lisi","wangwu","maliu","luqi","wangba" };
for (auto c : s3)
cout << c << " " << endl;
}
void pair_make()
{
//pair类型 用于生成特定类型的模板,两个public成员first second make_pair()函数 == !=等操作
//key_type (关键字类型) mapped_type(值类型,只适用于map) value_type(对于set为键值类型,map为pair类型)
//每个pair的关键字key为const不可改变,但是value可以改变 set只有key值所以不可变
//采用作用域访问
pair<string, int>author("zhangsan", 33);
cout << author.first << author.second << endl;
author.second = 44;//合法 author.first = "lisi" 违法
set<int>s = { 1,2,3 };
set<int>::iterator it = s.begin();
cout << *it << endl;// *it = 2;//违法 只读
pair<string, int>t = make_pair("zhangsan", 44);//make_pair()函数
vector<pair<string, int>>v;
vector<string>v2 = { "zhangsan","lisi","wangmazi" };
for(int i = 0;i<10;i++)
v.push_back(make_pair(v2[i%3], i + 30));
for (auto c : v)
cout << c.first << " " << c.second << endl;
}
//插入insert 删除erase
void insert_function()
{
vector<int>v = { 1,2,3,4,5,6,7,4,6,78,2,5 };
set<int>s;
s.insert(v.begin(), v.end());
s.insert(0);
for (auto c : s)
cout << c << " ";
cout << endl;
cout<<s.erase(5)<<endl;//erase(key)删除键值为key的元素,返回删除元素的个数,set01 multi 多个
cout << *(s.erase(s.begin())) << endl;//删除迭代器所指的元素,返回下一个迭代器
s.erase(++s.begin(), --s.end());//范围删除,+ - 不支持
for (auto c : s)
cout << c << " ";
cout << endl;
s.insert(v.begin() + 3, v.end() - 1);
map<string, int>m;
m.insert({ "zhangsan",22 });//最简单,常用花括号和make_pair()
m.insert(make_pair("lisi", 33));
m.insert(pair<string, int>("wangwu", 44));
m.insert(map<string, int>::value_type("maliu", 55));
//insert返回值w为pair(iterator,bool)iterator指向待插入元素的位置,bool表示插入是否成功,成功则true
//对于map 和set返回pair 对于multimap和multiset插入总是成功,返回iterator
auto ret1 = s.insert(0);
if (ret1.second == false)
cout << "插入0失败" << endl;
auto ret2 = m.insert({ "zhangsan",22 });
if (ret2.second == false)
ret2.first->second += 11;
cout << ret2.first->first << " " << ret2.first->second << endl;//ret2.first指向待插入(重复)迭代器
//对于multi返回迭代器
multimap<string, int>m2 = { {"zhangsan",22} };
auto it = m2.insert({ "zhangsan", 33 });
m2.insert({ "lisi",44 });
cout << it->first << " " << it->second << endl;
cout << m2.erase("lisi") << endl;//返回1个
//map的下标操作 set 和multiset multimap不存在下表操作,不存在值或者值不唯一
//[]先检查有没有,没有则创建,有则返回value_type 与迭代器不同,迭代器解引用返回pair类型
map<string, int>m3;//一个空map
m3["zhangsan"] = 44;//1)首先查找"zhangsan",没找到 2) 插入关键字zhangsan 值默认为0 3)将4赋值给zhangsan
m3.at("zhangsan") = 55;//先查找,没有则抛出异常out_of_ranage否则返回value_type
//访问元素
cout<<*(s.find(1))<<endl;//返回一个迭代器,找不到返回s.end();
cout << s.count(2) << endl;//返回一个数,key=2的个数
//只有有序容器中可用
cout << *s.lower_bound(3) << endl;//返回第一个不小于3的迭代器
cout << *s.upper_bound(3) << endl;//返回第一个大于3的迭代器
//multiset 和 multimap中查找,相同的key保存在相邻的位置
cout << endl << endl << endl;
auto it3 = m2.find("zhangsan");
int count = m2.count("zhangsan");
while (count)
{
cout << it3->first << " " << it3->second << endl;
count--;
it3++;
}
//upper_bound("zhangsan")找到则返回zhangsan下一个位置(尾后),未找到则返回一个可以插入zhangsan的位置
//不影响序列有序,可能zhangsan最大,找到end==m2.end() 也可能没找到 同时最大end == m2.end(),所以
//不能根据其返回值判断是否找到,但是返回一个范围,可以输出
for (auto beg = m2.lower_bound("zhangsan"), end = m2.upper_bound("zhangsan"); beg != end; beg++)
cout << beg->first << " " << beg->second << endl;
//equal_ranage找到则返回pair(iterator1,iterator2);iterator1指向第一个,iterator2指向最后一个的尾后
//如果没有找到则同时指向一个可以插入的位置
for(auto pos = m2.equal_range("zhangsan"); pos.first!= pos.second; pos.first++)
cout << pos.first->first << " " << pos.first->second << endl;
}
//无序容器 使用hash函数和==运算
// 桶管理:将具有相同hash值的元素保存在同一个桶中。无序容器的性能依赖于hash函数的性质和桶的大小和数量
//成员函数和map set差不多,关于有序的函数没有,多了桶管理函数
void unordered_container()
{
unordered_map<string, int>un_m = { {"ccc",3}, {"aaa",1},{"bbb",2 } };
un_m.insert({ "ddd",4 });
for (auto pos: un_m)
{
cout << pos.first << " " << pos.second << endl;
}
un_m.erase("ccc");
for (auto pos : un_m)
{
cout << pos.first << " " << pos.second << endl;
}
auto it = un_m.find("aaa");
cout << it->first << " " << it->second << endl;
cout << un_m.count("ddd") << endl;
//桶管理函数:允许我们查看桶的状态,必要时进行重组
cout<<un_m.bucket_count()<<endl;//正在使用的桶数量
cout << un_m.max_bucket_count()<<endl;//容器最多能容纳的桶的数量
cout << un_m.bucket_size(2) << endl;//第2个桶有几个元素
cout << un_m.bucket("ddd") << endl;//关键字为"ddd"在哪个桶里
cout << un_m.load_factor() << endl;//平均每个桶有几个元素
}
int main()
{
countre_init();
key_function();
pair_make();
insert_function();
unordered_container();
//调用函数对象,创建一个函数对象,调用它
Greater a;
cout<<a("zhangsan", "lisi")<<endl;
return 0;
}
priority_queue:
//使用方法 priority(Type,Conteiner,Function)
//std::priority_queue<T, std::vector<T>, greater<T>> pq;
//不加后面两个参数的话默认为 container 默认为vector function默认为less 大顶堆
//小顶堆 基本类型 priority_queue<int, vector<int>, greater<int> >q3;
//自定义型 则重载<
//函数greater在<functional>
push_heap pop_heap sort_heap
将[begin, end)范围进行堆排序,默认使用less<int>, 即最大元素放在第一个。
make_heap(v.begin(), v.end());
//将begin移动到end的前部,同时将剩下的元素堆排序为一个新的heap
//配合vector的pop_back进行出堆操作
pop_heap(v.begin(), v.end()); v.pop_back();
//刚插入的(尾部)元素做堆排序
v.push_back(100); push_heap(v.begin(), v.end());
//将一个堆做排序,最终成为一个有序的系列,可以看到sort_heap时,必须先是一个堆
//(两个特性:1、最大元素在第一个 2、添加或者删除元素以对数时间),因此必须先做一次make_heap.
sort_heap(v.begin(), v.end());
push_heap pop_heap sort_heap的基本操作:
void heap_opt()
{
//include<algorithm> "functional"
int myints[] = { 10,20,30,5,15 };
vector<int> v(myints, myints + 5);
vector<int>::iterator it;
//将[begin, end)范围进行堆排序,默认使用less<int>, 即最大元素放在第一个。
make_heap(v.begin(), v.end());
cout << "初始堆堆顶 : " << v.front() << endl;
//将begin移动到end的前部,同时将剩下的元素堆排序为一个新的heap
//配合vector的pop_back进行出堆操作
pop_heap(v.begin(), v.end()); v.pop_back();
cout << "max heap after pop : " << v.front() << endl;
//刚插入的(尾部)元素做堆排序
v.push_back(100); push_heap(v.begin(), v.end());
cout << "max heap after push: " << v.front() << endl;
//将一个堆做排序,最终成为一个有序的系列,可以看到sort_heap时,必须先是一个堆
//(两个特性:1、最大元素在第一个 2、添加或者删除元素以对数时间),因此必须先做一次make_heap.
sort_heap(v.begin(), v.end());
cout << "最终堆顺序:";
for (unsigned i = 0; i<v.size(); i++) cout << " " << v[i];
cout << endl;
}
priority_queue的基本操作:
void priority_queue_opt()
{
//使用方法 priority(Type,Conteiner,Function)
//std::priority_queue<T, std::vector<T>, greater<T>> pq;
//不加后面两个参数的话默认为 container 默认为vector function默认为less 大顶堆
//小顶堆 基本类型 priority_queue<int, vector<int>, greater<int> >q3;
//自定义型 则重载<
//函数greater在<functional>
priority_queue<int> q1;
//默认是最大值优先队列 q1等价于q2
priority_queue<int, vector<int>, less<int>>q2;
priority_queue<int, vector<int>, greater<int> >q3;
q2.push(1);
q2.push(3);
q2.push(4);
q2.push(6);
cout << "q2.size" << q2.size() << endl;
while (!q2.empty())
{
cout << q2.top() << ' ';
q2.pop();
}
cout << endl;
q3.push(6);
q3.push(3);
q3.push(2);
q3.push(1);
while (!q3.empty())
{
cout << q3.top() << ' ';
q3.pop();
}
cout << endl;
}
利用大顶堆小顶堆进行取中位数:
class MidNum {
public:
void Insert(int num)
{
if (((min.size() + max.size()) & 1) == 0)//目前总共偶数个数字
{
if (max.size()>0 && num<max[0])//偶数个应该放在最小堆,但是数字比大顶堆最大值小
{
//vector.push_back push_back() 数字进堆
//调整,先进大顶堆,将大顶堆最大放入最小堆保持元素差1
max.push_back(num);
//将front移动到end的前部,同时将剩下的元素重新构造成(堆排序)一个新的heap
push_heap(max.begin(), max.end(), less<int>());
num = max[0];
//pop_heap vector.pop_back数字出堆
//将[first, last)范围进行堆排序,默认使用less<int>, 即最大元素放在第一个。
pop_heap(max.begin(), max.end(), less<int>());
max.pop_back();
}
min.push_back(num);
push_heap(min.begin(), min.end(), greater<int>());
}
else
{
if (min.size()>0 && min[0]<num)//本来要插入大顶堆,结果num小顶堆最小值小
{
min.push_back(num);
push_heap(min.begin(), min.end(), greater<int>());
num = min[0];
pop_heap(min.begin(), min.end(), greater<int>());
min.pop_back();
}
max.push_back(num);
push_heap(max.begin(), max.end(), less<int>());
}
}
main测试函数
int main()
{
srand(time(0));
heap_opt();
priority_queue_opt();
MidNum m;
for (int i = 1; i < 10; ++i)
m.Insert(rand() % 100);
cout << m.GetMedian();
return 0;
}
结果:
参考:
primer
C++Reference
剑指offer