当前位置:   article > 正文

C++:map和set_c++set复杂度

c++set复杂度

目录

一.set介绍

1.set介绍

2.insert 使用

 set中的普通迭代器就是用的const迭代器!!

3.find

set::find和std::find对比

4.erase

5.swap 根节点交换

6.count 比find方便

7.lower_bound:返回>= val得位置迭代器

(1)lower_bound

用途:举例:要求删除>=x的所有值:

(2)upper_bound 返回>x位置的迭代器

8. std::multiset 跟set接口一样,只是允许冗余,不去重

9.set相关题目

二.map用法介绍

几个map和set的冷知识:

map:

①map是C++98中已存在的,unordered_map是C++11中才有的

②map中都重载了[]运算符,multimap中没有重载[]运算符,set也没有重载[]。

③map中key不能修改,因为如果修改了就不能保证红黑树的有序特性了

set:

①set中也可以存储键值对,实例化set时,将set中元素类型设置为pair即可

②set默认是升序,但是其内部默认不是按照大于比较,而是按照 less小于比较

③map和set查询的时间复杂度都是O(log_2N)

④map和set底层都是使用红黑树实现的

1.pair和make_pair

(1)pair键值对 的介绍

(2)make_pair 介绍

2.map的遍历

(1)英汉字典的遍历

(2)记录水果次数

3.insert写法提高 记录水果次数 的效率(不这么写,只是为[]做铺垫)

4.operator[] 运算符重载 

(1) 提高 记录水果次数 的效率的真正写法:

(2) 字典中利用[]插入或修改 示例

5.multimap 允许键值冗余

三.相关题目

1.692. 前K个高频单词

(1)做法一:stable_sort稳定排序

(2)做法二:stable_sort稳定排序 2

(3)做法三:sort 非稳定排序,可以控制比较方法使其稳定

 (4)做法四:利用map自身按照first排序

四.模拟实现

Map.h

Set.h

RBTree.h


一.set介绍

1.set介绍

set 是一个K模型的搜索二叉树 #include<set>

2.insert 使用

(1)和(2)相当于一样,在pos位置插入也会自动排序

 insert :排序 + 去重 

  1. void test_set1()
  2. {
  3. set<int> s;
  4. s.insert(4);
  5. s.insert(5);
  6. s.insert(2);
  7. s.insert(1);
  8. s.insert(1);
  9. s.insert(3);
  10. s.insert(2);
  11. s.insert(1);
  12. // 排序 + 去重
  13. set<int>::iterator it = s.begin();
  14. while (it != s.end())
  15. {
  16. //*it = 10; 迭代器不支持修改
  17. cout << *it << " ";
  18. ++it;
  19. }
  20. cout << endl;
  21. for (auto e : s)
  22. {
  23. cout << e << " ";
  24. }
  25. cout << endl;
  26. }

 set中的普通迭代器就是用的const迭代器!!


 

3.find

能找到就返回元素的迭代器,找不到就返回end

set::find和std::find对比

set::find 搜索二叉树特性查找,时间复杂度是O(logN)

全局的find 是暴力查找,时间复杂度是O(N)

所以set::find效率更高

  1. void test_set2()
  2. {
  3. set<int> s;
  4. s.insert(4);
  5. s.insert(5);
  6. s.insert(2);
  7. s.insert(1);
  8. s.insert(1);
  9. s.insert(3);
  10. s.insert(2);
  11. s.insert(1);
  12. set<int>::iterator pos = s.find(20); // O(logN)
  13. if (pos != s.end())
  14. {
  15. cout << "set.find找到了" << endl;
  16. }
  17. pos = find(s.begin(), s.end(), 2); // O(N)
  18. if (pos != s.end())
  19. {
  20. cout << "find找到了" << endl;
  21. }
  22. }

4.erase

size_type就是size_t,也就是unsigned int

(1) void erase (iterator position); 必须加检查if (pos != s.end()) s.erase(pos); 因为有pos时,正常运行,如果没有pos,就会报错。例如:s.erase(pos);

(2)size_ type erase (const value_ type& val) ; 则可以随便删,无论有没有都不报错 例如:s.erase(3)

