C++红黑树(2)

简介: C++红黑树(2)

四、红黑树的验证


  • 红黑树的检测分为两步:


  1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)


  1. 检测其是否满足红黑树的性质


  • 实现代码:


bool IsRBTree()
{
    //空树
    if (_root == nullptr)
    {
        return true;
    }
    //根节点为黑色
    if (_root->_col == RED)
    {
        cout << "根节点为红色" << endl;
        return false;
    }
    //黑色结点数量各路径上相同
    //先走一条得到基准值
    int Blacknum = 0;
    Node* cur = _root;
    while (cur)
    {
        if (cur->_col == BLACK)
            Blacknum++;
        cur = cur->_left;
    }
    //检查子树
    int i = 0;
    return _IsRBTree(_root, Blacknum, i);
}
bool _IsRBTree(Node* root, int blacknum, int count)
{
    //递归到空节点
    if (root == nullptr)
    {
        if (blacknum == count)
            return true;
        cout << "各路径上黑色节点个数不同" << endl;
        return false;
    }
  //子节点为红则检查父节点是否为红(通过父节点检查子节点会遇到空节点)
    if (root->_col == RED && root->_parent->_col == RED)
    {
        cout << "存在连续红色节点" << endl;
        return false;
    }
  //计数黑结点
    if (root->_col == BLACK)
        count++;
  //递归左右子树
    return _IsRBTree(root->_left, blacknum, count) && _IsRBTree(root->_right, blacknum, count);
}


五、红黑树的删除


红黑树的删除不做讲解,有兴趣可参考:《算法导论》或者《STL源码剖析》

http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html

http://blog.csdn.net/chenhuajie123/article/details/11951777


六、红黑树与AVL树的比较


分析总结:

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O( )


红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数


所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多


附上源码


RBTree.h:


#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
//颜色
enum Colour
{
  RED,
  BLACK,
};
template<class K, class V>
struct RBTreeNode
{
  RBTreeNode<K, V>* _left;
  RBTreeNode<K, V>* _right;
  RBTreeNode<K, V>* _parent;
  pair<K, V> _kv;
  Colour _col;
  RBTreeNode(const pair<K, V>& kv)
    :_left(nullptr)
    , _right(nullptr)
    , _parent(nullptr)
    , _kv(kv)
    , _col(RED)
  {}
};
template<class K, class V>
class RBTree
{
  typedef RBTreeNode<K, V> Node;
public:
  RBTree()
    :_root(nullptr)
  {
  }
  void _Destory(Node*& root)
  {
    if (root == nullptr)
      return;
    _Destory(root->_left);
    _Destory(root->_right);
    delete root;
    root = nullptr;
  }
  ~RBTree()
  {
    _Destory(_root);
  }
  Node* Find(const K& key)
  {
    Node* cur = _root;
    while (cur)
    {
      if (cur->_kv.first > key)
      {
        cur = cur->_left;
      }
      else if (cur->_kv.first < key)
      {
        cur = cur->_right;
      }
      else
      {
        return cur;
      }
    }
    return nullptr;
  }
  pair<Node*, bool> Insert(const pair<K, V>& kv)
  {
    //空树的情况
    if (_root == nullptr)
    {
      _root = new Node(kv);
      _root->_col = BLACK;
      return make_pair(_root, true);
    }
    //查找位置插入节点
    Node* cur = _root, * parent = _root;
    while (cur)
    {
      if (cur->_kv.first > kv.first)
      {
        parent = cur;
        cur = cur->_left;
      }
      else if (cur->_kv.first < kv.first)
      {
        parent = cur;
        cur = cur->_right;
      }
      else
      {
        return make_pair(cur, false);
      }
    }
    //创建链接节点
    cur = new Node(kv);
    Node* newnode = cur;
    if (parent->_kv.first > kv.first)
    {
      parent->_left = cur;
    }
    else
    {
      parent->_right = cur;
    }
    cur->_parent = parent;
    //父节点存在且为红,则需要调整(不能存在连续的红色节点)
    while (parent && parent->_col == RED)
    {
      //此时当前节点一定有祖父节点
      Node* granparent = parent->_parent;
      //具体调整情况主要看叔叔节点
      //分左右讨论
      if (parent == granparent->_left)
      {
        Node* uncle = granparent->_right;
        //情况1:叔叔节点存在且为红
        if (uncle && uncle->_col == RED)
        {
          //修改颜色,继续向上检查
          granparent->_col = RED;
          parent->_col = uncle->_col = BLACK;
          cur = granparent;
          parent = cur->_parent;
        }
        else//情况2和3:叔叔节点不存在 或者存在且为黑
        {
          //单旋(三代节点为斜线)+变色
          if (cur == parent->_left)
          {
            RotateR(granparent);
            granparent->_col = RED;
            parent->_col = BLACK;
          }
          else//双旋(三代节点为折线)+变色
          {
            RotateL(parent);
            RotateR(granparent);
            cur->_col = BLACK;
            granparent->_col = RED;
          }
          //旋转后不需再向上调整了
          break;
        }
      }
      else//parent=grandparent->right
      {
        Node* uncle = granparent->_left;
        if (uncle && uncle->_col == RED)
        {
          parent->_col = uncle->_col = BLACK;
          granparent->_col = RED;
          cur = granparent;
          parent = cur->_parent;
        }
        else
        {
          if (cur == parent->_right)
          {
            RotateL(granparent);
            parent->_col = BLACK;
            granparent->_col = RED;
          }
          else
          {
            RotateR(parent);
            RotateL(granparent);
            cur->_col = BLACK;
            granparent->_col = RED;
          }
          break;
        }
      }
    }
    //确保根节点为黑
    _root->_col = BLACK;
    return make_pair(newnode, true);
  }
  bool IsRBTree()
  {
    if (_root == nullptr)
    {
      return true;
    }
    if (_root->_col == RED)
    {
      cout << "根节点为红色" << endl;
      return false;
    }
    int Blacknum = 0;
    Node* cur = _root;
    while (cur)
    {
      if (cur->_col == BLACK)
        Blacknum++;
      cur = cur->_left;
    }
    int i = 0;
    return _IsRBTree(_root, Blacknum, i);
  }
private:
  bool _IsRBTree(Node* root, int blacknum, int count)
  {
    if (root == nullptr)
    {
      if (blacknum == count)
        return true;
      cout << "各路径上黑色节点个数不同" << endl;
      return false;
    }
    if (root->_col == RED && root->_parent->_col == RED)
    {
      cout << "存在连续红色节点" << endl;
      return false;
    }
    if (root->_col == BLACK)
      count++;
    return _IsRBTree(root->_left, blacknum, count) && _IsRBTree(root->_right, blacknum, count);
  }
  void RotateL(Node* parent)
  {
    Node* subR = parent->_right;
    Node* subRL = subR->_left;
    Node* parentP = parent->_parent;
    parent->_right = subRL;
    if (subRL)
    {
      subRL->_parent = parent;
    }
    subR->_left = parent;
    parent->_parent = subR;
    if (parent == _root)
    {
      _root = subR;
      subR->_parent = nullptr;
    }
    else
    {
      subR->_parent = parentP;
      if (parentP->_left == parent)
      {
        parentP->_left = subR;
      }
      else
      {
        parentP->_right = subR;
      }
    }
  }
  void RotateR(Node* parent)
  {
    Node* subL = parent->_left;
    Node* subLR = subL->_right;
    Node* parentP = parent->_parent;
    parent->_left = subLR;
    if (subLR)
    {
      subLR->_parent = parent;
    }
    subL->_right = parent;
    parent->_parent = subL;
    if (parent == _root)
    {
      _root = subL;
      subL->_parent = nullptr;
    }
    else
    {
      subL->_parent = parentP;
      if (parentP->_left == parent)
      {
        parentP->_left = subL;
      }
      else
      {
        parentP->_right = subL;
      }
    }
  }
private:
  Node* _root;
};


  • test.cpp:


