【C++】-- 红黑树详解(三)

简介: 【C++】-- 红黑树详解

4.红黑树节点插入代码

1.  //插入
2.  pair<Node*, bool> Insert(const pair<K, V>& kv)
3.  {
4.    if (_root == nullptr)
5.    {
6.      _root = new Node(kv);
7.      _root->_col = BLACK;
8.      return make_pair(_root, true);
9.    }
10. 
11.     //1.先看树中,kv是否存在
12.     Node* parent = nullptr;
13.     Node* cur = _root;
14.     while (cur)
15.     {
16.       if (cur->_kv.first < kv.first)
17.       {
18.         //kv比当前节点值大,向右走
19.         parent = cur;
20.         cur = cur->_right;
21.       }
22.       else if (cur->_kv.first > kv.first)
23.       {
24.         //kv比当前节点值小,向左走
25.         parent = cur;
26.         cur = cur->_left;
27.       }
28.       else
29.       {
30.         //kv和当前节点值相等,已存在,插入失败
31.         return make_pair(cur, false);
32.       }
33.     }
34. 
35.     //2.走到这里,说明kv在树中不存在,需要插入kv,并且cur已经为空,parent已经是叶子节点了
36.     Node* newNode = new Node(kv);
37.     newNode->_col = RED;
38.     if (parent->_kv.first < kv.first)
39.     {
40.       //kv比parent值大,插入到parent的右边
41.       parent->_right = newNode;
42.       cur->_parent = parent;
43.     }
44.     else
45.     {
46.       //kv比parent值小,插入到parent的左边
47.       parent->_left = newNode;
48.       cur->_parent = parent;
49.     }
50.     cur = newNode;
51. 
52.     //如果父亲存在,且父亲颜色为红就要处理
53.     while (parent && parent->_col == RED)
54.     {
55.       //关键看叔叔
56.       Node* grandfather = parent->_parent;
57.       if (parent == grandfather->_left)//父亲是祖父的左子树
58.       {
59.         Node* uncle = grandfather->_right;
60.         //情况一:叔叔存在且为红
61.         if (uncle->_col == RED)
62.         {
63.           parent->_col = uncle->_col = BLACK;
64.           grandfather->_col = RED;
65. 
66.           //继续向上调整
67.           cur = grandfather;
68.           parent = cur->_parent;
69.         }
70.         else//情况二+情况三:叔叔不存在或叔叔存在且为黑
71.         {
72.           //情况二:单旋
73.           if (cur == parent->_left)
74.           {
75.             RotateR(grandfather);
76.             parent->_col = BLACK;
77.             grandfather->_col = RED;
78.           }
79.           else//情况三:双旋
80.           {
81.             RotateL(parent);
82.             RotateR(grandfather);
83.             cur->_col = BLACK;
84.             grandfather->_col = RED;
85.           }
86.           break;//插入结束
87.         }
88.       }
89.       else//父亲是祖父的右子树
90.       {
91.         Node* uncle = grandfather->_left;
92.         //情况一:叔叔存在且为红
93.         if (uncle && uncle->_col == RED)
94.         {
95.           parent->_col = uncle->_col = BLACK;
96.           grandfather->_col = RED;
97. 
98.           //继续往上调整
99.           cur = grandfather;
100.          parent = grandfather->_parent;
101.        }
102.        else//情况二+情况三:叔叔不存在或叔叔存在且为黑
103.        {
104.          //情况二:单旋
105.          if (cur == parent->_right)
106.          {
107.            RotateL(grandfather);
108.            parent->_col = BLACK;
109.            grandfather->_col = RED;
110.          }
111.          else//情况三:双旋
112.          {
113.            RotateR(parent);
114.            RotateL(grandfather);
115.            cur->_col = BLACK;
116.            grandfather->_col = RED;
117.          }
118.          break;//插入结束
119.        }
120.      }
121. 
122.    }
123.    _root->_col = BLACK;
124. 
125.    return make_pair(newNode, true);
126.  }

五、红黑树查找

查找比较简单,递归向左走或向右走:

1.  //查找
2.  Node* Find(const K& key)
3.  {
4.    Node* cur = _root;
5.    while (cur)
6.    {
7.      if (cur->_kv.first < key)//key比当前节点小,就向右查找
8.      {
9.        cur = cur->_right;
10.       }
11.       else if (cur->_kv.first > key)//key比当前节点大,就向左查找
12.       {
13.         cur = cur->_left;
14.       }
15.       else//找到了
16.       {
17.         return cur;
18.       }
19.     }
20.     return nullptr;//空树,直接返回
21.   }

六、红黑树检查是否平衡

检查是否平衡还是要用到递归子函数

(1)需要判断是否满足红黑树的4条性质

(2)计算最左路径上的黑色节点个数,递归路径时,需要计算该条路径上的黑色节点个数是否和最左路径上的节点个数相等