(3)void erase (iterator first,iterator last) 删的是[ first, last),即不包含 last

  1. void test_set3()
  2. {
  3. set<int> s;
  4. s.insert(4);
  5. s.insert(5);
  6. s.insert(2);
  7. s.insert(1);
  8. s.insert(1);
  9. s.insert(3);
  10. s.insert(2);
  11. s.insert(1);
  12. cout << s.erase(3) << endl; //有就返回1
  13. cout << s.erase(30) << endl; //没有就返回0
  14. for (auto e : s)
  15. {
  16. cout << e << " ";
  17. }
  18. cout << endl;
  19. set<int>::iterator pos = s.find(3);
  20. if (pos != s.end())
  21. s.erase(pos);
  22. for (auto e : s)
  23. {
  24. cout << e << " ";
  25. }
  26. cout << endl;

5.swap 根节点交换

6.count 比find方便

  1. if (s.count(5))
  2. {
  3. cout << "5在" << endl;
  4. }
  5. if (s.find(5) != s.end())
  6. {
  7. cout << "5在" << endl;
  8. }

打印:

5在

5在

7.lower_bound:返回>= val得位置迭代器

(1)lower_bound

返回>= val得位置迭代器 3返回3位置 6 返回7位置

  1. 返回>= val的位置迭代器 3返回3位置 6 返回7位置
  2. set<int> s;
  3. s.insert(4);
  4. s.insert(5);
  5. s.insert(1);
  6. s.insert(3);
  7. s.insert(2);
  8. s.insert(7);
  9. s.insert(9);
  10. set<int>::iterator lowIt = s.lower_bound(3); 存在
  11. lowIt = s.lower_bound(6); 不存在

用途:举例:要求删除>=x的所有值:

  1. void test_set4()
  2. {
  3. set<int> s;
  4. s.insert(4);
  5. s.insert(5);
  6. s.insert(1);
  7. s.insert(3);
  8. s.insert(2);
  9. s.insert(7);
  10. s.insert(9);
  11. for (auto e : s)
  12. {
  13. cout << e << " ";
  14. }
  15. cout << endl;
  16. // 要求删除>=x的所有值
  17. int x;
  18. cin >> x;
  19. set<int>::iterator lowIt = s.lower_bound(x);
  20. s.erase(lowIt, s.end());
  21. for (auto e : s)
  22. {
  23. cout << e << " ";
  24. }
  25. cout << endl;
  26. }

(2)upper_bound 返回>x位置的迭代器

返回>x位置的迭代器,s.upper_bound(5) 存在5,不存在6,则返回7;s.upper_bound(6) 不存在6,返回7;

  1. set<int> s;
  2. s.insert(4);
  3. s.insert(5);
  4. s.insert(1);
  5. s.insert(3);
  6. s.insert(2);
  7. s.insert(7);
  8. s.insert(9);
  9. 返回>x位置的迭代器 -》 都是返回 7位置的迭代器
  10. set<int>::iterator upIt = s.upper_bound(5); // 存在
  11. upIt = s.upper_bound(6); // 不存在

用途:例如 删除x <=  <= y的区间 删除 [x,y]

  1. void test_set4()
  2. {
  3. set<int> s;
  4. s.insert(4);
  5. s.insert(5);
  6. s.insert(1);
  7. s.insert(3);
  8. s.insert(2);
  9. s.insert(7);
  10. s.insert(8);
  11. // 返回>= val得位置迭代器 3返回3位置 6 返回7位置
  12. /*set<int>::iterator lowIt = s.lower_bound(3); 存在
  13. lowIt = s.lower_bound(6); 不存在*/
  14. for (auto e : s)
  15. {
  16. cout << e << " ";
  17. }
  18. cout << endl;
  19. // 删除x <= <= y的区间 删除 [x,y]
  20. int x, y;
  21. cin >> x >> y;
  22. auto leftIt = s.lower_bound(x); // [
  23. auto rightIt = s.upper_bound(y); // )
  24. s.erase(leftIt, rightIt);
  25. for (auto e : s)
  26. {
  27. cout << e << " ";
  28. }
  29. cout << endl;
  30. }

8. std::multiset 跟set接口一样,只是允许冗余,不去重

插入重复的数时set会去重,multiset不去重,允许冗余

不同:

multiset 的count和erase 返回查找或删除个数

find(x) 多个x的话,find返回中序第一个x

  1. void test_set6()
  2. {
  3. multiset<int> s;
  4. s.insert(4);
  5. s.insert(5);
  6. s.insert(2);
  7. s.insert(1);
  8. s.insert(1);
  9. s.insert(3);
  10. s.insert(2);
  11. s.insert(1);
  12. s.insert(3);
  13. s.insert(3);
  14. s.insert(3);
  15. s.insert(3);
  16. // 排序
  17. set<int>::iterator it = s.begin(); //迭代器打印
  18. while (it != s.end())
  19. {
  20. //*it = 10;
  21. cout << *it << " ";
  22. ++it;
  23. }
  24. cout << endl;
  25. for (auto e : s) //范围for打印
  26. {
  27. cout << e << " ";
  28. }
  29. cout << endl;
  30. cout << s.count(1) << endl; //测试count,打印3,因为1有3个
  31. cout << s.erase(1) << endl; //测试erase,打印3,因为1有3个
  32. for (auto e : s)
  33. {
  34. cout << e << " ";
  35. }
  36. cout << endl;
  37. auto pos = s.find(3); // 多个x的话,find返回中序第一个x
  38. while (pos != s.end()) //从中序第一个3开始打印完整个
  39. {
  40. cout << *pos << " ";
  41. ++pos;
  42. }
  43. cout << endl;
  44. }

 

9.set相关题目

349. 两个数组的交集

方法一:把nums1和nums2分别放进s1和s2中进行去重,再利用范围for把s2中的每个元素在s1中进行查找,如果找到就放进v中。时间复杂度是:O(n*logn) n个节点,每个节点找logn高度次

  1. class Solution {
  2. public:
  3. vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
  4. //去重
  5. set<int> s1;
  6. for(auto e:nums1)
  7. {
  8. s1.insert(e);
  9. }
  10. //去重
  11. set<int> s2;
  12. for(auto e:nums2)
  13. {
  14. s2.insert(e);
  15. }
  16. vector<int> v;
  17. for(auto e:s2)
  18. {
  19. if(s1.count(e))
  20. {
  21. v.push_back(e);
  22. }
  23. }
  24. return v;
  25. }
  26. };

