题意:给出k个二叉搜索树的前序序列,判断该树是否为红黑树。

红黑树的定义:

  1. 结点的颜色非红即黑
  2. 根结点的颜色必须是黑色
  3. 每个叶子结点(指的是空结点,图中并没有画出来)都是黑色的
  4. 如果某个结点为红色,则它的孩子节点必须是黑色的。(表明从每个叶子到根的所有路径上不能有两个连续的红色节点。)
  5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。(所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。)
思路:
红黑树的判断:
  1. 根结点是否为黑色。
  2. 每条路径的黑色节点相等。统计出一条路径的黑色节点的个数,然后与其他路径黑色节点个数进行比较。
  3. 不存在连续的红色节点,判断红色节点的孩子节点是否为红色。
代码:

#include <cstdio>
#include <algorithm>
using namespace std;
#define BLACK 1
#define RED 0

struct Node{
    int val;
    int color;
    Node *lchild,*rchild;
    Node(int v){
        val=v>?v:-v;
        color=v>?BLACK:RED;
        lchild=rchild=nullptr;
    }
};

void insert(Node* &root,int val)
{
    if(root==nullptr){
        root=new Node(val);
        return;
    }
    if(abs(val)<root->val) insert(root->lchild,val);
    else insert(root->rchild,val);
}

//深度遍历,计算黑色结点的个数以及判断是否会出现连续两个红色结点
;
bool flag=true;
void dfs(Node* root,int cnt)
{
    if(root==nullptr){
        if(cnt!=totalBlackCnt) flag=false;
        return;
    }
    if(root->color==BLACK) cnt++;
    else{
        if(root->lchild && root->lchild->color==RED) flag=false;
        if(root->rchild && root->rchild->color==RED) flag=false;
    }
    //printf("val:%d color:%d cnt:%d\n",root->val,root->color,cnt);
    dfs(root->lchild,cnt);
    dfs(root->rchild,cnt);
}

int main()
{   int k,n,val;
    scanf("%d",&k);
    while(k--){
        scanf("%d",&n);
        Node* root=nullptr;
        ;i<n;i++){
            scanf("%d",&val);
            insert(root,val);
        }
        if(root->color==RED){
            printf("No\n");
            continue;
        }
        totalBlackCnt=;//记录从根结点到任意一个叶结点的简单路径上黑色结点的个数
        //此处计算最左端的路径
        Node* p=root;
        while(p){
            if(p->color==BLACK) totalBlackCnt++;
            p=p->lchild;
        }
        flag=true;//初始化
        dfs(root,);
        printf("%s\n",flag?"Yes":"No");
    }
    ;
}
【疑问】按照我自己一开始的想法,dfs()函数我是这么写的,然而这么写会有两个测试点通不过!

void dfs(Node* root,int cnt)
{
    if(root==nullptr) return;
    if(root->color==BLACK) cnt++;
    else{
        if(root->lchild && root->lchild->color==RED) flag=false;
        if(root->rchild && root->rchild->color==RED) flag=false;
    }
    if(root->lchild==nullptr && root->rchild==nullptr){
        if(cnt!=totalBlackCnt) flag=false;
    }
    //printf("val:%d color:%d cnt:%d\n",root->val,root->color,cnt);
    dfs(root->lchild,cnt);
    dfs(root->rchild,cnt);
}

【分析】事实上,之所以会这么写,是因为对红黑树的性质(3)还没有真正理解。一开始,对题目给出的这个条件就没搞明白,看了《算法导论》,它上面是这么写的:

树中的每个结点包含5个属性:color,key,left,right,parent。如果一个孩子没有子结点或父结点,则该结点相应指针属性的值为NULL。我们可以把这些NULL视为指向二叉搜索树的叶结点(外部结点)的指针,而把带关键字的结点视为树的内部结点。

因此,对性质(5)“从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点”的真正理解是——这里的叶子结点是空结点,而不是我认为的“没有孩子的结点”。事实上,我们常常把注意力放在内部结点上,因为它存储了关键字的值,而忽略叶结点。但是基本定义,基本概念不能搞混!比如下面图1中的结点8,请问它是叶节点吗?其实不是,因为它也有左右孩子,只不过它的左右孩子不存关键字,为NULL罢了。类似的思想在判断一棵树是否为完全二叉树中也应用到了。见例题

按照我错误的写法,程序会认为以下这样的也是红黑树:

(图1)

然而,这棵树并不是合法的红黑树。根据定义,它真正的形状应该是画成下面这个样子:

(图2)

可以看到,“7->11->null”这条路径中黑色结点的个数与其他路径不等。而按照我错误的写法来理解(即图1),因为结点11不是叶子结点,所以根本不会考虑这条路径上的情况,因此造成错误。

理解了定义之后,修改成如下便可AC,当然,我觉得这种写法不太好,还是上面完整代码中那个版本最佳!

void dfs(Node* root,int cnt)
{
    if(root==nullptr) return;
    if(root->color==BLACK) cnt++;
    else{
        if(root->lchild && root->lchild->color==RED) flag=false;
        if(root->rchild && root->rchild->color==RED) flag=false;
    }
    if(root->lchild==nullptr || root->rchild==nullptr)
        if(cnt!=totalBlackCnt) flag=false;
    }
    dfs(root->lchild,cnt);
    dfs(root->rchild,cnt);
}