1.  bool _CheckBalance(Node* root, int blackNum, int count)
2.  {
3.    if (root == nullptr)
4.    {
5.      if (count != blackNum)
6.      {
7.        cout << "黑色节点数量不相等" << endl;
8.        return false;
9.      }
10.       return true;
11.     }
12. 
13.     if (root->_col == RED && root->_parent->_col == RED)
14.     {
15.       cout << "存在连续红色节点" << endl;
16.       return false;
17.     }
18. 
19.     if (root->_col == BLACK)
20.     {
21.       count++;
22.     }
23. 
24.     return _CheckBalance(root->_left, blackNum, count)
25.       && _CheckBalance(root->_right, blackNum, count);
26.   }
27. 
28.   //检查是否平衡
29.   bool CheckBlance()
30.   {
31.     if (_root == nullptr)
32.     {
33.       return true;
34.     }
35. 
36.     if (_root->_col == RED)
37.     {
38.       cout << "根节点为红色" << endl;
39.       return false;
40.     }
41. 
42.     //找最左路径做黑色节点数量参考值
43.     int blackNum = 0;
44.     Node* left = _root;
45.     while (left)
46.     {
47.       if (left->_col == BLACK)
48.       {
49.         blackNum++;
50.       }
51.       left = left->_left;
52.     }
53. 
54.     int count = 0;
55.     return _CheckBlance(_root, blackNum, count);
56.   }

对于以下红黑树,递归过程如下:

七、红黑树遍历

遍历也很简单,中序递归遍历左子树和右子树:

1.  //遍历
2.  void _InOrder(Node* root)
3.  {
4.    if (root == nullptr)
5.    {
6.      return;
7.    }
8. 
9.    _InOrder(root->_left);
10.     cout << root->_kv.first << ":" << root->_kv.second << endl;
11.     _InOrder(root->_right);
12.   }
13. 
14.   void InOrder()
15.   {
16.     _InOrder(_root);
17.     cout << endl;
18.   }

八、红黑树验证

1. #include "RedBlackTree.h"
2. 
3. void TestRBTree()
4. {
5.  //,1,3,5,15,7,16,14
6.  int a[] = { 4,2,6,1,3,5,15,7,16 };
7.  RBTree<int, int> t;
8.  for (auto e : a)
9.  {
10.     t.Insert(make_pair(e, e));
11.   }
12. 
13.   t.InOrder();
14.   //cout << t.CheckBalance() << endl;
15. }
16. 
17. int main()
18. {
19.   TestRBTree();
20.   return 0;
21. }

插入成功:

相关文章
|
23天前
|
存储 缓存 监控
用 C++ 红黑树给公司电脑监控软件的日志快速排序的方法
本文介绍基于C++红黑树算法实现公司监控电脑软件的日志高效管理,利用其自平衡特性提升日志排序、检索与动态更新效率,并结合实际场景提出优化方向,增强系统性能与稳定性。
53 4
|
7月前
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
191 2
|
4月前
|
存储 C++
c++ 红黑树(带头结点)(k,k型)
想必在看到这篇文章的时候,你一定是带着问题去搜索的,一定是对红黑树已经有了初步大致的认识,已经知道了红黑树的性质与普通红黑树的功能与如何代码实现,但是莫一天突然看到了带头结点的红黑树,肯定是对此有一些疑惑的,或者来说在代码的实现上自己存在着某些疑惑。那么话不多说,就先给出红黑树(带头结点)的完整实现代码。然后再给出相应的详细解释。
88 0
|
4月前
|
Java C++
c++ 红黑树(自平衡二叉搜索树)(k,v型)
因为红黑树是一种特殊的AVL树(但少了平衡因子的存在),所以其结点的定义是在AVL树上加上新的成员变量,用于表示结点的颜色。RED,BLACK,//三叉链, _kv(kv){}首先我们在默认构造上,默认构造结点的颜色默认情况下为红色所以为什么构造结点时,默认将结点的颜色设置为红色?这是因为:当我们向红黑树插入结点时,若我们插入的是黑色结点,那么插入路径上黑色结点的数目就比其他路径上黑色结点的数目多了一个,即破坏了红黑树的性质4,此时我们就需要对红黑树进行调整。
102 0
|
10月前
|
存储 算法 安全
基于红黑树的局域网上网行为控制C++ 算法解析
在当今网络环境中,局域网上网行为控制对企业和学校至关重要。本文探讨了一种基于红黑树数据结构的高效算法,用于管理用户的上网行为,如IP地址、上网时长、访问网站类别和流量使用情况。通过红黑树的自平衡特性,确保了高效的查找、插入和删除操作。文中提供了C++代码示例,展示了如何实现该算法,并强调其在网络管理中的应用价值。
|
11月前
|
存储 C++
【C++】红黑树
红黑树是一种自平衡二叉搜索树,通过节点颜色(红或黑)及特定规则维持平衡,确保操作效率。其性质包括:每个节点非红即黑,根节点必黑,红节点的子节点必黑,从任一节点到其每个叶子的所有路径含相同数量的黑节点。实现上,通过节点结构定义、基本操作(插入、删除、旋转等)、维护平衡性质等步骤完成。代码示例展示了节点定义、插入操作及旋转调整方法。
162 2
【C++】红黑树
|
C++ 容器
【C++】红黑树模拟实现STL中的map与set
【C++】红黑树模拟实现STL中的map与set
|
Java C++ Python
【C++】手撕红黑树
【C++】手撕红黑树
96 1
|
关系型数据库 C++ 容器
【C++航海王:追寻罗杰的编程之路】关联式容器的底层结构——红黑树
【C++航海王:追寻罗杰的编程之路】关联式容器的底层结构——红黑树
101 0
|
Java C语言 C++
从C语言到C++_28(红黑树RedBlackTree)概念+插入接口实现(上)
从C语言到C++_28(红黑树RedBlackTree)概念+插入接口实现
139 4