方法二:

  1. class Solution {
  2. public:
  3. vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
  4. set<int> s1;
  5. for(auto e:nums1)
  6. {
  7. s1.insert(e);
  8. }
  9. set<int> s2;
  10. for(auto e:nums2)
  11. {
  12. s2.insert(e);
  13. }
  14. vector<int> v;
  15. set<int>::iterator it1=s1.begin();
  16. set<int>::iterator it2=s2.begin();
  17. while(it1!=s1.end() && it2!=s2.end())
  18. {
  19. if(*it1>*it2) //相比较,值小的++
  20. {
  21. ++it2;
  22. }
  23. else if(*it1<*it2) //相比较,值小的++
  24. {
  25. ++it1;
  26. }
  27. else //相比较,值相等就放进v中,同时++
  28. {
  29. v.push_back(*it1);
  30. ++it1;
  31. ++it2;
  32. }
  33. }
  34. return v;
  35. }
  36. };

二.map用法介绍

map是KV模型的搜索二叉树,insert和[]用法是重点,其他用法参考set        #include<map>

几个map和set的冷知识:

map:

①map是C++98中已存在的,unordered_map是C++11中才有的

②map中都重载了[]运算符,multimap中没有重载[]运算符,set也没有重载[]。

原因:map中key是唯一的,每个key都有与之对应的value,经常需要通过key获取value,因此 map为了形象简单 就重载了[]运算符, multimap中key是可以重复的,如果重载了[]运算符,给定 一个key时,就没有办法返回     value了,因此,multimap中没有重载[]运算符

③map中key不能修改,因为如果修改了就不能保证红黑树的有序特性了

set:

①set中也可以存储键值对,实例化set时,将set中元素类型设置为pair即可

②set默认是升序,但是其内部默认不是按照大于比较,而是按照 less小于比较

less是把小的放左边,所以是升序;greater是把大的放左边,所以是降序

map和set查询的时间复杂度都是O(log_2N)

解释:map和set的底层结构都是红黑树,而红黑树是近似的平衡二叉搜索树,故查询时间 复杂度为O(log_2N)

map和set底层都是使用红黑树实现的

1.pair和make_pair

(1)pair键值对 的介绍

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代
表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然
有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应
该单词,在词典中就可以找到与其对应的中文含义。

pair 打包了KV模型的key和val两个类型的值,c++不支持返回两个值,也就不知道返回key和val哪一个了,所以干脆打包key和val,返回一个pair结构

(value_type 是 pair<const key_type,mapped_type>)

pair中的first就相当于KV模型中的key,second相当于KV模型中的val

(2)make_pair 介绍

make_pair 相当于返回了一个pair的匿名对象

2.map的遍历

(1)英汉字典的遍历

几种插入英汉字典的方式:匿名对象插入,普通对象插入,make_pair插入

  1. void test_map1()
  2. {
  3. map<string, string> dict;
  4. // pair构造函数
  5. dict.insert(pair<string, string>("sort", "排序")); //匿名对象插入更便捷
  6. pair<string, string> kv("insert", "插入"); //普通对象插入
  7. dict.insert(kv);
  8. // make_pair
  9. auto ret1 = dict.insert(make_pair("left", "左边")); //make_pair插入
  10. auto ret2 = dict.insert(make_pair("left", "剩余"));
  11. // 遍历
  12. //map<string, string>::iterator it = dict.begin();
  13. auto it = dict.begin();
  14. while (it != dict.end())
  15. {
  16. //cout << *it << " "; // it->operator*()
  17. //cout << (*it).first << ":" << (*it).second << endl;
  18. cout << it->first << ":" << it->second << endl;
  19. ++it;
  20. }
  21. cout << endl;
  22. for (const auto& kv : dict)
  23. {
  24. cout << kv.first << ":" << kv.second << endl;
  25. }
  26. }
  27. int main()
  28. {
  29. test_map1();
  30. return 0;
  31. }

