• 19.set和map


    目录

    1.关联式容器

    2.set(key模型)

    2.1set

    2.2mutiset

    3.map(key 、value模型)

    4.AVL树

    4.1AVL树的概念

    4.2AVL树的实现

    5.红黑树

    5.1红黑树的概念

    5.2红黑树的性质

    5.3红黑树的实现

    6.set和map的模拟实现


    1.关联式容器

    序列是容器:vector、list、deque、forward_list等,主要用来存储数据的。

    关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是结构的键值对,在数据检索时比序列式容器效率更高。

    键值对:用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的消息。

    2.set(key模型)

    2.1set

    set是去重+排序

    1.insert 插入函数以及迭代器:

    1. #include
    2. #include
    3. using namespace std;
    4. void test1()
    5. {
    6. set<int> s;
    7. s.insert(1);
    8. s.insert(3);
    9. s.insert(2);
    10. s.insert(4);
    11. s.insert(5);
    12. //插入两个相等值时,直接去重
    13. s.insert(6);
    14. s.insert(6);
    15. s.insert(8);
    16. //迭代器 为中序
    17. set<int>::iterator it = s.begin();
    18. while (it != s.end())
    19. {
    20. cout << *it << " ";
    21. ++it;
    22. }
    23. cout << endl;
    24. }
    25. int main()
    26. {
    27. test1();
    28. return 0;
    29. }

    迭代器默认打印就是中序打印: 

    2.erase 删除函数

    值删除和迭代器删除的区别:

    size_type erase (const value_type& val);

    会返回一个size_type,是一个无符号整数,返回删除的数据个数。

    在set传值删除的时候,只有1或0.

    1. #include
    2. #include
    3. using namespace std;
    4. void test2()
    5. {
    6. set<int> s;
    7. s.insert(1);
    8. s.insert(3);
    9. s.insert(2);
    10. s.insert(4);
    11. s.insert(5);
    12. s.insert(6);
    13. s.insert(8);
    14. //迭代器删除
    15. set<int>::iterator pos = s.find(3);
    16. if (pos!=s.end()) //这里是必须检查的,必须保证迭代器有效
    17. {
    18. s.erase(pos);
    19. }
    20. //set::iterator pos = s.find(30);
    21. //s.erase(pos); //这里删除30 不存在的,迭代器失效会报错的
    22. //直接值删除,是不用考虑迭代器失效的问题
    23. //当值存在时我就删除。当值不存在时我也不会报错,不会删除。
    24. s.erase(30);//这里不会报错,值不存在就不删除,相当于封装了一个迭代器检查if (pos!=s.end())
    25. s.erase(8);
    26. for (auto e : s)
    27. {
    28. cout << e << " ";
    29. }
    30. cout << endl;
    31. }
    32. int main()
    33. {
    34. test2();
    35. return 0;
    36. }

     

    3.swap

     这个函数交换的是两个对象的根节点指针。

    2.2mutiset

    仅排序(不去重)

     1.插入函数

    1. #include
    2. #include
    3. using namespace std;
    4. void test3()
    5. {
    6. //排序
    7. multiset<int> s;
    8. s.insert(1);
    9. s.insert(3);
    10. s.insert(2);
    11. s.insert(4);
    12. s.insert(5);
    13. s.insert(6);
    14. s.insert(6);
    15. s.insert(6);
    16. s.insert(8);
    17. for (auto e : s)
    18. {
    19. cout << e << " ";
    20. }
    21. cout << endl;
    22. }
    23. int main()
    24. {
    25. test3();
    26. return 0;
    27. }

    2.erase删除函数

     当有多个相同的值时:find返回中序的第一个值。

    1. #include
    2. #include
    3. using namespace std;
    4. void test3()
    5. {
    6. //排序
    7. multiset<int> s;
    8. s.insert(1);
    9. s.insert(1);
    10. s.insert(1);
    11. s.insert(3);
    12. s.insert(2);
    13. s.insert(4);
    14. s.insert(5);
    15. s.insert(5);
    16. //find的val有多个值时,返回中序第一个val值所在节点的迭代器。
    17. multiset<int>::iterator pos = s.find(5);
    18. while (pos!=s.end())
    19. {
    20. cout << *pos << " ";
    21. ++pos;
    22. }
    23. cout << endl;
    24. for (auto e : s)
    25. {
    26. cout << e << " ";
    27. }
    28. cout << endl;
    29. }
    30. int main()
    31. {
    32. test3();
    33. return 0;
    34. }

    如果我想删除所有的1这个值呢?

    使用迭代器:

    1. #include
    2. #include
    3. using namespace std;
    4. void test3()
    5. {
    6. //排序
    7. multiset<int> s;
    8. s.insert(1);
    9. s.insert(1);
    10. s.insert(1);
    11. s.insert(3);
    12. s.insert(2);
    13. s.insert(4);
    14. s.insert(5);
    15. s.insert(5);
    16. //find的val有多个值时,返回中序第一个val值所在节点的迭代器。
    17. multiset<int>::iterator pos = s.find(1);
    18. while (pos!=s.end() && *pos==1)
    19. {
    20. auto next = pos;
    21. ++next;
    22. s.erase(pos); //删除所有的1
    23. pos = next;
    24. }
    25. for (auto e : s)
    26. {
    27. cout << e << " ";
    28. }
    29. cout << endl;
    30. }
    31. int main()
    32. {
    33. test3();
    34. return 0;
    35. }

    使用值删除时最方便的,它会自己删除所有等于1的节点:会返回删除数据的个数。它其实是对上面迭代器的封装。

    1. #include
    2. #include
    3. using namespace std;
    4. void test3()
    5. {
    6. //排序
    7. multiset<int> s;
    8. s.insert(1);
    9. s.insert(1);
    10. s.insert(1);
    11. s.insert(3);
    12. s.insert(2);
    13. s.insert(4);
    14. s.insert(5);
    15. s.insert(5);
    16. cout << s.erase(1)<//这里会返回删除1的个数
    17. for (auto e : s)
    18. {
    19. cout << e << " ";
    20. }
    21. cout << endl;
    22. }
    23. int main()
    24. {
    25. test3();
    26. return 0;
    27. }

    set能否借助迭代器进行节点值的修改呢?

    1. #include
    2. #include
    3. using namespace std;
    4. void test3()
    5. {
    6. //排序
    7. multiset<int> s;
    8. s.insert(1);
    9. s.insert(1);
    10. s.insert(1);
    11. s.insert(3);
    12. s.insert(2);
    13. s.insert(4);
    14. s.insert(5);
    15. s.insert(5);
    16. auto pos = s.find(1);
    17. if (pos != s.end())
    18. {
    19. *pos += 10;//这里是不能进行修改的,如果修改了有可能破坏搜索二叉树,因此这里去调用operator*()的时候,返回的是const 的引用
    20. }
    21. for (auto e : s)
    22. {
    23. cout << e << " ";
    24. }
    25. cout << endl;
    26. }
    27. int main()
    28. {
    29. test3();
    30. return 0;
    31. }

    直接标红报错:

    3.map(key 、value模型)

    在map里面不是存的两个值key和value,而是有进行了一层的封装,封装了一层类(结构体) ,map里面存的就是一个对象。封装的这个结构体就是pair,pair里面有2个值。

    1.插入函数

     pair的构造函数:

     make_pair:对pair的封装,是函数模板

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. void test1()
    6. {
    7. map dict;
    8. //直接创建pair对象,就行插入
    9. pair kv1("sort","排序");
    10. dict.insert(kv1);
    11. //创建匿名对象插入
    12. dict.insert(pair("left","左"));
    13. //使用make_pair,可以自动推导类型
    14. dict.insert(make_pair("string","字符串"));//常用
    15. //map::iterator it = dict.begin();
    16. auto it = dict.begin();
    17. while (it!=dict.end())
    18. {
    19. //cout << *it << " "; //去调用*重载,_node->value_type 去调用pair结构体,结构体没有重载流提取,因此不行
    20. //cout << (*it).first << ':' << (*it).second <
    21. //最好使用-> 看起来就知道是个自定义类型的数据
    22. cout << it->first << ':' << it->second << endl;
    23. ++it;
    24. }
    25. cout << endl;
    26. //支持迭代器,就支持范围for
    27. for (auto & kv : dict) //最好使用引用,存在拷贝构造
    28. {
    29. //kv=*it
    30. cout << kv.first << ':' << kv.second << endl;
    31. }
    32. }
    33. int main()
    34. {
    35. test1();
    36. return 0;
    37. }

    其他函数和set的基本差不多的。省略

    2.水果统计次数

    第一种代码:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. void test2()
    6. {
    7. string arr[] = { "苹果", "香蕉", "草莓", "樱桃", "香蕉", "苹果" };
    8. mapint> countMap;
    9. //map的key不支持修改,但是value是支持修改的
    10. for (auto& str:arr)
    11. {
    12. auto ret = countMap.find(str);
    13. if (ret==countMap.end())
    14. {
    15. //没有对应的水果,就插入
    16. countMap.insert(make_pair(str,1));
    17. }
    18. else
    19. {
    20. //有对应的水果就次数+1
    21. ret->second++;
    22. }
    23. }
    24. for (auto & kv : countMap)
    25. {
    26. //kv=*it
    27. cout << kv.first << ':' << kv.second << endl;
    28. }
    29. }
    30. int main()
    31. {
    32. test2();
    33. return 0;
    34. }

    上面的代码比较冗余:你find查找了依次,若是没有查找到,insert又去查找了依次,所以查找了2次。

    对代码进行优化:

    insert函数的返回值,是一个pair对象

    insert函数的返回值,是一个pair对象,如果插入的元素或该元素与map中的key相等,那么就返回这个节点的迭代器,pair的first存储这个迭代器。pair的second 存储bool值,当插入一个新节点,则返回true,若是map中存在该key,那么就返回false。

    代码改进:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. void test3()
    6. {
    7. string arr[] = { "苹果", "香蕉", "草莓", "樱桃", "香蕉", "苹果" };
    8. mapint> countMap;
    9. for (auto &str : arr)
    10. {
    11. //pair::iterator, bool> ret = countMap.insert(make_pair(str, 1));
    12. auto ret = countMap.insert(make_pair(str, 1));
    13. if (ret.second==false)//说明这个节点key存在了
    14. {
    15. ret.first->second++; //次数+1,这里去调用迭代器中的operator->()重载
    16. }
    17. }
    18. for (auto & kv : countMap)
    19. {
    20. //kv=*it
    21. cout << kv.first << ':' << kv.second << endl;
    22. }
    23. }
    24. int main()
    25. {
    26. test3();
    27. return 0;
    28. }

    方括号:

    这里是去调用insert,返回一个pair的对象,pair对象中第一个first存的map是迭代器,*这个迭代器,会去调用迭代器的*重载,找到map节点的value_type(pair对象), .second 取第二个值。

     返回值是mapped_type& ,这里是引用,对pair对象第二个变量(value)的引用。

     对代码改进:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. void test3()
    6. {
    7. string arr[] = { "苹果", "香蕉", "草莓", "樱桃", "香蕉", "苹果" };
    8. mapint> countMap;
    9. for (auto &str : arr)
    10. {
    11. countMap[str]++; //直接取调用operator[]
    12. }
    13. for (auto & kv : countMap)
    14. {
    15. //kv=*it
    16. cout << kv.first << ':' << kv.second << endl;
    17. }
    18. }
    19. int main()
    20. {
    21. test3();
    22. return 0;
    23. }

    [ ]的功能:1.插入2.查找3.修改(value的值)

    1. void test4()
    2. {
    3. mapdict;
    4. dict.insert(make_pair("sort","排序"));
    5. dict.insert(make_pair("left", "左边"));
    6. dict.insert(make_pair("left", "剩余"));//不会插入
    7. dict["left"] = "剩余"; //修改
    8. dict["test"]; //插入
    9. cout << dict["sort"] << endl;//查找
    10. dict["string"] = "字符串"; //插入+修改
    11. }
    12. int main()
    13. {
    14. test4();
    15. return 0;
    16. }

    multimap 用法基本都是差不多的,key相同也会插入。

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. void test5()
    6. {
    7. multimapdict;
    8. dict.insert(make_pair("sort", "排序"));
    9. dict.insert(make_pair("left", "左边"));
    10. dict.insert(make_pair("left", "剩余"));//会插入
    11. dict.insert(make_pair("left", "向左"));
    12. cout << dict.count("left") << endl;//查找次数
    13. auto it = dict.begin();
    14. while (it!=dict.end())
    15. {
    16. cout << it->first<<':'<second << endl;
    17. ++it;
    18. }
    19. cout << endl;
    20. }
    21. int main()
    22. {
    23. test5();
    24. return 0;
    25. }

    3.排序

    找出前K个最喜欢吃的水果

    1.利用sort

    第一种写法:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. //提供一个仿函数
    8. struct CountVal
    9. {
    10. bool operator()(const pairint>& p1,const pairint>& p2)
    11. {
    12. return p1.second > p2.second;
    13. }
    14. };
    15. void GetFavoriteFruit1(const vector& fruits, size_t k)
    16. {
    17. mapint> coutMap;
    18. for (auto& str:fruits)
    19. {
    20. coutMap[str]++;//统计次数
    21. }
    22. //找前k个
    23. vectorint>> Vsort;
    24. for (auto& e : coutMap)
    25. {
    26. Vsort.push_back(e);
    27. }
    28. //因为sort是随机迭代器,而map是双向迭代器,不行的,所以必须使用vector<>
    29. sort(Vsort.begin(), Vsort.end(), CountVal()); //pair提供了排序,但是不是我们想要的。需要自己写仿函数,排降序
    30. for (size_t i = 0; i < k;i++)
    31. {
    32. cout << Vsort[i].first << ':' << Vsort[i].second << endl;
    33. }
    34. cout << endl;
    35. }
    36. int main()
    37. {
    38. vector v = { "苹果", "苹果", "香蕉", "草莓", "草莓", "苹果", "苹果", "樱桃", "香蕉","葡萄"};
    39. GetFavoriteFruit1(v,3);
    40. return 0;
    41. }

    pair提供的排序,不适合我们这里

    第一种写法存在大量的深拷贝,因此使用存迭代器,继续改进第二种:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. //提供一个仿函数
    8. struct CountVal
    9. {
    10. bool operator()(mapint>::iterator& it1, mapint>::iterator& it2)
    11. {
    12. return it1->second > it2->second;
    13. }
    14. };
    15. void GetFavoriteFruit2(const vector& fruits, size_t k)
    16. {
    17. mapint> coutMap;
    18. for (auto& str : fruits)
    19. {
    20. coutMap[str]++;//统计次数
    21. }
    22. vectorint>::iterator> Vsort;//直接存迭代器,最多4个字节
    23. auto it = coutMap.begin();
    24. while (it != coutMap.end())
    25. {
    26. Vsort.push_back(it);
    27. ++it;
    28. }
    29. sort(Vsort.begin(), Vsort.end(), CountVal());
    30. for (size_t i = 0; i < k;i++)
    31. {
    32. cout << Vsort[i]->first << ':' << Vsort[i]->second << endl;
    33. }
    34. cout << endl;
    35. }
    36. int main()
    37. {
    38. vector v = { "苹果", "苹果", "香蕉", "草莓", "草莓", "苹果", "苹果", "樱桃", "香蕉","葡萄"};
    39. GetFavoriteFruit2(v,3);
    40. return 0;
    41. }

    2.使用multimap

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. using namespace std;
    9. void GetFavoriteFruit3(const vector& fruits, size_t k)
    10. {
    11. mapint> coutMap;
    12. for (auto& str : fruits)
    13. {
    14. coutMap[str]++;//统计次数
    15. }
    16. multimap<int, string, greater<int>> sortMap; //这里可以控制升降序,利用仿函数
    17. for (auto& kv : coutMap)
    18. {
    19. sortMap.insert(make_pair(kv.second,kv.first)); //这里使用second做为第一个值,first做第二个值
    20. }
    21. auto it = sortMap.begin();
    22. for (size_t i = 0; i < k; i++)
    23. {
    24. cout << it->second << ':' << it->first << endl;
    25. ++it;
    26. }
    27. }
    28. int main()
    29. {
    30. vector v = { "苹果", "苹果", "香蕉", "草莓", "草莓", "苹果", "苹果", "樱桃", "香蕉","葡萄"};
    31. GetFavoriteFruit3(v,3);
    32. return 0;
    33. }

    3.使用优先级队列

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. using namespace std;
    9. //提供一个仿函数
    10. struct CountVal
    11. {
    12. bool operator()(const pairint>&it1, const pairint>& it2)
    13. {
    14. return it1.second < it2.second; //给小于建大堆
    15. }
    16. };
    17. void GetFavoriteFruit4(const vector& fruits, size_t k)
    18. {
    19. mapint> coutMap;
    20. for (auto& str : fruits)
    21. {
    22. coutMap[str]++;//统计次数
    23. }
    24. priority_queueint>, vectorint>>, CountVal> pq;
    25. for (auto&kv : coutMap)
    26. {
    27. pq.push(kv);
    28. }
    29. while (k--)
    30. {
    31. cout << pq.top().first << ':' << pq.top().second << endl;
    32. pq.pop();
    33. }
    34. cout << endl;
    35. }
    36. int main()
    37. {
    38. vector v = { "苹果", "苹果", "香蕉", "草莓", "草莓", "苹果", "苹果", "樱桃", "香蕉","葡萄"};
    39. GetFavoriteFruit4(v,3);
    40. return 0;
    41. }

    这里也存在多次深拷贝,因此继续改进:存迭代器

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. using namespace std;
    9. //提供一个仿函数
    10. struct CountVal
    11. {
    12. bool operator()(const mapint>::iterator&it1, const mapint>::iterator& it2)
    13. {
    14. return it1->second < it2->second;
    15. }
    16. };
    17. void GetFavoriteFruit5(const vector& fruits, size_t k)
    18. {
    19. mapint> coutMap;
    20. for (auto& str : fruits)
    21. {
    22. coutMap[str]++;//统计次数
    23. }
    24. priority_queueint>::iterator, vectorint>::iterator>, CountVal> pq;
    25. auto it = coutMap.begin();
    26. while (it!=coutMap.end())
    27. {
    28. pq.push(it);
    29. ++it;
    30. }
    31. while (k--)
    32. {
    33. cout << pq.top()->first << ':' << pq.top()->second << endl;
    34. pq.pop();
    35. }
    36. cout << endl;
    37. }
    38. int main()
    39. {
    40. vector v = { "苹果", "苹果", "香蕉", "草莓", "草莓", "苹果", "苹果", "樱桃", "香蕉","葡萄"};
    41. GetFavoriteFruit5(v,3);
    42. return 0;
    43. }

    4.OJ题

    力扣https://leetcode.cn/problems/top-k-frequent-words/description/

    1. class Solution {
    2. public:
    3. vector topKFrequent(vector& words, int k) {
    4. mapint> countMap;
    5. for(auto& kv:words)
    6. {
    7. countMap[kv]++; //统计次数
    8. }
    9. multimap<int,string,greater<int>> sortmap;//利用mutilmap进行排序
    10. for(auto& e:countMap)
    11. {
    12. //e=*it
    13. sortmap.insert(make_pair(e.second,e.first));//这里反着使用,使用value进行排序
    14. }
    15. auto it=sortmap.begin();
    16. vector v;
    17. for(int i=0;i
    18. {
    19. v.push_back(it->second);
    20. ++it;
    21. }
    22. return v;
    23. }
    24. };

    4.AVL树

    4.1AVL树的概念

    二叉搜索树随可以缩短查找效率,但是如果数据有序或接近有序二叉树搜索树将退化为单支树,查找元素相当于顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新节点,如果能保证每个节点的左右子树高度之差绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

    一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

    1.它的左右子树都是AVL树

    2.左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)。平衡因子不一定需要,使用平衡因子是一种控制实现方式。平衡因子:右子树-左子树。这里规定一下,后面代码都是这样。也可以左减右。

    如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它又n个结点,其高度保持在 {\log _2}N\,搜索时间复杂度O( {\log _2}N\)。

    4.2AVL树的实现

    1.AVL树的框架

    1. template<class K,class V>
    2. struct AVLTreeNode
    3. {
    4. //3叉链
    5. AVLTreeNode* _left;
    6. AVLTreeNode* _right;
    7. AVLTreeNode* _parent;
    8. pair _kv;
    9. int _bf;//平衡因子
    10. AVLTreeNode(const pair& kv)
    11. :_left(nullptr)
    12. ,_right(nullptr)
    13. ,_parent(nullptr)
    14. ,_kv(kv)
    15. ,_bf(0)
    16. {}
    17. };
    18. template<class K,class V>
    19. class AVLTree
    20. {
    21. typedef struct AVLTreeNode Node;
    22. public:
    23. AVLTree()
    24. :_root(nullptr)
    25. {}
    26. ///在这里写成员函数
    27. private:
    28. Node* _root;
    29. };

    2.插入函数

    插入函数:

    1.搜索二叉树一样的插入,但是需要注意3叉链,需要链上

    2.对树进行平衡控制

      2.1插入结点后先更新平衡因子

      2.2根据平衡因子,是旋转还是不旋转

    更新平衡因子的过程,根据平衡因子分析什么时候需要旋转:

    更新平衡因子的结束条件:while(parent) ,插入节点有可能影响整条子树。

     这段代码就是插入结点,并且更新平衡因子:

    1. bool insert(const pair& kv)
    2. {
    3. //1.插入数据,和搜索二叉树一样,先插入数据
    4. if (_root == nullptr)
    5. {
    6. _root = new Node(kv);
    7. return true;
    8. }
    9. Node*cur = _root;
    10. Node*parent = nullptr;
    11. while (cur)
    12. {
    13. if (cur->_kv.first > kv.first)
    14. {
    15. parent = cur;
    16. cur = cur->_left;
    17. }
    18. else if (cur->_kv.first < kv.first)
    19. {
    20. parent = cur;
    21. cur = cur->_right;
    22. }
    23. else
    24. {
    25. //有这个结点之后,就去重了
    26. return false;
    27. }
    28. }
    29. //没有这个结点
    30. cur = new Node(kv);
    31. if (parent->_kv.first > kv.first)
    32. {
    33. parent->_left = cur;
    34. cur->_parent = parent;
    35. }
    36. else
    37. {
    38. parent->_right = cur;
    39. cur->_parent = parent;
    40. }
    41. //2.控制平衡
    42. // 1.更新平衡因子
    43. // 2.出现异常平衡因子,那么需要旋转平衡处理
    44. while (parent) //判断条件是根结点的_parent 为nullptr
    45. {
    46. //更新平衡因子
    47. if (parent->_left == cur)
    48. {
    49. parent->_bf--;
    50. }
    51. else
    52. {
    53. parent->_bf++;
    54. }
    55. if (parent->_bf==0)
    56. {
    57. break;
    58. }
    59. //根据平衡因子判断是旋转还是继续更新平衡因子
    60. else if (parent->_bf==1 || parent->_bf==-1)
    61. {
    62. //子树变成了1或-1,需要继续向上更新
    63. cur = parent;
    64. parent = parent->_parent;
    65. }
    66. else if (parent->_bf == -2 || parent->_bf == 2)
    67. {
    68. //此时需要进行旋转了。
    69. if (parent->_bf == -2 && cur->_bf == -1)//向右单旋的条件
    70. {
    71. RoateR(parent);
    72. }
    73. else if (parent->_bf==2 && cur->_bf ==1)//向左单旋的条件
    74. {
    75. RoateL(parent);
    76. }
    77. else if (parent->_bf==-2 && cur->_bf==1)//左右旋的条件
    78. {
    79. RoateLR(parent);
    80. }
    81. else if (parent->_bf == 2 && cur->_bf == -1)//右左旋的条件
    82. {
    83. RoateRL(parent);
    84. }
    85. break;//旋转完,就结束了,树已经平衡了
    86. }
    87. else
    88. {
    89. //这里说明上一次平衡因子出现了问题,不出问题不会到这里
    90. assert(false); //出现问题了。
    91. }
    92. }
    93. return true;
    94. }

    简单的插入过程: 

    3.AVL树的旋转

    1.右单旋

    由下图看出:parent->_bf==-2 && cur->_bf==-1 进行右单旋

    右单旋代码: 

    1. void RoateR(Node*parent)//右单旋
    2. {
    3. Node*subL = parent->_left;
    4. Node*subLR = subL->_right;
    5. parent->_left = subLR;
    6. if (subLR) //subL右边可能为空
    7. subLR->_parent = parent;
    8. subL->_right = parent;
    9. Node*parentPrev = parent->_parent; //记录parent的上一个结点
    10. parent->_parent = subL;
    11. if (parent == _root) //若parent是根节点
    12. {
    13. _root = subL;
    14. subL->_parent = nullptr;
    15. }
    16. else //若不是根,而是子树
    17. {
    18. if (parentPrev->_left == parent)//是左边子树
    19. {
    20. parentPrev->_left = subL;
    21. }//是右边子树
    22. else
    23. {
    24. parentPrev->_right = subL;
    25. }
    26. subL->_parent = parentPrev;
    27. }
    28. parent->_bf = subL->_bf = 0;//更新一下平衡因子
    29. }

    2.左单旋

    由下图看出:parent->_bf==2 && cur->_bf==1 进行左单旋

     左单旋代码:

    1. void RoateL(Node*parent)//左单旋
    2. {
    3. Node* subR = parent->_right;
    4. Node*subRL = subR->_left;
    5. parent->_right = subRL;
    6. if (subRL) //subRL有可能为空
    7. subRL->_parent = parent;
    8. subR->_left = parent;
    9. Node*parentPrev = parent->_parent;
    10. parent->_parent = subR;
    11. if (_root==parent)//如果是根节点
    12. {
    13. _root = subR;
    14. subR->_parent = nullptr;
    15. }
    16. else
    17. {
    18. if (parentPrev->_left==parent)
    19. {
    20. parentPrev->_left = subR;
    21. }
    22. else
    23. {
    24. parentPrev->_right = subR;
    25. }
    26. subR->_parent = parentPrev;
    27. }
    28. subR->_bf = parent->_bf = 0;//更新平衡因子
    29. }

    有了左单旋和右单旋的条件,以及函数的实现,因此insert继续完善左单旋和右单旋 :

    1. bool insert(const pair& kv)
    2. {
    3. //1.插入数据,和搜索二叉树一样,先插入数据
    4. if (_root == nullptr)
    5. {
    6. _root = new Node(kv);
    7. return true;
    8. }
    9. Node*cur = _root;
    10. Node*parent = nullptr;
    11. while (cur)
    12. {
    13. if (cur->_kv.first > kv.first)
    14. {
    15. parent = cur;
    16. cur = cur->_left;
    17. }
    18. else if (cur->_kv.first < kv.first)
    19. {
    20. parent = cur;
    21. cur = cur->_right;
    22. }
    23. else
    24. {
    25. //有这个结点之后,就去重了
    26. return false;
    27. }
    28. }
    29. //没有这个结点
    30. cur = new Node(kv);
    31. if (parent->_kv.first > kv.first)
    32. {
    33. parent->_left = cur;
    34. cur->_parent = parent;
    35. }
    36. else
    37. {
    38. parent->_right = cur;
    39. cur->_parent = parent;
    40. }
    41. //2.控制平衡
    42. // 1.更新平衡因子
    43. // 2.出现异常平衡因子,那么需要旋转平衡处理
    44. while (parent) //判断条件是根结点的_parent 为nullptr
    45. {
    46. //更新平衡因子
    47. if (parent->_left == cur)
    48. {
    49. parent->_bf--;
    50. }
    51. else
    52. {
    53. parent->_bf++;
    54. }
    55. //根据平衡因子判断是旋转还是继续更新平衡因子
    56. if (parent->_bf==1 || parent->_bf==-1)
    57. {
    58. //子树变成了1或-1,需要继续向上更新
    59. cur = parent;
    60. parent = parent->_parent;
    61. }
    62. else if (parent->_bf == -2 || parent->_bf == 2)
    63. {
    64. //此时需要进行旋转了。
    65. if (parent->_bf == -2 && cur->_bf == -1)//向右单旋的条件
    66. {
    67. RoateR(parent);
    68. }
    69. else if (parent->_bf==2 && cur->_bf ==1)//向左单旋的条件
    70. {
    71. RoateL(parent);
    72. }
    73. break;//旋转完,就结束了,树已经平衡了
    74. }
    75. else
    76. {
    77. //这里说明上一次平衡因子出现了问题,不出问题不会到这里
    78. assert(false); //出现问题了。
    79. }
    80. }
    81. return true;
    82. }

    当插入结点后,发现并不是单独的一侧高,而是左高和右高,或右高和左高,因此需要双旋。双旋又分为左右旋和右左旋。

    3.先进行左单旋再右旋(左右旋)

    在b或c插入新的结点,都会发生双旋,左右双旋的条件parent->_bf==-2 && cur->_bf==1  进行左单旋再右单旋。

    或者在b点插入新的结点,是一样的:

    因此代码为:但是这里更新平衡因子的时候都是更新成0,也就是上面图,最后的结果是0,0。但是这样是不对的。后面会讲解如何更新平衡因子。

    1. void RoateLR(Node*parent)//左右旋
    2. {
    3. RoateL(parent->_left);//先进行左单旋
    4. RoateR(parent);//在进行右单旋
    5. }

    4.先进行右单旋再左旋(右左旋)

    在b或c插入新的结点,都会发生双旋,右左双旋的条件parent->_bf==2 && cur->_bf==-1  进行右单旋再左单旋。

     或者在c插入结点:也是一样的

    因此代码为:但是这里更新平衡因子的时候都是更新成0,也就是上面图,最后的结果是0,0。但是这样是不对的。后面会讲解如何更新平衡因子。

    1. void RoateRL(Node*parent)//右左旋
    2. {
    3. RoateR(parent->_right);//先进行右单旋
    4. RoateL(parent);//在进行左单旋
    5. }

    所以有了上面的情况代码可以继续更新为:

    1. #include
    2. #include
    3. using namespace std;
    4. #include
    5. template<class K,class V>
    6. struct AVLTreeNode
    7. {
    8. //3叉链
    9. AVLTreeNode* _left;
    10. AVLTreeNode* _right;
    11. AVLTreeNode* _parent;
    12. pair _kv;
    13. int _bf;//平衡因子
    14. AVLTreeNode(const pair& kv)
    15. :_left(nullptr)
    16. ,_right(nullptr)
    17. ,_parent(nullptr)
    18. ,_kv(kv)
    19. , _bf(0)
    20. {}
    21. };
    22. template<class K,class V>
    23. class AVLTree
    24. {
    25. typedef struct AVLTreeNode Node;
    26. public:
    27. AVLTree()
    28. :_root(nullptr)
    29. {}
    30. bool insert(const pair& kv)
    31. {
    32. //1.插入数据,和搜索二叉树一样,先插入数据
    33. if (_root == nullptr)
    34. {
    35. _root = new Node(kv);
    36. return true;
    37. }
    38. Node*cur = _root;
    39. Node*parent = nullptr;
    40. while (cur)
    41. {
    42. if (cur->_kv.first > kv.first)
    43. {
    44. parent = cur;
    45. cur = cur->_left;
    46. }
    47. else if (cur->_kv.first < kv.first)
    48. {
    49. parent = cur;
    50. cur = cur->_right;
    51. }
    52. else
    53. {
    54. //有这个结点之后,就去重了
    55. return false;
    56. }
    57. }
    58. //没有这个结点
    59. cur = new Node(kv);
    60. if (parent->_kv.first > kv.first)
    61. {
    62. parent->_left = cur;
    63. cur->_parent = parent;
    64. }
    65. else
    66. {
    67. parent->_right = cur;
    68. cur->_parent = parent;
    69. }
    70. //2.控制平衡
    71. // 1.更新平衡因子
    72. // 2.出现异常平衡因子,那么需要旋转平衡处理
    73. while (parent) //判断条件是根结点的_parent 为nullptr
    74. {
    75. //更新平衡因子
    76. if (parent->_left == cur)
    77. {
    78. parent->_bf--;
    79. }
    80. else
    81. {
    82. parent->_bf++;
    83. }
    84. //根据平衡因子判断是旋转还是继续更新平衡因子
    85. if (parent->_bf==1 || parent->_bf==-1)
    86. {
    87. //子树变成了1或-1,需要继续向上更新
    88. cur = parent;
    89. parent = parent->_parent;
    90. }
    91. else if (parent->_bf == -2 || parent->_bf == 2)
    92. {
    93. //此时需要进行旋转了。
    94. if (parent->_bf == -2 && cur->_bf == -1)//向右单旋的条件
    95. {
    96. RoateR(parent);
    97. }
    98. else if (parent->_bf==2 && cur->_bf ==1)//向左单旋的条件
    99. {
    100. RoateL(parent);
    101. }
    102. else if (parent->_bf==-2 && cur->_bf==1)//左右旋的条件
    103. {
    104. RoateLR(parent);
    105. }
    106. else if (parent->_bf == 2 && cur->_bf == -1)//右左旋的条件
    107. {
    108. RoateRL(parent);
    109. }
    110. break;//旋转完,就结束了,树已经平衡了
    111. }
    112. else
    113. {
    114. //这里说明上一次平衡因子出现了问题,不出问题不会到这里
    115. assert(false); //出现问题了。
    116. }
    117. }
    118. return true;
    119. }
    120. void RoateR(Node*parent)//右单旋
    121. {
    122. Node*subL = parent->_left;
    123. Node*subLR = subL->_right;
    124. parent->_left = subLR;
    125. if (subLR) //subL右边可能为空
    126. subLR->_parent = parent;
    127. subL->_right = parent;
    128. Node*parentPrev = parent->_parent; //记录parent的上一个结点
    129. parent->_parent = subL;
    130. if (parent == _root) //若parent是根节点
    131. {
    132. _root = subL;
    133. subL->_parent = nullptr;
    134. }
    135. else //若不是根,而是子树
    136. {
    137. if (parentPrev->_left == parent)//是左边子树
    138. {
    139. parentPrev->_left = subL;
    140. }//是右边子树
    141. else
    142. {
    143. parentPrev->_right = subL;
    144. }
    145. subL->_parent = parentPrev;
    146. }
    147. parent->_bf = subL->_bf = 0;//更新一下平衡因子
    148. }
    149. void RoateL(Node*parent)//左单旋
    150. {
    151. Node* subR = parent->_right;
    152. Node*subRL = subR->_left;
    153. parent->_right = subRL;
    154. if (subRL) //subRL有可能为空
    155. subRL->_parent = parent;
    156. subR->_left = parent;
    157. Node*parentPrev = parent->_parent;
    158. parent->_parent = subR;
    159. if (_root==parent)//如果是根节点
    160. {
    161. _root = subR;
    162. subR->_parent = nullptr;
    163. }
    164. else
    165. {
    166. if (parentPrev->_left==parent)
    167. {
    168. parentPrev->_left = subR;
    169. }
    170. else
    171. {
    172. parentPrev->_right = subR;
    173. }
    174. subR->_parent = parentPrev;
    175. }
    176. subR->_bf = parent->_bf = 0;//更新平衡因子
    177. }
    178. void RoateLR(Node*parent)//左右旋
    179. {
    180. //保存好2个结点的指针
    181. Node* subL = parent->_left;
    182. Node*subLR = subL->_right;
    183. int bf = subL->_bf;
    184. RoateL(parent->_left);//先进行左单旋
    185. RoateR(parent);//在进行右单旋
    186. //if (bf==1)
    187. //{
    188. // subL->_bf = -1;
    189. // parent->_bf = 0;
    190. // subLR->_bf = 0;
    191. //}
    192. //else if (bf==-1)
    193. //{
    194. // subL->_bf = 0;
    195. // parent->_bf = 1;
    196. // subLR->_bf = 0;
    197. //}
    198. //else if (bf==0)
    199. //{
    200. // subL->_bf = 0;
    201. // parent->_bf =0;
    202. // subLR->_bf = 0;
    203. //}
    204. //else
    205. //{
    206. // //这里就是出错了
    207. // assert(false);
    208. //}
    209. }
    210. void RoateRL(Node*parent)//右左旋
    211. {
    212. Node* subR = parent->_right;
    213. Node* subRL = subR->_left;
    214. int bf = subRL->_bf;
    215. RoateR(parent->_right);//先进行右单旋
    216. RoateL(parent);//在进行左单旋
    217. //if (bf == 1)
    218. //{
    219. // subRL->_bf = subR->_bf = 0;
    220. // parent->_bf = -1;
    221. //}
    222. //else if (bf=-1)
    223. //{
    224. // subRL->_bf = parent->_bf = 0;
    225. // subR->_bf = 1;
    226. //}
    227. //else if (bf == 0)
    228. //{
    229. // subRL->_bf = subR->_bf = parent->_bf = 0;
    230. //}
    231. //else
    232. //{
    233. // //这里是不可能到达的。
    234. // assert(false);
    235. //}
    236. }
    237. void Inorder()
    238. {
    239. _Inorder(_root);
    240. }
    241. void _Inorder(Node* root)//中序遍历
    242. {
    243. if (root == nullptr)
    244. return;
    245. _Inorder(root->_left);
    246. cout << root->_kv.first << ":" << root->_kv.second << endl;
    247. _Inorder(root->_right);
    248. }
    249. private:
    250. Node* _root;
    251. };

    5.AVL树调试

    1.中序遍历只是检查是否为搜索二叉树,没办法检查是否为平衡二叉树。

    1. void Inorder()
    2. {
    3. _Inorder(_root);
    4. }
    5. void _Inorder(Node* root)//中序遍历
    6. {
    7. if (root == nullptr)
    8. return;
    9. _Inorder(root->_left);
    10. cout << root->_kv.first << ":" << root->_kv.second << endl;
    11. _Inorder(root->_right);
    12. }

    2.检查高度,仅检查高度是不行的,有可能平衡因子有问题。

    1. int TreeHigh(Node*root)
    2. {
    3. if (root == nullptr)
    4. return 0;
    5. int left_high = TreeHigh(root->_left);
    6. int right_high = TreeHigh(root->_right);
    7. return left_high > right_high ? left_high + 1 : right_high + 1;
    8. }
    9. bool IsBanlance()
    10. {
    11. return _IsBanlance(_root);
    12. }
    13. bool _IsBanlance(Node*root)
    14. {
    15. if (root==nullptr)
    16. {
    17. return true;
    18. }
    19. int left_high = TreeHigh(root->_left);
    20. int right_high = TreeHigh(root->_right);
    21. //平衡因子有异常
    22. if (right_high - left_high != root->_bf)
    23. {
    24. cout << root->_kv.first << "现在是:" << root->_bf << endl;
    25. cout << root->_kv.first << "应该是:" << right_high - left_high << endl;
    26. return false;
    27. }
    28. return abs(left_high - right_high)< 2 && _IsBanlance(root->_left) && _IsBanlance(root->_right);
    29. }

    测试代码:在插入的时候顺便检查一下平衡因子

    1. #include"AVLTreeNode.h"
    2. using namespace std;
    3. int main()
    4. {
    5. //int a[] = { 5, 4, 3, 2, 1 ,0};
    6. //int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    7. int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    8. AVLTree<int, int> AVL;
    9. for (auto&e :a)
    10. {
    11. AVL.insert(make_pair(e,e));
    12. cout << "insert"<":"<IsBanlance() << endl;
    13. }
    14. AVL.Inorder();
    15. return 0;
    16. }

    是在插入14的时候出现了问题: 

     因此对照插入数据,进行画图分析,怎么错了。就能找到问题所在。

    6.分析平衡因子

    1.左右旋的平衡因子分析

    所以我们需要把平衡因子修改对,对于平衡因子的分析:

    第一种情况:

    第二种情况: 

    第三种情况: 

    因此代码左右旋的正确代码:

    1. void RoateLR(Node*parent)//左右旋
    2. {
    3. //保存好2个结点的指针
    4. Node* subL = parent->_left;
    5. Node*subLR = subL->_right;
    6. int bf = subL->_bf;
    7. RoateL(parent->_left);//先进行左单旋
    8. RoateR(parent);//在进行右单旋
    9. //从新更新一下平衡因子
    10. if (bf==1)
    11. {
    12. subL->_bf = -1;
    13. parent->_bf = 0;
    14. subLR->_bf = 0;
    15. }
    16. else if (bf==-1)
    17. {
    18. subL->_bf = 0;
    19. parent->_bf = 1;
    20. subLR->_bf = 0;
    21. }
    22. else if (bf==0)
    23. {
    24. subL->_bf = 0;
    25. parent->_bf =0;
    26. subLR->_bf = 0;
    27. }
    28. else
    29. {
    30. //这里就是出错了
    31. assert(false);
    32. }
    33. }

    2.右左旋的平衡因子分析

    第一种情况:

    第二种情况:

    第三种情况:60本身这个结点就是新增结点,也就是h==0

     因此右左旋代码实现:

    1. void RoateRL(Node*parent)//右左旋
    2. {
    3. Node* subR = parent->_right;
    4. Node* sunRL = subR->_left;
    5. int bf = subRL->_bf; //提前保存好结点的平衡因子
    6. RoateR(parent->_right);//先进行右单旋
    7. RoateL(parent);//在进行左单旋
    8. //更新平衡因子
    9. if (bf == 1)
    10. {
    11. subRL->_bf = subR->_bf = 0;
    12. parent->_bf = -1;
    13. }
    14. else if (bf==-1)
    15. {
    16. subRL->_bf = parent->_bf = 0;
    17. subR->_bf = 1;
    18. }
    19. else if (bf == 0)//别忘了这种情况
    20. {
    21. subRL->_bf = subR->_bf = parent->_bf = 0;
    22. }
    23. else //平衡因子出现问题
    24. {
    25. //这里是不可能到达的。
    26. //说明上一次插入已经出现错误了
    27. assert(false);
    28. }
    29. }

    都分析完成后,所有的代码:

    AVLTreeNode.h

    1. #include
    2. #include
    3. using namespace std;
    4. #include
    5. template<class K,class V>
    6. struct AVLTreeNode
    7. {
    8. //3叉链
    9. AVLTreeNode* _left;
    10. AVLTreeNode* _right;
    11. AVLTreeNode* _parent;
    12. pair _kv;
    13. int _bf;//平衡因子
    14. AVLTreeNode(const pair& kv)
    15. :_left(nullptr)
    16. ,_right(nullptr)
    17. ,_parent(nullptr)
    18. ,_kv(kv)
    19. , _bf(0)
    20. {}
    21. };
    22. template<class K,class V>
    23. class AVLTree
    24. {
    25. typedef struct AVLTreeNode Node;
    26. public:
    27. AVLTree()
    28. :_root(nullptr)
    29. {}
    30. bool insert(const pair& kv)
    31. {
    32. //1.插入数据,和搜索二叉树一样,先插入数据
    33. if (_root == nullptr)
    34. {
    35. _root = new Node(kv);
    36. return true;
    37. }
    38. Node*cur = _root;
    39. Node*parent = nullptr;
    40. while (cur)
    41. {
    42. if (cur->_kv.first > kv.first)
    43. {
    44. parent = cur;
    45. cur = cur->_left;
    46. }
    47. else if (cur->_kv.first < kv.first)
    48. {
    49. parent = cur;
    50. cur = cur->_right;
    51. }
    52. else
    53. {
    54. //有这个结点之后,就去重了
    55. return false;
    56. }
    57. }
    58. //没有这个结点
    59. cur = new Node(kv);
    60. if (parent->_kv.first > kv.first)
    61. {
    62. parent->_left = cur;
    63. cur->_parent = parent;
    64. }
    65. else
    66. {
    67. parent->_right = cur;
    68. cur->_parent = parent;
    69. }
    70. //2.控制平衡
    71. // 1.更新平衡因子
    72. // 2.出现异常平衡因子,那么需要旋转平衡处理
    73. while (parent) //判断条件是根结点的_parent 为nullptr
    74. {
    75. //更新平衡因子
    76. if (parent->_left == cur)
    77. {
    78. parent->_bf--;
    79. }
    80. else
    81. {
    82. parent->_bf++;
    83. }
    84. if (parent->_bf==0)
    85. {
    86. break;
    87. }
    88. //根据平衡因子判断是旋转还是继续更新平衡因子
    89. else if (parent->_bf==1 || parent->_bf==-1)
    90. {
    91. //子树变成了1或-1,需要继续向上更新
    92. cur = parent;
    93. parent = parent->_parent;
    94. }
    95. else if (parent->_bf == -2 || parent->_bf == 2)
    96. {
    97. //此时需要进行旋转了。
    98. if (parent->_bf == -2 && cur->_bf == -1)//向右单旋的条件
    99. {
    100. RoateR(parent);
    101. }
    102. else if (parent->_bf==2 && cur->_bf ==1)//向左单旋的条件
    103. {
    104. RoateL(parent);
    105. }
    106. else if (parent->_bf==-2 && cur->_bf==1)//左右旋的条件
    107. {
    108. RoateLR(parent);
    109. }
    110. else if (parent->_bf == 2 && cur->_bf == -1)//右左旋的条件
    111. {
    112. RoateRL(parent);
    113. }
    114. break;//旋转完,就结束了,树已经平衡了
    115. }
    116. else
    117. {
    118. //这里说明上一次平衡因子出现了问题,不出问题不会到这里
    119. assert(false); //出现问题了。
    120. }
    121. }
    122. return true;
    123. }
    124. void RoateR(Node*parent)//右单旋
    125. {
    126. Node*subL = parent->_left;
    127. Node*subLR = subL->_right;
    128. parent->_left = subLR;
    129. if (subLR) //subL右边可能为空
    130. subLR->_parent = parent;
    131. subL->_right = parent;
    132. Node*parentPrev = parent->_parent; //记录parent的上一个结点
    133. parent->_parent = subL;
    134. if (parent == _root) //若parent是根节点
    135. {
    136. _root = subL;
    137. subL->_parent = nullptr;
    138. }
    139. else //若不是根,而是子树
    140. {
    141. if (parentPrev->_left == parent)//是左边子树
    142. {
    143. parentPrev->_left = subL;
    144. }//是右边子树
    145. else
    146. {
    147. parentPrev->_right = subL;
    148. }
    149. subL->_parent = parentPrev;
    150. }
    151. parent->_bf = subL->_bf = 0;//更新一下平衡因子
    152. }
    153. void RoateL(Node*parent)//左单旋
    154. {
    155. Node* subR = parent->_right;
    156. Node*subRL = subR->_left;
    157. parent->_right = subRL;
    158. if (subRL) //subRL有可能为空
    159. subRL->_parent = parent;
    160. subR->_left = parent;
    161. Node*parentPrev = parent->_parent;
    162. parent->_parent = subR;
    163. if (_root==parent)//如果是根节点
    164. {
    165. _root = subR;
    166. subR->_parent = nullptr;
    167. }
    168. else
    169. {
    170. if (parentPrev->_left==parent)
    171. {
    172. parentPrev->_left = subR;
    173. }
    174. else
    175. {
    176. parentPrev->_right = subR;
    177. }
    178. subR->_parent = parentPrev;
    179. }
    180. subR->_bf = parent->_bf = 0;//更新平衡因子
    181. }
    182. void RoateLR(Node*parent)//左右旋
    183. {
    184. //保存好2个结点的指针
    185. Node* subL = parent->_left;
    186. Node*subLR = subL->_right;
    187. int bf = subLR->_bf;
    188. RoateL(parent->_left);//先进行左单旋
    189. RoateR(parent);//在进行右单旋
    190. if (bf==1)
    191. {
    192. subL->_bf = -1;
    193. parent->_bf = 0;
    194. subLR->_bf = 0;
    195. }
    196. else if (bf==-1)
    197. {
    198. subL->_bf = 0;
    199. parent->_bf = 1;
    200. subLR->_bf = 0;
    201. }
    202. else if (bf==0)
    203. {
    204. subL->_bf = 0;
    205. parent->_bf =0;
    206. subLR->_bf = 0;
    207. }
    208. else
    209. {
    210. //这里就是出错了
    211. assert(false);
    212. }
    213. }
    214. void RoateRL(Node*parent)//右左旋
    215. {
    216. Node* subR = parent->_right;
    217. Node* subRL = subR->_left;
    218. int bf = subRL->_bf;
    219. RoateR(parent->_right);//先进行右单旋
    220. RoateL(parent);//在进行左单旋
    221. if (bf == 1)
    222. {
    223. subRL->_bf = subR->_bf = 0;
    224. parent->_bf = -1;
    225. }
    226. else if (bf==-1)
    227. {
    228. subRL->_bf = parent->_bf = 0;
    229. subR->_bf = 1;
    230. }
    231. else if (bf == 0)
    232. {
    233. subRL->_bf = subR->_bf = parent->_bf = 0;
    234. }
    235. else
    236. {
    237. //这里是不可能到达的。
    238. assert(false);
    239. }
    240. }
    241. void Inorder()
    242. {
    243. _Inorder(_root);
    244. }
    245. void _Inorder(Node* root)//中序遍历
    246. {
    247. if (root == nullptr)
    248. return;
    249. _Inorder(root->_left);
    250. cout << root->_kv.first << ":" << root->_kv.second << endl;
    251. _Inorder(root->_right);
    252. }
    253. int TreeHigh(Node*root)
    254. {
    255. if (root == nullptr)
    256. return 0;
    257. int left_high = TreeHigh(root->_left);
    258. int right_high = TreeHigh(root->_right);
    259. return left_high > right_high ? left_high + 1 : right_high + 1;
    260. }
    261. bool IsBanlance()
    262. {
    263. return _IsBanlance(_root);
    264. }
    265. bool _IsBanlance(Node*root)
    266. {
    267. if (root==nullptr)
    268. {
    269. return true;
    270. }
    271. int left_high = TreeHigh(root->_left);
    272. int right_high = TreeHigh(root->_right);
    273. //平衡因子有异常
    274. if (right_high - left_high != root->_bf)
    275. {
    276. cout << root->_kv.first << "现在是:" << root->_bf << endl;
    277. cout << root->_kv.first << "应该是:" << right_high - left_high << endl;
    278. return false;
    279. }
    280. return abs(left_high - right_high)< 2 && _IsBanlance(root->_left) && _IsBanlance(root->_right);
    281. }
    282. private:
    283. Node* _root;
    284. };

    main.cpp

    1. #include"AVLTreeNode.h"
    2. using namespace std;
    3. int main()
    4. {
    5. //int a[] = { 5, 4, 3, 2, 1 ,0};
    6. int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    7. //int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    8. AVLTree<int, int> AVL;
    9. for (auto&e :a)
    10. {
    11. AVL.insert(make_pair(e,e));
    12. cout << "insert"<":"<IsBanlance() << endl;
    13. }
    14. AVL.Inorder();
    15. return 0;
    16. }

    测试结果:3个用例,没问题。

    AVL树的性能:AVL树是一颗绝对平衡的二叉树,其要求每个节点的左右子树高度差的绝对值不超过1,这样可以保证查询时高效的时间复杂度,即{\log _2}N\

    5.红黑树

    5.1红黑树的概念

    红黑树,是一种二叉树搜索树,但在每个节点上增加一个存储位表示结点的颜色,可以是Red或BLACK通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡

    5.2红黑树的性质

    1.每个结点不是红色就是黑色

    2.根结点是黑色

    3.如果一个结点是红色,则它的两个孩子结点是黑色的。(没有连续的红色结点)

    4.每条路径上所包含的黑色结点数目是一样多的。

    5.每个叶子结点都是黑色的(此处的叶子结点指的是空节点,即NIL 都是黑色的) 。但是这个黑色结点可以不算,不用管就是了。

    以上的前4个红黑树性质,确定了最长路径不超过最短路径的2倍,从NIL开始到根节点代表一条路径。下图一共10条路径。

    通过下图理解为什么满足上面的性质,红黑树就能保证:其最长路径中结点个数不会超过最短路径结点个数的两倍。

    最短路径:全黑

    最长路径:一黑一红

    假设每条路径黑节点的数量是N,  N<=任意路径长度<=2N

    红黑树复杂度分析:

    红黑树是近似平衡与AVL树完全平衡相比,AVL树的复杂度是{\log _2}N\,比红黑树效率高,但是它需要大量的旋转才能达到平衡付出代价很大,所以红黑树更吃香。

    5.3红黑树的实现

    1.红黑树的基本框架

    1. #include
    2. #include
    3. using namespace std;
    4. enum color
    5. {
    6. RED,
    7. BLACK
    8. };
    9. template<class K,class V>
    10. struct RBtreeNode
    11. {
    12. RBtreeNode* _left;
    13. RBtreeNode* _right;
    14. RBtreeNode* _parent;
    15. pair _kv;
    16. color _col;
    17. RBtreeNode(const pair& kv)
    18. :_left(nullptr)
    19. , _right(nullptr)
    20. , _parent(nullptr)
    21. , _kv(kv)
    22. , _col(RED)
    23. {}
    24. };
    25. template<class K,class V>
    26. class RBTtree
    27. {
    28. typedef RBtreeNode Node;
    29. public:
    30. RBTtree()
    31. :_root(nullptr)
    32. {}
    33. //这里增加成员函数
    34. private:
    35. Node* _root;
    36. };

    2.insert函数

    思考一个问题:在插入节点时,是插入红色的节点还是黑色的。答案:红色的,若是插入黑色的,根据红黑树的定义,每条路径上所包含相同数目的黑色节点,若是插入黑色节点,那么将会对整棵树产生影响,反而插入红色节点,最差只会影响这一条路径上的,最好不影响。

    这里的插入节点和前面的平衡二叉树是一样的,旋转也一样,只是不更新平衡因子。不同的是控制上的不同,所以只介绍控制。

    以下分析都是分析的左边插入节点,右边插入就是相反了。

    情况1:只是变色

    情况2:单旋

    情况3:

    红黑树insert代码:

    1. bool insert(const pair& kv)
    2. {
    3. //
    4. if (_root == nullptr)
    5. {
    6. _root = new Node(kv);
    7. _root->_col = BLACK;
    8. return true;
    9. }
    10. Node* cur = _root;
    11. Node* parent = nullptr;
    12. while (cur)
    13. {
    14. if (cur->_kv.first > kv.first)
    15. {
    16. parent = cur;
    17. cur = cur->_left;
    18. }
    19. else if (cur->_kv.first < kv.first)
    20. {
    21. parent = cur;
    22. cur = cur->_right;
    23. }
    24. else
    25. {
    26. return false;
    27. }
    28. }
    29. cur = new Node(kv);
    30. cur->_col = RED;//把结点以红色插入
    31. if (parent->_kv.first < kv.first)
    32. {
    33. parent->_right = cur;
    34. cur->_parent = parent;
    35. }
    36. else
    37. {
    38. parent->_left = cur;
    39. cur->_parent = parent;
    40. }
    41. //进行红黑树的控制
    42. while (parent && parent->_col==RED)//父节点位黑或者不存在就结束了
    43. {
    44. Node*gradparent = parent->_parent; //这里的祖父一定是存在的,因为parent->_col==RED,所以parent不可能是根节点
    45. if (gradparent->_left==parent)//在左边进行插入的
    46. {
    47. Node* uncle = gradparent->_right;
    48. if (uncle && uncle->_col == RED)//u存在且为红色,情况1
    49. {
    50. uncle->_col = BLACK;
    51. parent->_col = BLACK;
    52. gradparent->_col = RED;
    53. cur = gradparent;//把祖父当成新增结点
    54. parent = cur->_parent;
    55. }
    56. else //u不存在或为黑
    57. {
    58. if (parent->_left==cur) //在parent插入左边插入节点,情况2
    59. {
    60. //单旋
    61. // g
    62. // p u(存在为黑,或不存在)
    63. // c
    64. RoateR(gradparent);
    65. gradparent->_col = RED;
    66. parent->_col = BLACK;
    67. }
    68. else //在parent的右边插入节点 ,情况3
    69. {
    70. //双旋
    71. // g
    72. // p u
    73. // c
    74. RoateL(parent);
    75. RoateR(gradparent);
    76. cur->_col = BLACK;
    77. gradparent->_col = RED;
    78. }
    79. break;
    80. }
    81. }
    82. else //gradparent->_left==parent,在树的右边插入了节点
    83. {
    84. Node*uncle = gradparent->_left;
    85. if (uncle && uncle->_col==RED)//情况1 u存在且为红
    86. {
    87. parent->_col = BLACK;
    88. uncle->_col = BLACK;
    89. gradparent->_col = RED;
    90. cur = gradparent;
    91. parent = cur->_parent;
    92. }
    93. else //u不存在或着u为黑
    94. {
    95. // g
    96. //u p
    97. // cur
    98. if (parent->_right == cur)//情况2
    99. {
    100. //进行左单旋
    101. RoateL(gradparent);
    102. parent->_col = BLACK;
    103. gradparent->_col = RED;
    104. }
    105. // g
    106. //u p
    107. // c
    108. else //情况3
    109. {
    110. //双旋
    111. RoateR(parent);
    112. RoateL(gradparent);
    113. cur->_col = BLACK;
    114. gradparent->_col = RED;
    115. }
    116. break;
    117. }
    118. }
    119. }
    120. _root->_col = BLACK;//不管是子树还是根节点都需要是黑色
    121. return true;
    122. }

    测试代码:使用中序只能证明是搜索二叉树。

    1. #include"RBTree.h"
    2. int main()
    3. {
    4. //int a[] = { 5, 4, 3, 2, 1 ,0};
    5. //int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    6. int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    7. RBTtree<int, int> t;
    8. for (auto e : a)
    9. {
    10. t.insert(make_pair(e,e));
    11. }
    12. t.Inoder();
    13. return 0;
    14. }

    那如何证明是红黑树呢?

    主要是检验性质3和4。

    注意这里检查是否存在连续红色节点的时候,去检查红色节点的父亲节点。

    这里检查每条路径上的黑色节点是否一样,需要选取一个基准值,这里选的树的最左边那条路径。

    1. bool IsBanlance()
    2. {
    3. if (_root && _root->_col == RED) //检查根节点是不是黑色的
    4. {
    5. cout << "根节点不是黑色" << endl;
    6. return false;
    7. }
    8. int benchmark = 0; //取一个路径上黑色节点的数量作为基准值
    9. Node* cur = _root;
    10. while (cur)//这里取的最左路径为基准,以方便检验黑色节点的数量
    11. {
    12. if (cur->_col == BLACK)
    13. {
    14. benchmark++;
    15. }
    16. cur = cur->_left;
    17. }
    18. int BlackCount = 0;
    19. return _IsBanlance(_root, benchmark, BlackCount);
    20. }
    21. bool _IsBanlance(Node* root, int benchmark, int BlackCount)
    22. {
    23. if (root == nullptr)
    24. {
    25. //检查每一条黑色节点数量
    26. if (BlackCount != benchmark)
    27. {
    28. cout << "路径黑色节点不一样" << endl;
    29. return false;
    30. }
    31. return true;
    32. }
    33. //这里不去检查孩子节点,而是检查父亲节点,检查孩子太麻烦了,情况比较多
    34. if (root->_col==RED && root->_parent->_col==RED) //root->_col==RED 一定存在父节点,因为根黑色的
    35. {
    36. cout << "连续的红节点" << endl;
    37. return false;
    38. }
    39. if (root->_col == BLACK)
    40. {
    41. BlackCount++;
    42. }
    43. return _IsBanlance(root->_left, benchmark, BlackCount) && _IsBanlance(root->_right, benchmark, BlackCount);
    44. }

    测试代码:

    RBTree.h

    1. #include
    2. #include
    3. using namespace std;
    4. enum color
    5. {
    6. RED,
    7. BLACK
    8. };
    9. template<class K,class V>
    10. struct RBtreeNode
    11. {
    12. RBtreeNode* _left;
    13. RBtreeNode* _right;
    14. RBtreeNode* _parent;
    15. pair _kv;
    16. color _col;
    17. RBtreeNode(const pair& kv)
    18. :_left(nullptr)
    19. , _right(nullptr)
    20. , _parent(nullptr)
    21. , _kv(kv)
    22. , _col(RED)
    23. {}
    24. };
    25. template<class K,class V>
    26. class RBTtree
    27. {
    28. typedef RBtreeNode Node;
    29. public:
    30. RBTtree()
    31. :_root(nullptr)
    32. {}
    33. void RoateR(Node*parent)
    34. {
    35. Node*subL = parent->_left;
    36. Node* subLR = subL->_right;
    37. parent->_left = subL->_right;
    38. if (subLR)
    39. subLR->_parent = parent;
    40. subL->_right = parent;
    41. Node*prevparent = parent->_parent;
    42. parent->_parent = subL;
    43. if (parent == _root)
    44. {
    45. _root = subL;
    46. subL->_parent = nullptr;
    47. }
    48. else if (prevparent->_left==parent)
    49. {
    50. prevparent->_left = subL;
    51. subL->_parent = prevparent;
    52. }
    53. else if (prevparent->_right==parent)
    54. {
    55. prevparent->_right = subL;
    56. subL->_parent = prevparent;
    57. }
    58. else
    59. {
    60. assert(false);
    61. }
    62. }
    63. void RoateL(Node* parent)
    64. {
    65. Node*subR = parent->_right;
    66. Node*subRL = subR->_left;
    67. parent->_right = subRL;
    68. if (subRL)
    69. {
    70. subRL->_parent = parent;
    71. }
    72. subR->_left = parent;
    73. Node*prevparent = parent->_parent;
    74. parent->_parent = subR;
    75. if (parent==_root)
    76. {
    77. _root = subR;
    78. subR->_parent = nullptr;
    79. }
    80. else if (prevparent->_left == parent)
    81. {
    82. prevparent->_left = subR;
    83. subR->_parent = prevparent;
    84. }
    85. else if (prevparent->_right == parent)
    86. {
    87. prevparent->_right = subR;
    88. subR->_parent = prevparent;
    89. }
    90. else
    91. {
    92. assert(false);
    93. }
    94. }
    95. bool insert(const pair& kv)
    96. {
    97. //
    98. if (_root == nullptr)
    99. {
    100. _root = new Node(kv);
    101. _root->_col = BLACK;
    102. return true;
    103. }
    104. Node* cur = _root;
    105. Node* parent = nullptr;
    106. while (cur)
    107. {
    108. if (cur->_kv.first > kv.first)
    109. {
    110. parent = cur;
    111. cur = cur->_left;
    112. }
    113. else if (cur->_kv.first < kv.first)
    114. {
    115. parent = cur;
    116. cur = cur->_right;
    117. }
    118. else
    119. {
    120. return false;
    121. }
    122. }
    123. cur = new Node(kv);
    124. cur->_col = RED;//把结点以红色插入
    125. if (parent->_kv.first < kv.first)
    126. {
    127. parent->_right = cur;
    128. cur->_parent = parent;
    129. }
    130. else
    131. {
    132. parent->_left = cur;
    133. cur->_parent = parent;
    134. }
    135. //进行红黑树的控制
    136. while (parent && parent->_col==RED)//父节点位黑或者不存在就结束了
    137. {
    138. Node*gradparent = parent->_parent; //这里的祖父一定是存在的,因为parent->_col==RED,所以parent不可能是根节点
    139. if (gradparent->_left==parent)//在左边进行插入的
    140. {
    141. Node* uncle = gradparent->_right;
    142. if (uncle && uncle->_col == RED)//u存在且为红色,情况1
    143. {
    144. uncle->_col = BLACK;
    145. parent->_col = BLACK;
    146. gradparent->_col = RED;
    147. cur = gradparent;//把祖父当成新增结点
    148. parent = cur->_parent;
    149. }
    150. else //u不存在或为黑
    151. {
    152. if (parent->_left==cur) //在parent插入左边插入节点,情况2
    153. {
    154. //单旋
    155. // g
    156. // p u(存在为黑,或不存在)
    157. // c
    158. RoateR(gradparent);
    159. gradparent->_col = RED;
    160. parent->_col = BLACK;
    161. }
    162. else //在parent的右边插入节点 ,情况3
    163. {
    164. //双旋
    165. // g
    166. // p u
    167. // c
    168. RoateL(parent);
    169. RoateR(gradparent);
    170. cur->_col = BLACK;
    171. gradparent->_col = RED;
    172. }
    173. break;
    174. }
    175. }
    176. else //gradparent->_left==parent,在树的右边插入了节点
    177. {
    178. Node*uncle = gradparent->_left;
    179. if (uncle && uncle->_col==RED)//情况1 u存在且为红
    180. {
    181. parent->_col = BLACK;
    182. uncle->_col = BLACK;
    183. gradparent->_col = RED;
    184. cur = gradparent;
    185. parent = cur->_parent;
    186. }
    187. else //u不存在或着u为黑
    188. {
    189. // g
    190. //u p
    191. // cur
    192. if (parent->_right == cur)//情况2
    193. {
    194. //进行左单旋
    195. RoateL(gradparent);
    196. parent->_col = BLACK;
    197. gradparent->_col = RED;
    198. }
    199. // g
    200. //u p
    201. // c
    202. else //情况3
    203. {
    204. //双旋
    205. RoateR(parent);
    206. RoateL(gradparent);
    207. cur->_col = BLACK;
    208. gradparent->_col = RED;
    209. }
    210. break;
    211. }
    212. }
    213. }
    214. _root->_col = BLACK;//不管是子树还是根节点都需要是黑色
    215. return true;
    216. }
    217. //中序遍历
    218. void Inoder()
    219. {
    220. _Inoder(_root);
    221. }
    222. void _Inoder(Node* root)
    223. {
    224. if (root == nullptr)
    225. return;
    226. _Inoder(root->_left);
    227. cout << root->_kv.first << ":" << root->_kv.second << endl;
    228. _Inoder(root->_right);
    229. }
    230. bool IsBanlance()
    231. {
    232. if (_root && _root->_col == RED) //检查根节点是不是黑色的
    233. {
    234. cout << "根节点不是黑色" << endl;
    235. return false;
    236. }
    237. int benchmark = 0; //取一个路径上黑色节点的数量作为基准值
    238. Node* cur = _root;
    239. while (cur)//这里取的最左路径为基准
    240. {
    241. if (cur->_col == BLACK)
    242. {
    243. benchmark++;
    244. }
    245. cur = cur->_left;
    246. }
    247. int BlackCount = 0;
    248. return _IsBanlance(_root, benchmark, BlackCount);
    249. }
    250. bool _IsBanlance(Node* root, int benchmark, int BlackCount)
    251. {
    252. if (root == nullptr)
    253. {
    254. //检查每一条黑色节点数量
    255. if (BlackCount != benchmark)
    256. {
    257. cout << "路径黑色节点不一样" << endl;
    258. return false;
    259. }
    260. return true;
    261. }
    262. //这里不去检查孩子节点,而是检查父亲节点,检查孩子太麻烦了,情况比较多
    263. if (root->_col==RED && root->_parent->_col==RED) //root->_col==RED 一定存在父节点,因为根黑色的
    264. {
    265. cout << "连续的红节点" << endl;
    266. return false;
    267. }
    268. if (root->_col == BLACK)
    269. {
    270. BlackCount++;
    271. }
    272. return _IsBanlance(root->_left, benchmark, BlackCount) && _IsBanlance(root->_right, benchmark, BlackCount);
    273. }
    274. private:
    275. Node* _root;
    276. };

    main.cpp

    1. #include"RBTree.h"
    2. int main()
    3. {
    4. //int a[] = { 5, 4, 3, 2, 1 ,0};
    5. //int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    6. int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    7. RBTtree<int, int> t;
    8. for (auto e : a)
    9. {
    10. t.insert(make_pair(e,e));
    11. cout << "insert" << e << ":"<IsBanlance() << endl;
    12. }
    13. t.Inoder();
    14. return 0;
    15. }

    也可以给随机值: 

    1. #include
    2. #include
    3. #include"RBTree.h"
    4. int main()
    5. {
    6. //int a[] = { 5, 4, 3, 2, 1 ,0};
    7. //int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    8. //int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    9. vector<int> v;
    10. srand(time(0));
    11. int N = 100000;
    12. for (int i = 0; i < N; i++)
    13. {
    14. v.push_back(rand()); //给随机值
    15. }
    16. RBTtree<int, int> t;
    17. for (auto e : v)
    18. {
    19. t.insert(make_pair(e,e));
    20. cout << "insert" << e << ":"<IsBanlance() << endl;
    21. }
    22. // cout <
    23. t.Inoder();
    24. return 0;
    25. }

    6.set和map的模拟实现

    1.set和map的模拟实现

    观察STL源码:stl_map.h , stl_set.h , stl_tree.h。

    set是key ,map是 pair

    为了实现红黑树既可以是pair,也可以是key,那就需要改进红黑树。

    这里最主要的是实现set和map共用一个红黑树:

    RBTree.h

    1. #pragma once
    2. #include
    3. namespace zcf{
    4. enum color
    5. {
    6. RED,
    7. BLACK
    8. };
    9. template<class T>//这里只需要一个模板参数,用于接受类型
    10. struct RBtreeNode
    11. {
    12. RBtreeNode* _left;
    13. RBtreeNode* _right;
    14. RBtreeNode* _parent;
    15. T _data; //根据传入的模板参数来确定这里是pair还是key
    16. color _col;
    17. RBtreeNode(const T& data)
    18. :_left(nullptr)
    19. , _right(nullptr)
    20. , _parent(nullptr)
    21. , _data(data)
    22. , _col(RED)
    23. {}
    24. };
    25. //迭代器
    26. template<class T, class Ref, class Ptr>
    27. struct RBTreeIterator
    28. {
    29. typedef RBTreeIterator Self;
    30. typedef RBtreeNode Node;
    31. Node* _node;
    32. RBTreeIterator(Node* node)
    33. :_node(node)
    34. {}
    35. Ref operator*()
    36. {
    37. return _node->_data;
    38. }
    39. Ptr operator->()
    40. {
    41. return &(_node->_data);
    42. }
    43. //前置++
    44. //当前结点的右子树不为空,那么就去找右子树的最左结点
    45. //当前结点的右子树为空:因为是中序遍历,++也要遵循中序
    46. // 1.如果当前结点是parent的左边,++就是parent
    47. // 2.如果当前结点是parent的右边,++就是当前结点的_parent,直到parent为空,或parent->_left==cur
    48. Self& operator++()
    49. {
    50. if(_node->_right) // 右子树不为空,那就是右子树的最左节点
    51. {
    52. Node* cur = _node->_right;
    53. while (cur->_left)
    54. {
    55. cur = cur->_left;
    56. }
    57. _node = cur;
    58. }
    59. else//右子树为空
    60. {
    61. Node*cur = _node;
    62. Node*parent = cur->_parent;
    63. while (parent && parent->_right==cur)
    64. {
    65. cur = cur->_parent;
    66. parent = parent->_parent;
    67. }
    68. //父亲的左节点为cur。
    69. //parent->_left==cur或parent==nullptr
    70. _node = parent;
    71. }
    72. return *this;
    73. }
    74. //前置-- ,与++是相反的思想
    75. Self& operator--()
    76. {
    77. if (_node->_left)//左子树不为空,找最右节点
    78. {
    79. Node*cur = _node->_left;
    80. while (cur->_right)
    81. {
    82. cur = cur->_right;
    83. }
    84. _node = cur;
    85. }
    86. else//左子树为空
    87. {
    88. Node*cur = _node;
    89. Node*parent = cur->_parent;
    90. while (parent && parent->_left==cur)
    91. {
    92. cur = cur->_parent;
    93. parent = parent->_parent;
    94. }
    95. _node = parent;
    96. }
    97. return *this;
    98. }
    99. bool operator!=(const Self& s)
    100. {
    101. return _node != s._node;
    102. }
    103. bool operator==(const Self& s)
    104. {
    105. return _node == s._node;
    106. }
    107. };
    108. template<class K,class T,class KeyOfT>//使用T来解决红黑树是key还是pair,
    109. //KeyOfT 来解决比较的问题,因为红黑树在比较的时候不知道是pair还是key,而map和set类中知道
    110. class RBTtree
    111. {
    112. public:
    113. typedef RBTreeIterator< T, T&, T*> iterator;
    114. typedef RBTreeIterator< T, const T&,const T*> const_iterator;
    115. typedef RBtreeNode Node; //typedef一下RBtreeNode,根据传入的T进行节点的实例化,确定是pair还是key
    116. RBTtree()
    117. :_root(nullptr)
    118. {}
    119. Node* copy(Node* root)
    120. {
    121. if (root == nullptr)
    122. return nullptr;
    123. //拷贝结点
    124. Node* newnode = new Node(root->_data);
    125. newnode->_col = root->_col;//更新颜色
    126. //Node*newnode=new Node(*root);//这里会去调用拷贝构造,但是拷贝构造是系统默认的,只更新了颜色和data
    127. //更新左和右
    128. newnode->_left = copy(root->_left);
    129. newnode->_right = copy(root->_right);
    130. //更新parent
    131. if (newnode->_left)//不为空
    132. {
    133. newnode->_left->_parent = newnode;
    134. }
    135. if (newnode->_right)
    136. {
    137. newnode->_right->_parent = newnode;
    138. }
    139. return newnode;
    140. }
    141. //拷贝构造,需要深拷贝
    142. RBTtree(const RBTtree& rb)
    143. {
    144. _root=copy(rb._root);
    145. }
    146. //赋值
    147. RBTtree& operator=(RBTtree tmp)
    148. {
    149. swap(_root, tmp._root);
    150. return *this;
    151. }
    152. //迭代器
    153. iterator begin() //找最小的节点
    154. {
    155. Node* min = _root;
    156. while (min && min->_left)
    157. {
    158. min = min->_left;
    159. }
    160. return iterator(min);
    161. }
    162. iterator end()
    163. {
    164. return iterator(nullptr);
    165. }
    166. //查找函数,查找的是key
    167. iterator find(const K& key)
    168. {
    169. KeyOfT kot;
    170. Node* cur = _root;
    171. while (cur)
    172. {
    173. if (kot(cur->_data) > kot(key))
    174. {
    175. cur = cur->_left;
    176. }
    177. else if (kot(cur->_data) < kot(key))
    178. {
    179. cur = cur->_right;
    180. }
    181. else //找到了
    182. {
    183. return iterator(cur);
    184. }
    185. }
    186. return end(); //没有找到,返回nullptr;
    187. }
    188. void RoateR(Node*parent)
    189. {
    190. Node*subL = parent->_left;
    191. Node* subLR = subL->_right;
    192. parent->_left = subL->_right;
    193. if (subLR)
    194. subLR->_parent = parent;
    195. subL->_right = parent;
    196. Node*prevparent = parent->_parent;
    197. parent->_parent = subL;
    198. if (parent == _root)
    199. {
    200. _root = subL;
    201. subL->_parent = nullptr;
    202. }
    203. else if (prevparent->_left==parent)
    204. {
    205. prevparent->_left = subL;
    206. subL->_parent = prevparent;
    207. }
    208. else if (prevparent->_right==parent)
    209. {
    210. prevparent->_right = subL;
    211. subL->_parent = prevparent;
    212. }
    213. else
    214. {
    215. assert(false);
    216. }
    217. }
    218. void RoateL(Node* parent)
    219. {
    220. Node*subR = parent->_right;
    221. Node*subRL = subR->_left;
    222. parent->_right = subRL;
    223. if (subRL)
    224. {
    225. subRL->_parent = parent;
    226. }
    227. subR->_left = parent;
    228. Node*prevparent = parent->_parent;
    229. parent->_parent = subR;
    230. if (parent==_root)
    231. {
    232. _root = subR;
    233. subR->_parent = nullptr;
    234. }
    235. else if (prevparent->_left == parent)
    236. {
    237. prevparent->_left = subR;
    238. subR->_parent = prevparent;
    239. }
    240. else if (prevparent->_right == parent)
    241. {
    242. prevparent->_right = subR;
    243. subR->_parent = prevparent;
    244. }
    245. else
    246. {
    247. assert(false);
    248. }
    249. }
    250. //insert返回pair对象,对象里面一个是迭代器,一个是bool
    251. pairbool> insert(const T& data)
    252. {
    253. if (_root == nullptr)
    254. {
    255. _root = new Node(data);
    256. _root->_col = BLACK;
    257. return make_pair(iterator(_root),true);
    258. }
    259. Node* cur = _root;
    260. Node* parent = nullptr;
    261. KeyOfT kot; //创建KeyOfT的对象,相当于仿函数
    262. while (cur)
    263. {
    264. if (kot(cur->_data) > kot(data))//比较去调用KeyOfT对象的重载的()
    265. {
    266. parent = cur;
    267. cur = cur->_left;
    268. }
    269. else if (kot(cur->_data) < kot(data))//比较去调用KeyOfT对象的重载的()
    270. {
    271. parent = cur;
    272. cur = cur->_right;
    273. }
    274. else
    275. {
    276. //返回相同结点的迭代器
    277. return make_pair(iterator(cur),false);
    278. }
    279. }
    280. cur = new Node(data);
    281. //记录一下结点,好返回,因为下面会改变cur
    282. Node* newnode = cur;
    283. cur->_col = RED;//把结点以红色插入
    284. if (kot(parent->_data) < kot(data))//比较去调用KeyOfT对象的重载的()
    285. {
    286. parent->_right = cur;
    287. cur->_parent = parent;
    288. }
    289. else
    290. {
    291. parent->_left = cur;
    292. cur->_parent = parent;
    293. }
    294. //进行红黑树的控制
    295. while (parent && parent->_col==RED)//父节点位黑或者不存在就结束了
    296. {
    297. Node*gradparent = parent->_parent; //这里的祖父一定是存在的,因为parent->_col==RED,所以parent不可能是根节点
    298. if (gradparent->_left==parent)//在左边进行插入的
    299. {
    300. Node* uncle = gradparent->_right;
    301. if (uncle && uncle->_col == RED)//u存在且为红色,情况1
    302. {
    303. uncle->_col = BLACK;
    304. parent->_col = BLACK;
    305. gradparent->_col = RED;
    306. cur = gradparent;//把祖父当成新增结点
    307. parent = cur->_parent;
    308. }
    309. else //u不存在或为黑
    310. {
    311. if (parent->_left==cur) //在parent插入左边插入节点,情况2
    312. {
    313. //单旋
    314. // g
    315. // p u(存在为黑,或不存在)
    316. // c
    317. RoateR(gradparent);
    318. gradparent->_col = RED;
    319. parent->_col = BLACK;
    320. }
    321. else //在parent的右边插入节点 ,情况3
    322. {
    323. //双旋
    324. // g
    325. // p u
    326. // c
    327. RoateL(parent);
    328. RoateR(gradparent);
    329. cur->_col = BLACK;
    330. gradparent->_col = RED;
    331. }
    332. break;
    333. }
    334. }
    335. else //gradparent->_left==parent,在树的右边插入了节点
    336. {
    337. Node*uncle = gradparent->_left;
    338. if (uncle && uncle->_col==RED)//情况1 u存在且为红
    339. {
    340. parent->_col = BLACK;
    341. uncle->_col = BLACK;
    342. gradparent->_col = RED;
    343. cur = gradparent;
    344. parent = cur->_parent;
    345. }
    346. else //u不存在或着u为黑
    347. {
    348. // g
    349. //u p
    350. // cur
    351. if (parent->_right == cur)//情况2
    352. {
    353. //进行左单旋
    354. RoateL(gradparent);
    355. parent->_col = BLACK;
    356. gradparent->_col = RED;
    357. }
    358. // g
    359. //u p
    360. // c
    361. else //情况3
    362. {
    363. //双旋
    364. RoateR(parent);
    365. RoateL(gradparent);
    366. cur->_col = BLACK;
    367. gradparent->_col = RED;
    368. }
    369. break;
    370. }
    371. }
    372. }
    373. _root->_col = BLACK;//不管是子树还是根节点都需要是黑色
    374. return make_pair(iterator(newnode),true);
    375. }
    376. //析构函数
    377. ~RBTtree()
    378. {
    379. Destory(_root);
    380. _root = nullptr;
    381. }
    382. void Destory(Node*root)
    383. {
    384. if (root == nullptr)
    385. return;
    386. Destory(root->_left);
    387. Destory(root->_right);
    388. delete root;
    389. }
    390. private:
    391. Node* _root;
    392. };
    393. }

    my_set.h

    1. #pragma once
    2. #include"RBTree.h"
    3. namespace zcf
    4. {
    5. template<class K>
    6. class set
    7. {
    8. public:
    9. struct SetKeyOfT
    10. {
    11. const K& operator()(const K& k)
    12. {
    13. return k; //直接返回key
    14. }
    15. };
    16. typedef typename RBTtree::iterator iterator; //迭代器
    17. pairbool> insert(const K& key)
    18. {
    19. return _t.insert(key);
    20. }
    21. iterator begin()
    22. {
    23. return _t.begin();
    24. }
    25. iterator end()
    26. {
    27. return _t.end();
    28. }
    29. iterator find(const K& key)
    30. {
    31. return _t.find(key);
    32. }
    33. protected:
    34. RBTtree _t; //关键,set知道自己是key,传的是key
    35. //set知道怎么比较SetKeyOfT
    36. };
    37. void test_set()
    38. {
    39. set<int> s;
    40. s.insert(1);
    41. s.insert(2);
    42. s.insert(3);
    43. set<int>::iterator it = s.begin();
    44. while (it!=s.end())
    45. {
    46. cout << *it<<" ";
    47. ++it;
    48. }
    49. cout << endl;
    50. set<int> s1(s);//拷贝构造
    51. set<int>::iterator it1 = s1.begin();
    52. while (it1 != s1.end())
    53. {
    54. cout << *it1 << " ";
    55. ++it1;
    56. }
    57. cout << endl;
    58. set<int> s2;
    59. s2 = s1; //赋值运算
    60. set<int>::iterator it2 = s2.begin();
    61. while (it2 != s2.end())
    62. {
    63. cout << *it2 << " ";
    64. ++it2;
    65. }
    66. cout << endl;
    67. }
    68. }

    my_map.h

    1. #pragma once
    2. #include"RBTree.h"
    3. namespace zcf
    4. {
    5. template<class K,class V>
    6. class map
    7. {
    8. public:
    9. struct MapKeyOfT //提供一个内置类
    10. {
    11. const K& operator()(const pair& kv)
    12. {
    13. return kv.first; //使用key进行比较,返回pair的第一个值
    14. }
    15. };
    16. //注意这里
    17. typedef typename RBTtree, MapKeyOfT>::iterator iterator;//迭代器
    18. pairbool> insert(const pair& kv)
    19. {
    20. return _t.insert(kv);
    21. }
    22. iterator begin()
    23. {
    24. return _t.begin();
    25. }
    26. iterator end()
    27. {
    28. return _t.end();
    29. }
    30. iterator find(const K& key)
    31. {
    32. return _t.find(key);
    33. }
    34. V& operator[](const K&key)
    35. {
    36. auto ret=_t.insert(make_pair(key,V()));//给缺省值
    37. //ret是pair对象
    38. return ret.first->second;//调用迭代器的operator->()
    39. }
    40. protected:
    41. RBTtree, MapKeyOfT> _t; //这里是关键,map知道自己是pair,所以传的pair
    42. //比较也是这样的,map知道怎么比较MapKeyOfT
    43. };
    44. void test_map()
    45. {
    46. map dict;
    47. dict.insert(make_pair("left","左"));
    48. dict.insert(make_pair("right", "右"));
    49. dict.insert(make_pair("map", "地图"));
    50. dict["map"] = "地图或映射"; //修改second
    51. dict["state"] = "状态"; //新增
    52. auto it = dict.begin();
    53. while (it!=dict.end())
    54. {
    55. cout << it->first << ":" << it->second << endl;
    56. ++it;
    57. }
    58. cout << endl;
    59. map dict1(dict);//拷贝构造
    60. auto it1 = dict.begin();
    61. while (it1 != dict1.end())
    62. {
    63. cout << it1->first << ":" << it1->second << endl;
    64. ++it1;
    65. }
    66. cout << endl;
    67. }
    68. }

    main.cpp

    1. #include
    2. #include
    3. using namespace std;
    4. #include"my_set.h"
    5. #include"my_map.h"
    6. int main()
    7. {
    8. zcf::test_set();
    9. zcf::test_map();
    10. return 0;
    11. }

     对于迭代器相对比较难的是++:

  • 相关阅读:
    【微服务】服务容错---Sentinel
    运维监控Zabbix部署
    PY32F003F18按键输入
    老卫带你学---leetcode刷题(124. 二叉树中的最大路径和)
    应用层 - 常见协议、域名、DNS、DHCP、HTTP、form提交、正向代理反向代理、CDN
    【GEE】基于GEE进行非监督学习
    【C++】C&C++内存管理
    【Verilog基础】一些时序约束相关的面试真题
    Source Map知多少?Golang手写SourceMap转换过程
    VUE3中 reacitive源码理解
  • 原文地址:https://blog.csdn.net/qq_37303158/article/details/126041837