#define _CRT_SECURE_NO_WARNINGS 1
#include "RBTree.h"
#include <vector>
#include <string>
#include <stdlib.h>
#include <time.h>
void TestRBTree()
{
  //int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
  //int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
  RBTree<int, int> t;
  int n = 1000000;
  srand(time(0));
  for (int i = 0; i < n; ++i)
  {
    int e = rand();
    t.Insert(make_pair(e, e));
  }
  //t.InOrder();
  cout << t.IsRBTree() << endl;
}
void test_RBTree()
{
  int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
  RBTree<int, int> t;
  for (auto e : a)
  {
    t.Insert(make_pair(e, e));
  }
  cout << t.IsRBTree() << endl;
}
int main()
{
    test_RBTree();
  TestRBTree();
  return 0;
}
相关文章
|
6月前
|
C++
c++的学习之路:27、红黑树
c++的学习之路:27、红黑树
51 4
|
6月前
|
测试技术 C++
C++进阶--红黑树
C++进阶--红黑树
|
6月前
|
编译器 C++ 容器
【C++学习手札】基于红黑树封装模拟实现map和set
【C++学习手札】基于红黑树封装模拟实现map和set
|
6月前
|
存储 关系型数据库 数据库
【数据结构】—红黑树(C++实现)
【数据结构】—红黑树(C++实现)
|
6月前
|
C++ 容器
【C++】红黑树模拟实现STL中的map与set
【C++】红黑树模拟实现STL中的map与set
|
3月前
|
关系型数据库 C++ 容器
【C++航海王:追寻罗杰的编程之路】关联式容器的底层结构——红黑树
【C++航海王:追寻罗杰的编程之路】关联式容器的底层结构——红黑树
35 0
|
4月前
|
Java C++ Python
【C++】手撕红黑树
【C++】手撕红黑树
26 1
|
6月前
|
Java C语言 C++
从C语言到C++_28(红黑树RedBlackTree)概念+插入接口实现(上)
从C语言到C++_28(红黑树RedBlackTree)概念+插入接口实现
52 4
|
6月前
|
C语言
从C语言到C++_29(红黑树封装set和map)红黑树迭代器的实现(下)
从C语言到C++_29(红黑树封装set和map)红黑树迭代器的实现
47 3
|
5月前
|
关系型数据库 C++
【c++】红黑树
【c++】红黑树
23 0