(2)记录水果次数

  1. void test_map2()
  2. {
  3. string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
  4. map<string, int> countMap;
  5. for (auto& str : arr)
  6. {
  7. map<string, int>::iterator it = countMap.find(str);
  8. if (it != countMap.end()) //如果countMap中有,就计数加1
  9. {
  10. it->second++;
  11. }
  12. else
  13. {
  14. countMap.insert(make_pair(str, 1)); //没有就插入水果
  15. }
  16. }
  17. for (auto& str : arr)
  18. {
  19. countMap[str]++;
  20. }
  21. for (const auto& kv : countMap)
  22. {
  23. cout << kv.first << ":" << kv.second << endl;
  24. }
  25. }

3.insert写法提高 记录水果次数 的效率(不这么写,只是为[]做铺垫)

map的insert默认是按照pair中的first进行排序的

 

  1. string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
  2. map<string, int> countMap;
  3. for (auto& str : arr)
  4. {
  5. pair<map<string, int>::iterator, bool> ret = countMap.insert(make_pair(str, 1));
  6. //或者 auto ret = countMap.insert(make_pair(str, 1));
  7. if (ret.second == false)
  8. {
  9. ret.first->second++;
  10. }
  11. }
  12. for (const auto& kv : countMap)
  13. {
  14. cout << kv.first << ":" << kv.second << endl;
  15. }

解释:

pair<map<string, int>::iterator, bool>  ret = countMap.insert(make_pair(str, 1)) 插入节点,若插入成功,ret.first这个iterator 存的是新插入节点的迭代器,ret.second 存的是true;若插入失败,ret.first这个iterator 存的是已有的相同节点的迭代器,ret.second 存的是false;插入失败就再记录个数++就行,ret.first->second++; 用于访问记录水果个数,ret.first 是节点迭代器,ret.first->second++; 节点中的second用于记录对应水果的个数

4.operator[] 运算符重载 

(1) 提高 记录水果次数 的效率的真正写法:

  1. void test_map2()
  2. {
  3. string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
  4. map<string, int> countMap;
  5. for (auto& str : arr)
  6. {
  7. countMap[str]++;
  8. }
  9. for (const auto& kv : countMap)
  10. {
  11. cout << kv.first << ":" << kv.second << endl;
  12. }
  13. }

 

 解释:

 countMap[str]++; 中 countMap[str] 返回的是新插入节点中的 次数second 。

如果插入的str不在 对象countMap中,countMap[str]++; 就是插入这个节点,迭代器就是新节点的迭代器,看原码可知 int类型的次数second用的是缺省值(对应原码中的mapped_typed(),是缺省值 ),所以开始second就是0,++后就是1。作用就是插入并修改val (val意思就是second)。

如果插入的str在 对象countMap中,countMap[str]++; 就是查找到这个节点,迭代器就是已有节点的迭代器,int类型的次数second在第一次已经是1了,++后就是2。作用就是插入并修改val (val意思就是second,用于计水果次数)。

(2) 字典中利用[]插入或修改 示例

  1. void test_map1()
  2. {
  3. map<string, string> dict;
  4. // pair构造函数
  5. dict.insert(pair<string, string>("sort", "排序"));
  6. pair<string, string> kv("insert", "插入");
  7. dict.insert(kv);
  8. // make_pair
  9. auto ret1 = dict.insert(make_pair("left", "左边"));
  10. auto ret2 = dict.insert(make_pair("left", "剩余"));
  11. dict["operator"] = "重载"; // 插入+修改
  12. dict["left"] = "左边、剩余"; // 修改
  13. dict["erase"]; // 插入
  14. cout << dict["left"] << endl; // 查找
  15. }

5.multimap 允许键值冗余

相比map,multimap使用函数接口最大的区别是什么?
答:不支持operator[] 。

三.相关题目

1.692. 前K个高频单词

(1)做法一:stable_sort稳定排序

