PAT甲级1135----红黑树题解

题目描述

  1. Is It A Red-Black Tree (30)
    时间限制
    400 ms
    内存限制
    65536 kB
    代码长度限制
    16000 B
    判题程序
    Standard
    作者
    CHEN, Yue

There is a kind of balanced binary search tree named red-black tree in the data structure. It has the following 5 properties:

(1) Every node is either red or black.
(2) The root is black.
(3) Every leaf (NULL) is black.
(4) If a node is red, then both its children are black.
(5) For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.

For example, the tree in Figure 1 is a red-black tree, while the ones in Figure 2 and 3 are not.

Figure 1

Figure 2

Figure 3

For each given binary search tree, you are supposed to tell if it is a legal red-black tree.

Input Specification:

Each input file contains several test cases. The first line gives a positive integer K (<=30) which is the total number of cases. For each case, the first line gives a positive integer N (<=30), the total number of nodes in the binary tree. The second line gives the preorder traversal sequence of the tree. While all the keys in a tree are positive integers, we use negative signs to represent red nodes. All the numbers in a line are separated by a space. The sample input cases correspond to the trees shown in Figure 1, 2 and 3.

Output Specification:

For each test case, print in a line “Yes” if the given tree is a red-black tree, or “No” if not.
Sample Input:

3
9
7 -2 1 5 -4 -11 8 14 -15
9
11 -2 1 -7 5 -4 8 14 -15
8
10 -7 5 -6 8 15 -11 17

Sample Output:

Yes
No
No

红黑树性质

红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个叶节点(NIL节点,空节点)是黑色的。
性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

题目理解

对于这题,数据域为正的节点为黑结点,数据域为负的是红节点。然后忽略正负,他是一个二叉搜索树,这就给了我们由前序遍历建树的条件。建完树后判断。
如何判断二叉树。根据题目描述的性质,我们要进行如下三点判断
1、根节点是否为正数
2、节点为负数的节点的孩子是否为正数
3、从根节点到叶子节点所有路径拥有相同的黑色节点
第三点是有第五条性质决定的
因为如果满足我们的第三条判断,那么从根节点的子孩子出发到达叶子节点的所有路径拥有的黑色节点必然相同,层层递归下去,就是性质五

建离二叉链树

/*
**per[perL~preR]之间代表的是二叉子树前序遍历,初始值因为整棵树
*/
Tree* buildTree(int preL,int preR){
  //如果左索引比右索引说明递归到的是叶子节点的子节点,自然为NULL
  if(preL>preR)
    return NULL;
  Tree *tree = new Tree(pre[preL]);
  //在前序数组中,找到第一个比根节点大的节点即为右子树的根节点
  int i = preL+1;
  for(;i<=preR;++i){
    if(abs(pre[i])>abs(pre[preL])){
      break;
    }
  }
  //递归建立左右子树
  tree->left = buildTree(preL+1,i-1);
  tree->right = buildTree(i,preR);
  //返回根节点
  return tree;
}

红黑树判断

/*
**@tree 根节点
**@isRedroot 根节点是否为红色如果是红色就要判断当前节点是不是黑了
**@num_blacknodes 记录当前路径已经遍历的黑色节点个数
**
**@flag 初始值为true,他只有改为false的机会,只要我们某一次判断是错的他的值变永久性改为false
**@first 状态位,是不是第一次到达叶子节点
**@num 记录第一次到达叶子节点时经过的黑色节点个数,并作为判断从根节点出发到叶子节点的其他路径是否与第一次相等的凭借
*/
void judge(Tree *tree,bool isRedroot,int num_blacknodes){
  //如果当前节点为空,代表父节点为叶子节点
  if(tree==NULL){
    //如果第一次抵达叶子节点,那么用num存储,黑色节点的个数
    if(first){
      num = num_blacknodes;
      first = false;
    }else{
      //如果不是第一次,就进行红黑树的第五条性质判断
      if(num!=num_blacknodes){
        flag = false;
      }
    }
  }else{
   //记录当前节点颜色
    bool isBlack = tree->data>0;
    //如果父节点是红色,而当前节点也是红色,那么就不是红黑树
    if(isRedroot&&!isBlack){
      flag = false;
    }
    judge(tree->left,!isBlack,num_blacknodes+isBlack);
    judge(tree->right,!isBlack,num_blacknodes+isBlack);
  }
}

完整代码

#include <iostream>
#include <cmath>

using namespace std;

struct Tree{
  int data;
  Tree *left;
  Tree *right;
  Tree(int d):data(d){}
};

int pre[30];

Tree* buildTree(int preL,int preR){
  if(preL>preR)
    return NULL;
  Tree *tree = new Tree(pre[preL]);
  int i = preL+1;
  for(;i<=preR;++i){
    if(abs(pre[i])>abs(pre[preL])){
      break;
    }
  }
  tree->left = buildTree(preL+1,i-1);
  tree->right = buildTree(i,preR);
  return tree;
}

void freeMemory(Tree *tree){
  if(tree!=NULL){
    freeMemory(tree->left);
    freeMemory(tree->right);
    delete tree;
    tree = NULL;
  }
}

bool flag,first;
int num;

void judge(Tree *tree,bool isRedroot,int num_blacknodes){
  if(tree==NULL){
    if(first){
      num = num_blacknodes;
      first = false;
    }else{
      if(num!=num_blacknodes){
        flag = false;
      }
    }
  }else{
    bool isBlack = tree->data>0;
    if(isRedroot&&!isBlack){
      flag = false;
    }
    judge(tree->left,!isBlack,num_blacknodes+isBlack);
    judge(tree->right,!isBlack,num_blacknodes+isBlack);
  }
}

int main(int argc, char const *argv[])
{
  int K;
  cin >> K;
  for (int i = 0; i < K; ++i)
  {
    int N;
    cin >> N;
    flag = first = true;
    num = 0;
    for (int j = 0; j < N; ++j)
    {
      cin >> pre[j];
    }
    Tree *tree = buildTree(0,N-1);
    if(tree->data<0){
      flag = false;
    }else{
      judge(tree,false,0);
    }
    cout << (flag?"Yes":"No") << endl;
    freeMemory(tree);
  }
  return 0;
}

没有更多推荐了,返回首页