PAT_甲级_1135 Is It A Red-Black Tree (30point(s)) (C++)【红黑树/先序+中序构建二叉树/判断红黑树性质】

目录

1,题目描述

题目大意

 知识补充

2,思路

数据结构

算法

3,AC代码

4,解题过程


1,题目描述

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) Every node is either red or black.:节点非黑即红;
  • (2) The root is black.:根节点为黑色(根节点大于0);
  • (3) Every leaf (NULL) is black.:规定空节点(NULL)为黑色;
  • (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.:对每个结点,从该节点向下延申到每个叶子节点的路径中,所有路径含有的黑色节点数目相同;

 知识补充

这篇文章讲解的很详细@hucongWh【红黑树】

这篇文章介绍实例,动态构建红黑树,挺有意思@日拱一兵【红黑树,超强动静图详解,简单易懂】

 

2,思路

(解决这道题不需要对红黑树有很深刻的认识,只需要判断是否符合性质即可)

用到先序加中序遍历构建二叉树,具体操作可以参考这里@&再见萤火虫&【PAT_甲级_1020 Tree Traversals (25分) (C++)【树的遍历】】

数据结构

  • struct node{
        int key;
        node *left = NULL, *right = NULL;
    };动态二叉链表存储节点;
  • int pre[35], in[35]:先序遍历序列,中序遍历序列(即数组从小到大排序);
  • unordered_set<int> record:记录节点到所有叶节点路径中,黑色节点的数目,若record.size()==1则该节点符合条件5,否则说明黑色节点数目不唯一;

算法

  1. 获得二叉树的先序和中序(由于是balanced binary search tree,所以中序遍历即从小到大的排序)遍历; 
  2. 根据先序和中序遍历,构建二叉树:
  3. 设计函数getBlackNum,并利用unordered_set<int> record记录节点到所有叶节点路径中,黑色节点的数目,若record.size()==1则该节点符合条件5,否则说明黑色节点数目不唯一;
  4. 利用DFS遍历二叉树。对每个节点调用函数getBlackNum判断是否满足性质5;当节点为红色时判断其子节点是否满足性质4。利用全局变量flag记录目前为止是否符合红黑树性质,是则继续,不是则返回;

 

3,AC代码

#include<bits/stdc++.h>
using namespace std;
struct node{
    int key;
    node *left = NULL, *right = NULL;
};
int pre[35], in[35], K, N, key;                 //K判断次数 N节点数
bool flag;
unordered_set<int> record;                      //记录节点到所有叶节点路径中 黑色节点的数目 若record.size()==1则该节点符合条件5

bool cmp1(int a, int b){ return abs(a) < abs(b);}
void buildTree(node *&r, int root, int left, int right){// !!!*&
    if(left > right) return;
    if(r == NULL){
        r = new node();
        r->key = pre[root];
    }
    int i = left;
    while(i <= right && in[i] != pre[root])
        i++;
    buildTree(r->left, root+1, left, i-1);
    buildTree(r->right, root+(i-left)+1, i+1, right);
}
void getBlackNum(node *n, int num){
    if(n == NULL || n->key > 0)                 //黑色节点
        num++;
    if(n == NULL){
        record.insert(num);
        return;
    }
    getBlackNum(n->left, num);
    getBlackNum(n->right, num);
}
void dfsJudge(node *tree){
    if(tree != NULL && flag == true){
        record.clear();
        getBlackNum(tree, 0);
        if(record.size() > 1) flag = false;     //判断该节点对应的条件5
        if(flag == true && tree->key < 0){      //判断红色节点是否满足条件4
            if(tree->left != NULL && tree->left->key < 0)
                flag = false;
            if(tree->right != NULL && tree->right->key < 0)
                flag = false;
        }
        if(flag == true)
            dfsJudge(tree->left);
        if(flag == true)
            dfsJudge(tree->right);
    }
    else return;
}
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
    cin>>K;
    for(int i = 0; i < K; i++){
        flag = true;
        scanf("%d", &N);
        for(int j = 0; j < N; j++){
            scanf("%d", &pre[j]);
            if(pre[j] == 0) flag = false;
        }
        if(pre[0] <= 0)
            flag = false;
        else{
            memcpy(in, pre, N*sizeof(int));     //pre数组拷贝到in数组中
            sort(in, in + N, cmp1);             // !!!不是sort(pre, pre + N, cmp1);
            node *root = NULL;
            buildTree(root, 0, 0, N-1);
            dfsJudge(root);
        }
        printf("%s\n", flag ? "Yes":"No");
    }
    return 0;
}

 

4,解题过程

一发入魂o(* ̄▽ ̄*)ブ

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值