A1135 | 红黑树判断:审题、根据“先序遍历”和“BST树”的条件生成后序遍历、递归判断

对A1135这题有心里阴影了,今天终于拿下AC。学习自柳神博客:https://www.liuchuo.net/archives/4099

首先读题很关键:

There is a kind of balanced binary search tree named red-black tree in the data structure………………

红黑树首先应该是一棵BST树,不然从何谈起维护二分查找结构?

所以第一步就应该根据先序遍历以及BST树的特性来判断是否是一棵BST树,然后根据这两个条件生成树形链式结构。



柳神博客中给出的方法是生成后序遍历然后判断size是否与先序遍历的长度相等。笔者认为生成一个新的先序遍历然后判断长度也可以。

void getPost(int root,int end){//create a BST by pre order and BST‘s property
    if(root>end) return;
    int i=root+1,j=end;
    while(i<=end && pre[root]>pre[i]) i++;
    while(j>=root+1 && pre[root]<pre[j]) j--;
    if(i!=j+1) return;
    getPost(root+1,j);
    getPost(i,end);
    post.push_back(pre[root]);
}

以上是生成后序遍历的代码。代码逻辑:

7 2 1 5 4 11 8 14 16

j↑ ↑i

让i->遍历[root + 1 , 大于root的数],j<-遍历[小于root的数 , end]

然后二者相互错开,建立新的递归关系。

特殊边界条件:

  \

   2

     \

      3

这个结构符合BST树的定义,先序遍历是 123。

第一轮:

1 2 3

j i

第二轮:

2 3

j i

第三轮:

ij



然后再谈到递归判断。两个递归判断代码:

int getNum(Node* node){
    if(!node) return 0;
    int l=getNum(node->l);
    int r=getNum(node->r);
    int m=max(l,r);
    if(!node->isR) m++;
    return m;
}
bool judge1(Node* node){//every path to leaves have same black
    if(!node) return true;
    if(getNum(node->l)!=getNum(node->r)) return false;
    return judge1(node->l) && judge1(node->r);
}
bool judge2(Node* node){//the node is red , the both leaves is black
    if(!node) return true;
    if(node->isR){
        if(node->l && node->l->isR) return false;
        if(node->r && node->r->isR) return false;
    }
    return judge2(node->l) && judge2(node->r);
}


完整代码:

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>

#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 10000
#define MAX 0x06FFFFFF
#define V vector<int>

using namespace std;

V post;
V pre;
typedef struct Node{
    int d=0;
    bool isR=true;
    struct Node* l=NULL;
    struct Node* r=NULL;
    Node(int D,int I){
        d=D;isR=I;
        l=NULL;r=NULL;
    }
}Node;

Node *root=NULL;

void getPost(int root,int end);
Node* bst_insert(Node* p,int d);
bool judge1(Node* node);
bool judge2(Node* node);

int main() {
    freopen("d:/input/A1135/1.txt","r",stdin);
    int N,M,i;
    scanf("%d",&N);
    while(N-->0){
        scanf("%d",&M);
        pre.resize(M);
        post.clear();
        root=NULL;
        FF(i,M){
            int t;
            scanf("%d",&t);
            pre[i]=abs(t);
            root=bst_insert(root,t);
        }
        getPost(0,M-1);
        if(post.size()!=M){
            OL("No");continue;
        }
        if(root->isR){
            OL("No");continue;
        }
        if(judge1(root) && judge2(root))
            OL("Yes");
        else OL("No");
    }
//    OL("OK");
    return 0;
}

void getPost(int root,int end){//create a BST by pre order and BST‘s property
    if(root>end) return;
    int i=root+1,j=end;
    while(i<=end && pre[root]>pre[i]) i++;
    while(j>=root+1 && pre[root]<pre[j]) j--;
    if(i!=j+1) return;
    getPost(root+1,j);
    getPost(i,end);
    post.push_back(pre[root]);
}

Node* bst_insert(Node* p,int d){
    Node* node=new Node(abs(d),d<0);//if d < 0 , d is red
    if(!p){//node is null
        return node;
    }else{
        int v=abs(d);
        if(v>p->d){//r
            if(p->r){
                p->r=bst_insert(p->r,d);
            }else{
                p->r=node;
            }
        }else{
            if(p->l){
                p->l=bst_insert(p->l,d);
            }else{
                p->l=node;
            }
        }
    }
    return p;
}

int getNum(Node* node){
    if(!node) return 0;
    int l=getNum(node->l);
    int r=getNum(node->r);
    int m=max(l,r);
    if(!node->isR) m++;
    return m;
}

bool judge1(Node* node){//every path to leaves have same black
    if(!node) return true;
    if(getNum(node->l)!=getNum(node->r)) return false;
    return judge1(node->l) && judge1(node->r);
}

bool judge2(Node* node){//the node is red , the both leaves is black
    if(!node) return true;
    if(node->isR){
        if(node->l && node->l->isR) return false;
        if(node->r && node->r->isR) return false;
    }
    return judge2(node->l) && judge2(node->r);
}

原文地址:https://www.cnblogs.com/TQCAI/p/8146471.html

时间: 2024-10-03 10:16:46

A1135 | 红黑树判断:审题、根据“先序遍历”和“BST树”的条件生成后序遍历、递归判断的相关文章

PAT甲题题解-1119. Pre- and Post-order Traversals (30)-(根据前序、后序求中序)

