笛卡尔树 中序遍历判断是否为二叉搜索树

来源:互联网 发布:做报表的软件 编辑:程序博客网 时间:2024/06/05 05:06

 笛卡尔树是一种特殊的二叉树,其结点包含两个关键字K1和K2。首先笛卡尔树是关于K1的二叉搜索树,即结点左子树的所有K1值都比该结点的K1值小,右子树的所有K1值都比该结点的K1值大。其次所有结点的K2值满足优先队列(不妨设为最小堆)的顺序要求,即该结点的K2值比其子树中的所有K2值小。给定一棵二叉树,请判定该树是否笛卡尔树。

1.实验要求

(1)输入说明:

        输入第一行中给出正整数N(N<=1000),为树中结点总数。随后N行,每行给出q一个结点的信息,包括:结点的K1值、K2值、左孩子结点编号、右孩子结点编号。设结点从0-(N-1)编号。若某结点不存在孩子结点,则该位置给出-1。       

(2)输出说明:

        如果该树是一棵笛卡尔树则输出YES,否则输出NO。

(3)测试用例:

        输入:                               输出:

      

序号

输入

输出

说明

1

6

8 27 5 1                     

9 40 -1 -1

10 20 0 3

12 21 -1 4

15 22 -1 -1

5 35 -1 -1

YES

一般情况YES测试

2

6

8 27 5 1

9 40 -1 -1

10 20 0 3

12 11 -1 4

15 22 -1 -1

50 35 -1 -1

NO

一般情况NO测试

3

6

8 27 5 1

9 40 -1 -1

10 20 0 3

12 21 -1 4

11 22 -1 -1

5 35 -1 -1

NO

K2满足最小堆顺序,但K1不满足二叉搜索树

4

9

11 5 3 -1

15 3 4 7

5 2 6 0

6 8 -1 -1

9 6 -1 8

10 1 2 1

2 4 -1 -1

20 7 -1 -1

12 9 -1 -1

NO

K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件------即简单的后序遍历不能给出正确结果

5

1

1 1 -1 -1

YES

边界测试:最小N

 

        

4.解决思路:

 (1)问题分析

本题主要分两个子问题:1.根据输入的信息建立二叉树2.根据树的结构判断其是否满足笛卡尔树的性质。

判断其是否满足笛卡尔树的性质:

需要分别对K1,K2进行判断。

对K1键值进行中序遍历,边遍历边比较,若遍历结果为递增有序,则是一个二叉搜索树,只要有不符,则不是二叉搜索树。

对K2键值进行后序遍历,先检查左、右子树是否都满足条件,若是,则将当前结点的K2值与左右子树的K2最小值比较,确定是否满足条件;否则返回No。

 

 (2)实现要点

a.用数组实现二叉树的存储:

注意到题目是用0-(N-1)整型编号代表树的结点的,所以可以把每个结点的信息存储在元素结构体的数组里,将结构体中的左右孩子域定义为整型。

b.数组实现二叉树的根的表示:

由于题目没有直接说明哪个结点是根,所以需要在建树过程中确定根结点信息。可以为每个结点建立一个标记tag,初始化为1(即每一个结点都有可能是根结点)。在建立树的过程中,不断将是左右孩子结点的tag设置为0(即有父结点的不是根)。建树完成后,扫描一遍所有结点的tag,唯一一个tag不为0的结点,就是根结点。

#include<stdio.h>struct node{int k1;int k2;int left;int right;int tag=1;}tree[1010];int CreatTree(int n){for(int i=0;i<n;i++){scanf("%d%d%d%d",&tree[i].k1,&tree[i].k2,&tree[i].left,&tree[i].right);if(tree[i].left!=-1) tree[tree[i].left].tag=0;if(tree[i].right!=-1) tree[tree[i].right].tag=0;}for(int i=0;i<n;i++){if(tree[i].tag) return i;}}int Flag1=1;int IsBstree(int root){if(tree[root].left==-1&&tree[root].right==-1) return tree[root].k1;    if(tree[root].left!=-1)   {   int TmpLeft=IsBstree(tree[root].left);if(tree[root].k1<TmpLeft||tree[root].k1==TmpLeft) Flag1=0;   }    if(tree[root].right==-1) return tree[root].k1;int  TmpRight=IsBstree(tree[root].right);if(tree[root].k1>TmpRight||tree[root].k1==TmpRight)  Flag1=0;return TmpRight;}int Flag2=1;int IsMinHeap(int root){int MinLeft,MinRight;int TmpMin;if(tree[root].left==-1&&tree[root].right==-1)      return tree[root].k2;else if(tree[root].left!=-1&&tree[root].right==-1)  {     MinLeft=IsMinHeap(tree[root].left);        if(tree[root].k2>TmpMin||tree[root].k2==TmpMin) Flag2=0;    return TmpMin;}else if(tree[root].right!=-1&&tree[root].left==-1) {   MinRight=IsMinHeap(tree[root].right);   if(tree[root].k2>TmpMin||tree[root].k2==TmpMin) Flag2=0;   return TmpMin;}else  {MinLeft=IsMinHeap(tree[root].left);MinRight=IsMinHeap(tree[root].right);TmpMin = MinLeft<MinRight?MinLeft:MinRight;if(tree[root].k2>TmpMin||tree[root].k2==TmpMin) Flag2=0;    return TmpMin;   }   }int main(){int n;scanf("%d",&n);int root= CreatTree(n);IsBstree(root);IsMinHeap(root);if(Flag1&&Flag2) printf("YES\n");else printf("NO\n");return 0;}
用flag1和flag2是因为在递归的时候要return k1,k2值来与上一层次比较,无法return false/true来判断是否为二叉搜索树/最小堆。在网上搜索中序遍历判断是否为二叉搜索树,发现有两种方法,一种是多开一个数组保存中序遍历结果,然后再对数组里的值进行遍历比较。第二种方法是递归时return false/true,前驱结点的值用static 来保存。

//判断是否为BSTbool isBST(Node* root){     static Node *prev = NULL;      // 中序遍历这棵树,并保存前驱节点至prev中     if (root)     {          if (!isBST(root->left))               return false;           // 检测节点值的合法性          if (prev != NULL && root->key <= prev->key)               return false;           prev = root;           //右子树          return isBST(root->right);     }      return true;}


0 0