把map中的pair放到v中再用stable_sort稳定排序,再把各个pair对应的first放到vv中,再输出vv

  1. class Solution {
  2. public:
  3. typedef map<string,int>::iterator CountIter;
  4. struct less
  5. {
  6. bool operator()(const pair<string,int>& x,const pair<string,int>& y)
  7. {
  8. return x.second>y.second;
  9. }
  10. };
  11. vector<string> topKFrequent(vector<string>& words, int k) {
  12. map<string,int> countMap;
  13. for(auto& str:words)
  14. {
  15. countMap[str]++;
  16. }
  17. vector<pair<string,int>> v;
  18. CountIter it=countMap.begin();
  19. while(it!=countMap.end())
  20. {
  21. //cout<<it->first<<" "<<it->second<<endl;
  22. v.push_back(*it);
  23. ++it;
  24. }
  25. stable_sort(v.begin(),v.end(),less()); //stable_sort稳定排序
  26. vector<string> vv;
  27. for(int i=0;i<k;i++)
  28. {
  29. vv.push_back(v[i].first);
  30. }
  31. for(auto e:v)
  32. {
  33. cout<<e.first<<" "<<e.second<<endl;
  34. }
  35. return vv;
  36. }
  37. };

(2)做法二:stable_sort稳定排序 2

与做法一不同的是:pair很大,为了减少拷贝,我们可以选择不拷贝pair而是拷贝迭代器,把map中的迭代器放到v中,比较方法中通过迭代器找到second,再用stable_sort稳定排序这些迭代器,再把各个迭代器对应的first放到vv中,再输出vv

自己敲的:

  1. class Solution {
  2. public:
  3. typedef map<string,int>::iterator CountIter;
  4. struct less //降序
  5. {
  6. bool operator()(const CountIter& x,const CountIter& y)
  7. {
  8. return x->second > y->second;
  9. }
  10. };
  11. vector<string> topKFrequent(vector<string>& words, int k) {
  12. map<string,int> countMap;
  13. for(auto& str:words)
  14. {
  15. countMap[str]++;
  16. }
  17. vector<CountIter> v;
  18. CountIter it=countMap.begin();
  19. while(it!=countMap.end())
  20. {
  21. //cout<<it->first<<" "<<it->second<<endl;
  22. v.push_back(it);
  23. ++it;
  24. }
  25. stable_sort(v.begin(),v.end(),less()); //stable_sort稳定排序
  26. for(auto e:v)
  27. {
  28. cout<<e->first<<" "<<e->second<<endl;
  29. }
  30. vector<string> vv;
  31. for(int i=0;i<k;i++)
  32. {
  33. vv.push_back(v[i]->first);
  34. }
  35. return vv;
  36. }
  37. };

(3)做法三:sort 非稳定排序,可以控制比较方法使其稳定

相比较上面的方法,把stable_sort换成sort后,只需要控制比较方法即可使其稳定:因为map中默认是按照分first小的在前排序的,sort 时我们设计的比较方法是按second排序的,但是当second相等时,sort有可能打乱之前map中按 first 排的先后顺序,这样就是不稳定。我们只需要比较方法中让second相等时的情况再按first小的在前排好就可以达到稳定的目的。(相等时会多比一下first,会影响一点效率)

自己敲的:

 (4)做法四:利用map自身按照first排序

map的insert默认是按照pair中的first进行排序的,因此我们可以创建一个sortMap,int对应first,string对应second,然后一个一个从kv中插入进sortMap(kv中的first和second颠倒一下插入进去),因为map默认去掉重复的first,这样会导致把次数重复的元素去掉(因为次数放在了first位置),因此要用允许重复的multimap,插入顺序map默认是less降序,因为是top-k问题,我们要把map中插入顺序改成升序插入greater<int>。

  1. class Solution {
  2. public:
  3. vector<string> topKFrequent(vector<string>& words, int k) {
  4. map<string,int> countMap;
  5. for(auto& str:words)
  6. {
  7. countMap[str]++;
  8. }
  9. //排序
  10. multimap<int,string,greater<int>> sortMap;
  11. for(auto& kv:countMap)
  12. {
  13. sortMap.insert(make_pair(kv.second,kv.first));
  14. }
  15. // auto it=sortMap.begin();
  16. // while(it!=sortMap.end())
  17. // {
  18. // cout<<it->first<<" "<<it->second<<endl;
  19. // ++it;
  20. // }
  21. vector<string> vv;
  22. auto it=sortMap.begin();
  23. for(int i=0;i<k;i++)
  24. {
  25. vv.push_back(it->second);
  26. ++it;
  27. }
  28. return vv;
  29. }
  30. };

官方写法:

四.用红黑树模拟实现map,set

重点:

struct SetKeyOfT 仿函数,用于在RBTree.h找到map/set中所要比较的值,用于控制RBTree.h中pair类型的比较方法,因为库中的pair类型 先比first再比second 的比较方法不是我们想要的