(先说一句,题目还不错,很值得动手思考并且去实现.) 题意:根据前序遍历和后序遍历建树,输出中序遍历序列,序列可能不唯一,输出其中一个即可. 已知前序遍历和后序遍历序列,是无法确定一棵二叉树的,原因在于如果只有一棵子树可能是左孩子也有可能是右孩子.由于只要输出其中一个方案,所以假定为左孩子即可.下面就是如何根据前序和后序划分出根节点和左右孩子,这里需要定义前序和后序的区间范围,分别为[preL,preR],[postL,postR]. 一开始区间都为[1,n],可以发现前序的第一个和后序的最后一

算法导论 第十三章 红黑树(python)-1插入

红黑树是上一章二叉搜索树的改进,实现一种平衡 ,保证不会出现二叉树变链表的情况,基本动态集合操作的时间复杂度为O(lgn) 实际用途:c++stl中的set,map是用他实现的 红黑树的性质: 1.每个结点或是红色的,或是黑色的 2.跟结点是黑色的 3.每个叶结点(NIL)是黑色 4.如果一个结点是红色的,则它的两个结点都是黑色的 5.对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同的数目的黑色结点(数目被称为黑高bh(x)) 如下图: (T.nil 哨兵后面被忽略 None) 红

数据结构(三):非线性逻辑结构-特殊的二叉树结构:堆、哈夫曼树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树

在上一篇数据结构的博文<数据结构(三):非线性逻辑结构-二叉树>中已经对二叉树的概念.遍历等基本的概念和操作进行了介绍.本篇博文主要介绍几个特殊的二叉树,堆.哈夫曼树.二叉搜索树.平衡二叉搜索树.红黑树.线索二叉树,它们在解决实际问题中有着非常重要的应用.本文主要从概念和一些基本操作上进行分类和总结. 一.概念总揽 (1) 堆 堆(heap order)是一种特殊的表,如果将它看做是一颗完全二叉树的层次序列,那么它具有如下的性质:每个节点的值都不大于其孩子的值,或每个节点的值都不小于其孩子的值

算法05 之红-黑树

从第4节的分析中可以看出,二叉搜索树是个很好的数据结构,可以快速地找到一个给定关键字的数据项,并且可以快速地插入和删除数据项.但是二叉搜索树有个很麻烦的问题,如果树中插入的是随机数据,则执行效果很好,但如果插入的是有序或者逆序的数据,那么二叉搜索树的执行速度就变得很慢.因为当插入数值有序时,二叉树就是非平衡的了,排在一条线上,其实就变成了一个链表--它的快速查找.插入和删除指定数据项的能力就丧失了. 为了能以较快的时间O(logN)来搜索一棵树,需要保证树总是平衡的(或者至少大部分是平衡的),这

Nginx 红黑树结构 ngx_rbtree_t

概述 有关红黑树的基础知识在前面文章中已经做了介绍,想要更详细的了解红黑树可以参考文章<数据结构-红黑树>,在这里只是单纯对 Nginx 中红黑树源码的解析,Nginx 红黑树源码是实现跟算法导论中的讲解是一样的. 红黑树结构 typedef ngx_uint_t ngx_rbtree_key_t; typedef ngx_int_t ngx_rbtree_key_int_t; /* 红黑树节点结构 */ typedef struct ngx_rbtree_node_s ngx_rbtree_

算法5-2:红黑树

红黑树就是将二三树表示成二叉树的形式,极大地简化了算法. 红黑树的基本思想就是将二三树中的三节点表示成两个二节点,而这两个二节点之间使用红色的连接,普通连接使用黑色的连接. 红黑树中的每个节点都有以下性质: 没有一个节点同时拥有两个红连接 每个空节点到根节点路径上黑色连接的数量都是相同的 红连接只会出现在左边 下图展示了二三树和红黑树的等价表示 查找操作 与普通的二叉树查找树的算法一致,忽略节点的颜色即可. 旋转操作 有时候会出现下图红连接在右侧的情况.这时候就需要通过左旋操作,使其符合红黑树的

图解集合7:红黑树概念、红黑树的插入及旋转操作详细解读

原文地址http://www.cnblogs.com/xrq730/p/6867924.html,转载请注明出处,谢谢! 初识TreeMap 之前的文章讲解了两种Map,分别是HashMap与LinkedHashMap,它们保证了以O(1)的时间复杂度进行增.删.改.查,从存储角度考虑,这两种数据结构是非常优秀的.另外,LinkedHashMap还额外地保证了Map的遍历顺序可以与put顺序一致,解决了HashMap本身无序的问题. 尽管如此,HashMap与LinkedHashMap还是有自己

通过2-3-4树理解红黑树

前言 红黑树是数据结构中比较复杂的一种,最近与它交集颇多,于是花了一周的空闲时间跟它死磕,终于弄明白并实现了红黑树.写文总结一下,希望能给试图理解红黑树的同学一些灵感,也让我能记得更深刻. 在研究红黑树时吃了不少苦头,原因有二: 红黑树的插入和删除非常复杂,很多人并没有理解或完全实现,或实现了的没有任何注释,让人很难参考: 网络上红黑树的理解方式较为单一,一般是 双黑.caseN 法,而插入和删除的情况很多,每种都有对应的处理方式,如果死记硬背的话,再过一段时间再回忆各种情况可能就一头雾水了.

简单清晰的红黑树

查找(一) 我们使用符号表这个词来描述一张抽象的表格,我们会将信息(值)存储在其中,然后按照指定的键来搜索并获取这些信息.键和值的具体意义取决于不同的应用. 符号表中可能会保存很多键和很多信息,因此实现一张高效的符号表也是一项很有挑战性的任务. 我们会用三种经典的数据类型来实现高效的符号表:二叉查找数.红黑树.散列表. 二分查找 我们使用有序数组存储键,经典的二分查找能够根据数组的索引大大减少每次查找所需的比较次数. 在查找时,我们先将被查找的键和子数组的中间键比较.如果被查找的键小于中间键,我