3、如何判断一棵树是否是红黑树?

时间:2022-08-26 21:28:57

一、红黑树的定义

红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。除了二叉查找树强制的一般要求以外,对于任何有效的红黑树有如下的额外要求:

  • 性质1. 节点是红色或黑色。

  • 性质2. 根节点是黑色。

  • 性质3 每个叶节点(NIL节点,空节点)是黑色的。

  • 性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

  • 性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点

二、如何判断是否是红黑树(假设正数代表黑色,负数代表红色)

1、中序遍历树,如何序列是递增的,则是二叉查找树,继续下一步。否则不是,结束。

2、如果根是黑色,继续下一步,否则结束。

3、对树的层序遍历的逆序列(队列+栈)一一遍历。判断以当前结点为根结点的树是否是红黑树(从边界开始,递推判断)。

map<Node*, int> mp;//以当前结点的指针为Key,值为当前结点到每个叶子的黑色结点的数目
  • 若当前结点的孩子结点为空时,则当前结点是红黑树。

  • 若左孩子和右孩子到叶子节点的黑色结点数不同,结束。

  • 若存在左孩子且当前结点和左孩子的颜色都为红色,结束。

  • 若存在右孩子且当前结点和右孩子的颜色都为红色,结束。

  • 经以上判断后,以当前结点为根的树是红黑树。则,若当前结点为红色,当前结点到每个叶子的黑色结点的数目等于任一孩子到叶子节点的黑色结点数。

若当前结点为黑色,当前结点到每个叶子的黑色结点的数目等于任一孩子到叶子节点的黑色结点数+1。

 

代码:

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <map>
using namespace std;


struct Node {

    int data;
    Node *lchild, *rchild;
};

bool isRedBlock;
vector<int> pre, in;
queue<Node*> Q;
stack<Node*> st;
map<Node*, int> mp;


//前序和中序建树
Node* create(int preL, int preR, int inL, int inR) {
    if (preL > preR) return NULL;
    Node* root = new Node;
    root->data = pre[preL];
    int k;
    for (k = inL; k <= inR; k++) {
        if (in[k] == pre[preL]) break;
    }
    int numleft = k - inL;
    root->lchild = create(preL + 1, preL + numleft, inL, k - 1);
    root->rchild = create(preL + numleft + 1, preR, k + 1, inR);
    return root;
}

bool cmp(int a, int b) {
    return abs(a) < abs(b);
}
void layertraverse(Node* root) {
    Q.push(root);
    while (!Q.empty()) {
        Node* front = Q.front();
        Q.pop();
        st.push(front);
        if (front->lchild != NULL) Q.push(front->lchild);
        if (front->rchild != NULL) Q.push(front->rchild);
    }
}

bool isRedSeq(Node* root) {
    bool flag = false;
    if (root->lchild != NULL&& root->data < 0 && root->lchild->data < 0) flag = true;
    if (root->rchild != NULL && root->data < 0 && root->rchild->data < 0) flag = true;
    return flag;
}
void judge() {
    while (!st.empty()) {
        Node* top = st.top();
        st.pop();
        if (top->lchild == NULL && top->rchild == NULL) {
            if (top->data > 0) mp[top] = 1;
            else mp[top] = 0;
        }
        else{
            if (mp[top->lchild] == mp[top->rchild]) {
                
                if (isRedSeq(top)) {
                    isRedBlock = false;
                    break;
                }
                if (top->data > 0) mp[top] = mp[top->lchild] + 1;
                else mp[top] = mp[top->lchild];
            }
            else {
                isRedBlock = false;
                break;
            }
        }
    }
}
int main(){
    int k, n;
    scanf("%d", &k);
    for (int i = 0; i < k; i++) {
        pre.clear();
        in.clear();
        while (!st.empty()) st.pop();
        while (!Q.empty()) Q.pop();
        mp.clear();
        isRedBlock = true;
        
        scanf("%d", &n);
        pre.resize(n);
        for (int j = 0; j < n; j++) scanf("%d", &pre[j]);
        in = pre;
        sort(in.begin(), in.end(), cmp);
        Node* root = create(0, n - 1, 0, n - 1);
        if (root->data > 0) {
            layertraverse(root);
            judge();
        }
        else isRedBlock = false;
        printf("%s\n", isRedBlock == true ? "Yes" : "No");
    }
    return 0;
}