• C++:map和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

    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::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和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

    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 dict;
    4. // pair构造函数
    5. dict.insert(pair("sort", "排序")); //匿名对象插入更便捷
    6. pair 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::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. mapint> countMap;
    5. for (auto& str : arr)
    6. {
    7. mapint>::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. mapint> countMap;
    3. for (auto& str : arr)
    4. {
    5. pairint>::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::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. mapint> 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 dict;
    4. // pair构造函数
    5. dict.insert(pair("sort", "排序"));
    6. pair 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 mapint>::iterator CountIter;
    4. struct less
    5. {
    6. bool operator()(const pairint>& x,const pairint>& y)
    7. {
    8. return x.second>y.second;
    9. }
    10. };
    11. vector topKFrequent(vector& words, int k) {
    12. mapint> countMap;
    13. for(auto& str:words)
    14. {
    15. countMap[str]++;
    16. }
    17. vectorint>> v;
    18. CountIter it=countMap.begin();
    19. while(it!=countMap.end())
    20. {
    21. //cout<first<<" "<second<
    22. v.push_back(*it);
    23. ++it;
    24. }
    25. stable_sort(v.begin(),v.end(),less()); //stable_sort稳定排序
    26. vector vv;
    27. for(int i=0;i
    28. {
    29. vv.push_back(v[i].first);
    30. }
    31. for(auto e:v)
    32. {
    33. cout<" "<
    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 mapint>::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 topKFrequent(vector& words, int k) {
    12. mapint> countMap;
    13. for(auto& str:words)
    14. {
    15. countMap[str]++;
    16. }
    17. vector v;
    18. CountIter it=countMap.begin();
    19. while(it!=countMap.end())
    20. {
    21. //cout<first<<" "<second<
    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<first<<" "<second<
    29. }
    30. vector vv;
    31. for(int i=0;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

    1. class Solution {
    2. public:
    3. vector topKFrequent(vector& words, int k) {
    4. mapint> 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<first<<" "<second<
    19. // ++it;
    20. // }
    21. vector vv;
    22. auto it=sortMap.begin();
    23. for(int i=0;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& kv)
    11. {
    12. return kv.first;
    13. }
    14. };
    15. public:
    16. typedef typename RBTree, MapKeyOfT>::iterator iterator;
    17. typedef typename RBTree, MapKeyOfT>::const_iterator const_iterator;
    18. iterator begin()
    19. {
    20. return _t.Begin();
    21. }
    22. iterator end()
    23. {
    24. return _t.End();
    25. }
    26. pairbool> insert(const pair& 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. pairbool> ret = insert(make_pair(key, V()));
    37. return ret.first->second;
    38. }
    39. private:
    40. RBTree, MapKeyOfT> _t;
    41. };
    42. void test_map1()
    43. {
    44. mapint> 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. mapint>::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. mapint> 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 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::const_iterator iterator;
    17. typedef typename RBTree::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. pairbool> insert(const K& key)
    27. {
    28. //pair::iterator, bool> ret = _t.Insert(key);
    29. auto ret = _t.Insert(key);
    30. return pairbool>(iterator(ret.first._node), ret.second);
    31. }
    32. iterator find(const K& key)
    33. {
    34. return _t.Find(key);
    35. }
    36. private:
    37. RBTree _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* _left;
    11. RBTreeNode* _right;
    12. RBTreeNode* _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 Node;
    27. typedef __RBTreeIterator 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
    117. // map RBTree>
    118. // KeyOfT -> 支持取出T对象中key的仿函数
    119. template<class K, class T, class KeyOfT>
    120. class RBTree
    121. {
    122. typedef RBTreeNode Node;
    123. public:
    124. typedef __RBTreeIterator iterator;
    125. typedef __RBTreeIteratorconst 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. pairbool> 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. };

  • 相关阅读:
    python3读取yaml文件
    [ jquery 选择器 :nth-of-type() ] 选取指定类型(p)父元素下的第几个子元素
    扬帆起航:CCF开源发展论坛在深举办
    Idea部署dubbo-admin
    深入解读GLIDE/PITI代码
    零数科技荣获2022金融科技创新引领奖
    大数据Doris(二):Doris原理篇
    [思维]Yet Another Problem Codeforces1747D
    MMLAB系列:MMCLS基本操作
    企业安全—SDL概述篇
  • 原文地址:https://blog.csdn.net/zhang_si_hang/article/details/126398107