1135 Is It A Red-Black Tree的更多相关文章

  1. [转载] 红黑树(Red Black Tree)- 对于 JDK TreeMap的实现

    转载自http://blog.csdn.net/yangjun2/article/details/6542321 介绍另一种平衡二叉树:红黑树(Red Black Tree),红黑树由Rudolf B ...

  2. Red–black tree ---reference wiki

    source address:http://en.wikipedia.org/wiki/Red%E2%80%93black_tree A red–black tree is a type of sel ...

  3. Red Black Tree 红黑树 AVL trees 2-3 trees 2-3-4 trees B-trees Red-black trees Balanced search tree 平衡搜索树

    小结: 1.红黑树:典型的用途是实现关联数组 2.旋转 当我们在对红黑树进行插入和删除等操作时,对树做了修改,那么可能会违背红黑树的性质.为了保持红黑树的性质,我们可以通过对树进行旋转,即修改树中某些 ...

  4. CF1208H Red Blue Tree

    CF1208H Red Blue Tree 原本应该放在这里但是这题过于毒瘤..单独开了篇blog 首先考虑如果 $ k $ 无限小,那么显然整个树都是蓝色的.随着 $ k $ 逐渐增大,每个点都会有 ...

  5. 2018 ICPC青岛网络赛 B. Red Black Tree(倍增lca好题)

    BaoBao has just found a rooted tree with n vertices and (n-1) weighted edges in his backyard. Among ...

  6. 计蒜客 Red Black Tree(树形DP)

    You are given a rooted tree with n nodes. The nodes are numbered 1..n. The root is node 1, and m of ...

  7. Red Black Tree(红黑树)

    (修改于 2018-05-06 15:53:22 还差删除维护操作.层序遍历没完成.维护操作没完成不想写层序遍历怎么办...) 今天下午完成了红黑树的插入的维护操作,但删除的维护操作还没有解决,删除的 ...

  8. ZOJ - 4048 Red Black Tree (LCA+贪心) The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online

    题意:一棵树上有m个红色结点,树的边有权值.q次查询,每次给出k个点,每次查询有且只有一次机会将n个点中任意一个点染红,令k个点中距离红色祖先距离最大的那个点的距离最小化.q次查询相互独立. 分析:数 ...

  9. Red Black Tree java.util.TreeSet

    https://docs.oracle.com/javase/9/docs/api/java/util/SortedMap.html public interface SortedMap<K,V ...

  10. 简单聊聊红黑树(Red Black Tree)

    ​ 前言 众所周知,红黑树是非常经典,也很非常重要的数据结构,自从1972年被发明以来,因为其稳定高效的特性,40多年的时间里,红黑树一直应用在许多系统组件和基础类库中,默默无闻的为我们提供服务,身边 ...

随机推荐

  1. (转)MapReduce Design Patterns(chapter 4 (part 1))(七)

    Chapter 4. Data Organization Patterns 与前面章节的过滤器相比,本章是关于数据重组.个别记录的价值通常靠分区,分片,排序成倍增加.特别是在分布式系统中,因为这能提高 ...

  2. CUDA Samples: Long Vector Add

    以下CUDA sample是分别用C++和CUDA实现的两个非常大的向量相加操作,并对其中使用到的CUDA函数进行了解说,各个文件内容如下: common.hpp: #ifndef FBC_CUDA_ ...

  3. Mac安装三方软件

    安装提示“xxx软件已损坏,打不开,您应该将它移到废纸篓”的提示,其实并不是软件本身有问题,而是Mac系统的一个安全机制问题步骤1:Spotlight搜索(快捷键:command+空格或右上角搜索的符 ...

  4. 华为荣耀8 android 让真机显示 DeBug Log调试信息 (真机调试时不显示 Logcat 日志的解决办法)

    ================================================================ 以下内容转载自: https://blog.csdn.net/aiko ...

  5. swift获取图片路径出错

    获取图片路径 用以下方式获取 let path = Bundle.main.path(forResource: "ImageName", ofType: "ImageTy ...

  6. Sublime 笔记

    1. 安装PackageControl 官网:https://packagecontrol.io/ v2: import urllib2,os,hashlib; h = '2915d1851351e5 ...

  7. vc 实现一个 http Server

    实现 http 的协议解析 以及封装 , 对应不同的访问地址, 调用绑定的处理程序 , #include "stdafx.h" #include "lyocomm\web ...

  8. WPF 程序无法触摸操作?我们一起来找原因和解决方法!

    WPF 自诞生以来就带着微软先生的傲慢.微软说 WPF 支持触摸,于是 WPF 就真的支持触摸了.对,我说的是"支持触摸",那种摸上去能点能动的:偶尔还能带点儿多指的炫酷效果.但是 ...

  9. 【DUBBO】 Dubbo原理解析-Dubbo内核实现之基于SPI思想Dubbo内核实现

    转载:http://blog.csdn.net/quhongwei_zhanqiu/article/details/41577235 SPI接口定义 定义了@SPI注解 public @interfa ...

  10. 关于json格式字符串解析并用mybatis存入数据库

    园子里面找了很多关于json解析后存入数据库的方法,不是太乱,就是没有写完,我下面的主题代码多是受下面两位的启发,请按顺序查看 http://www.cnblogs.com/tian830937/p/ ...