Map.h

  1. #pragma once
  2. #include "RBTree.h"
  3. namespace bit
  4. {
  5. template<class K, class V>
  6. class map
  7. {
  8. struct MapKeyOfT
  9. {
  10. const K& operator()(const pair<K, V>& kv)
  11. {
  12. return kv.first;
  13. }
  14. };
  15. public:
  16. typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
  17. typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::const_iterator const_iterator;
  18. iterator begin()
  19. {
  20. return _t.Begin();
  21. }
  22. iterator end()
  23. {
  24. return _t.End();
  25. }
  26. pair<iterator, bool> insert(const pair<K, V>& kv)
  27. {
  28. return _t.Insert(kv);
  29. }
  30. iterator find(const K& key)
  31. {
  32. return _t.Find(key);
  33. }
  34. V& operator[](const K& key)
  35. {
  36. pair<iterator, bool> ret = insert(make_pair(key, V()));
  37. return ret.first->second;
  38. }
  39. private:
  40. RBTree<K, pair<K, V>, MapKeyOfT> _t;
  41. };
  42. void test_map1()
  43. {
  44. map<string, int> m;
  45. m.insert(make_pair("111", 1));
  46. m.insert(make_pair("555", 5));
  47. m.insert(make_pair("333", 3));
  48. m.insert(make_pair("222", 2));
  49. map<string, int>::iterator it = m.begin();
  50. while (it != m.end())
  51. {
  52. cout << it->first << ":" << it->second << endl;
  53. ++it;
  54. }
  55. cout << endl;
  56. for (auto& kv : m)
  57. {
  58. cout << kv.first << ":" << kv.second << endl;
  59. }
  60. cout << endl;
  61. }
  62. void test_map2()
  63. {
  64. string arr[] = { "ƻ", "", "ƻ", "", "ƻ", "ƻ", "", "ƻ", "㽶", "ƻ", "㽶" };
  65. map<string, int> countMap;
  66. for (auto& str : arr)
  67. {
  68. countMap[str]++;
  69. }
  70. for (const auto& kv : countMap)
  71. {
  72. cout << kv.first << ":" << kv.second << endl;
  73. }
  74. }
  75. void test_map3()
  76. {
  77. map<string, string> dict;
  78. dict["insert"];
  79. dict["insert"] = "";
  80. dict["left"] = "";
  81. }
  82. }

Set.h

  1. #pragma once
  2. #include "RBTree.h"
  3. namespace bit
  4. {
  5. template<class K>
  6. class set
  7. {
  8. struct SetKeyOfT
  9. {
  10. const K& operator()(const K& key)
  11. {
  12. return key;
  13. }
  14. };
  15. public:
  16. typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
  17. typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
  18. iterator begin() const //set内容不想被修改(key值不修改),则给this设置const,
  19. { //调用时会调用带const的Begin()
  20. return _t.Begin();
  21. }
  22. iterator end() const
  23. {
  24. return _t.End();
  25. }
  26. pair<iterator, bool> insert(const K& key)
  27. {
  28. //pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);
  29. auto ret = _t.Insert(key);
  30. return pair<iterator, bool>(iterator(ret.first._node), ret.second);
  31. }
  32. iterator find(const K& key)
  33. {
  34. return _t.Find(key);
  35. }
  36. private:
  37. RBTree<K, K, SetKeyOfT> _t;
  38. };
  39. void test_set1()
  40. {
  41. set<int> s;
  42. s.insert(8);
  43. s.insert(6);
  44. s.insert(11);
  45. s.insert(5);
  46. s.insert(6);
  47. s.insert(7);
  48. s.insert(10);
  49. s.insert(13);
  50. s.insert(12);
  51. s.insert(15);
  52. set<int>::iterator it = s.begin();
  53. while (it != s.end())
  54. {
  55. cout << *it << " ";
  56. ++it;
  57. }
  58. cout << endl;
  59. for (auto e : s)
  60. {
  61. cout << e << " ";
  62. }
  63. cout << endl;
  64. }
  65. }

