最近做編程題發現關聯容器忘得多,翻翻以前寫的代碼,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