RBTree.h

  1. pragma once
  2. enum Colour
  3. {
  4. RED,
  5. BLACK,
  6. };
  7. template<class T>
  8. struct RBTreeNode
  9. {
  10. RBTreeNode<T>* _left;
  11. RBTreeNode<T>* _right;
  12. RBTreeNode<T>* _parent;
  13. T _data; // 数据
  14. Colour _col;
  15. RBTreeNode(const T& data)
  16. :_data(data)
  17. , _left(nullptr)
  18. , _right(nullptr)
  19. , _parent(nullptr)
  20. , _col(RED)
  21. {}
  22. };
  23. template<class T, class Ref, class Ptr>
  24. struct __RBTreeIterator
  25. {
  26. typedef RBTreeNode<T> Node;
  27. typedef __RBTreeIterator<T, Ref, Ptr> Self;
  28. Node* _node;
  29. __RBTreeIterator(Node* node)
  30. :_node(node)
  31. {}
  32. Ref operator*()
  33. {
  34. return _node->_data;
  35. }
  36. Ptr operator->()
  37. {
  38. return &_node->_data;
  39. }
  40. // 休息17:00
  41. Self& operator++() //中序遍历
  42. {
  43. if (_node->_right == nullptr) //当前节点的右节点为空
  44. {
  45. // 就找祖先里面,孩子是父亲左的那个父亲
  46. Node* cur = _node;
  47. Node* parent = cur->_parent;
  48. while (parent && parent->_right == cur)
  49. { //只要这个父亲的孩子不是父亲的左,就继续往上找
  50. cur = cur->_parent;
  51. parent = parent->_parent;
  52. }
  53. //直到这个父亲的孩子是父亲的左,这个父亲就是该++走到的节点
  54. _node = parent;
  55. }
  56. else //当前节点的右节点不为空
  57. {
  58. // 就走完右子树的最左节点
  59. Node* subLeft = _node->_right;
  60. while (subLeft->_left)
  61. {
  62. subLeft = subLeft->_left;
  63. }
  64. _node = subLeft;
  65. }
  66. return *this;
  67. }
  68. Self operator++(int)
  69. {
  70. Self tmp(*this);
  71. ++(*this);
  72. return tmp;
  73. }
  74. Self& operator--()
  75. {
  76. if (_node->_left == nullptr)
  77. {
  78. // 找祖先里面,孩子是父亲
  79. Node* cur = _node;
  80. Node* parent = cur->_parent;
  81. while (parent && cur == parent->_left)
  82. {
  83. cur = cur->_parent;
  84. parent = parent->_parent;
  85. }
  86. _node = parent;
  87. }
  88. else
  89. {
  90. // 左子树的最右节点
  91. Node* subRight = _node->_left;
  92. while (subRight->_right)
  93. {
  94. subRight = subRight->_right;
  95. }
  96. _node = subRight;
  97. }
  98. return *this;
  99. }
  100. Self operator--(int)
  101. {
  102. Self tmp(*this);
  103. --(*this);
  104. return tmp;
  105. }
  106. bool operator!=(const Self& s) const
  107. {
  108. return _node != s._node;
  109. }
  110. bool operator==(const Self& s) const
  111. {
  112. return _node == s->_node;
  113. }
  114. };
  115. // T决定红黑树存什么数据
  116. // set RBTree<K, K>
  117. // map RBTree<K, pair<K, V>>
  118. // KeyOfT -> 支持取出T对象中key的仿函数
  119. template<class K, class T, class KeyOfT>
  120. class RBTree
  121. {
  122. typedef RBTreeNode<T> Node;
  123. public:
  124. typedef __RBTreeIterator<T, T&, T*> iterator;
  125. typedef __RBTreeIterator<T, const T&, const T*> const_iterator;
  126. // 构造 拷贝构造 赋值 和析构 跟搜索树实现方式是一样的
  127. iterator Begin()
  128. {
  129. Node* subLeft = _root;
  130. while (subLeft && subLeft->_left)
  131. {
  132. subLeft = subLeft->_left;
  133. }
  134. return iterator(subLeft);
  135. }
  136. iterator End()
  137. {
  138. return iterator(nullptr);
  139. }
  140. const_iterator Begin() const
  141. {
  142. Node* subLeft = _root;
  143. while (subLeft && subLeft->_left)
  144. {
  145. subLeft = subLeft->_left;
  146. }
  147. return const_iterator(subLeft);
  148. }
  149. const_iterator End() const
  150. {
  151. return const_iterator(nullptr);
  152. }
  153. pair<iterator, bool> Insert(const T& data)
  154. {
  155. // 1、搜索树的规则插入
  156. // 2、看是否违反平衡规则,如果违反就需要处理:旋转
  157. if (_root == nullptr)
  158. {
  159. _root = new Node(data);
  160. _root->_col = BLACK;
  161. return make_pair(iterator(_root), true);
  162. }
  163. KeyOfT kot;
  164. Node* parent = nullptr;
  165. Node* cur = _root;
  166. while (cur)
  167. {
  168. if (kot(cur->_data) < kot(data))
  169. {
  170. parent = cur;
  171. cur = cur->_right;
  172. }
  173. else if (kot(cur->_data) > kot(data))
  174. {
  175. parent = cur;
  176. cur = cur->_left;
  177. }
  178. else
  179. {
  180. return make_pair(iterator(cur), true);
  181. }
  182. }
  183. cur = new Node(data);
  184. Node* newnode = cur;
  185. cur->_col = RED;
  186. if (kot(parent->_data) < kot(data))
  187. {
  188. parent->_right = cur;
  189. }
  190. else
  191. {
  192. parent->_left = cur;
  193. }
  194. cur->_parent = parent;
  195. // 存在连续红色节点
  196. while (parent && parent->_col == RED)
  197. {
  198. Node* grandfater = parent->_parent;
  199. assert(grandfater);
  200. if (grandfater->_left == parent)
  201. {
  202. Node* uncle = grandfater->_right;
  203. // 情况一:
  204. if (uncle && uncle->_col == RED) // 叔叔存在且为红
  205. {
  206. // 变色
  207. parent->_col = uncle->_col = BLACK;
  208. grandfater->_col = RED;
  209. // 继续往上处理
  210. cur = grandfater;
  211. parent = cur->_parent;
  212. }
  213. else // 叔叔不存在 或者 叔叔存在且为黑
  214. {
  215. if (cur == parent->_left) // 单旋
  216. {
  217. // g
  218. // p
  219. // c
  220. RotateR(grandfater);
  221. parent->_col = BLACK;
  222. grandfater->_col = RED;
  223. }
  224. else // 双旋
  225. {
  226. // g
  227. // p
  228. // c
  229. RotateL(parent);
  230. RotateR(grandfater);
  231. cur->_col = BLACK;
  232. grandfater->_col = RED;
  233. }
  234. break;
  235. }
  236. }
  237. else //(grandfater->_right == parent)
  238. {
  239. Node* uncle = grandfater->_left;
  240. // 情况一:
  241. if (uncle && uncle->_col == RED)
  242. {
  243. // 变色
  244. parent->_col = uncle->_col = BLACK;
  245. grandfater->_col = RED;
  246. // 继续往上处理
  247. cur = grandfater;
  248. parent = cur->_parent;
  249. }
  250. else
  251. {
  252. if (cur == parent->_right)
  253. {
  254. // g
  255. // p
  256. // c
  257. RotateL(grandfater);
  258. parent->_col = BLACK;
  259. grandfater->_col = RED;
  260. }
  261. else // 双旋
  262. {
  263. // g
  264. // p
  265. // c
  266. RotateR(parent);
  267. RotateL(grandfater);
  268. cur->_col = BLACK;
  269. grandfater->_col = RED;
  270. }
  271. break;
  272. }
  273. }
  274. }
  275. _root->_col = BLACK;
  276. return make_pair(iterator(newnode), true);
  277. }
  278. void RotateL(Node* parent)
  279. {
  280. Node* subR = parent->_right;
  281. Node* subRL = subR->_left;
  282. parent->_right = subRL;
  283. if (subRL)
  284. subRL->_parent = parent;
  285. Node* ppNode = parent->_parent;
  286. subR->_left = parent;
  287. parent->_parent = subR;
  288. if (parent == _root)
  289. {
  290. _root = subR;
  291. _root->_parent = nullptr;
  292. }
  293. else
  294. {
  295. if (parent == ppNode->_left)
  296. {
  297. ppNode->_left = subR;
  298. }
  299. else
  300. {
  301. ppNode->_right = subR;
  302. }
  303. subR->_parent = ppNode;
  304. }
  305. }
  306. void RotateR(Node* parent)
  307. {
  308. Node* subL = parent->_left;
  309. Node* subLR = subL->_right;
  310. parent->_left = subLR;
  311. if (subLR)
  312. subLR->_parent = parent;
  313. Node* ppNode = parent->_parent;
  314. subL->_right = parent;
  315. parent->_parent = subL;
  316. if (parent == _root)
  317. {
  318. _root = subL;
  319. _root->_parent = nullptr;
  320. }
  321. else
  322. {
  323. if (ppNode->_left == parent)
  324. {
  325. ppNode->_left = subL;
  326. }
  327. else
  328. {
  329. ppNode->_right = subL;
  330. }
  331. subL->_parent = ppNode;
  332. }
  333. }
  334. iterator Find(const K& key)
  335. {
  336. Node* cur = _root;
  337. KeyOfT kot;
  338. while (cur)
  339. {
  340. if (kot(cur->_data) < key)
  341. {
  342. cur = cur->_right;
  343. }
  344. else if (kot(cur->_data) > key)
  345. {
  346. cur = cur->_left;
  347. }
  348. else
  349. {
  350. return iterator(cur);
  351. }
  352. }
  353. return End();
  354. }
  355. private:
  356. Node* _root = nullptr;
  357. };

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/202047
推荐阅读
相关标签
  

闽ICP备14008679号