PTA数据结构练习题 笛卡尔树

题面:

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

输入格式:

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

输出格式:

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

输入样例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
 

输出样例1:

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
 

输出样例2:

NO

题意分析:给定节点数据以构造一颗二叉树。判断该树是否既满足二叉查找树性质,又满足小二叉堆性质。
二叉查找树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
 
对一棵树是否为搜索树判断方法:
前序遍历已经构造的树,用一个标记来记录上一个被遍历的值,与当前节点的k值进行比较。(将标记初始值设为INT_MIN)
代码:
/*注:本题中对树的表示因给出数据原因,采用存取在结构体数组中表示,左右节点的Tree(int)值表示数组下标,具体构建方法见完整代码 */
bool Sreachtree(Tree t) { if (t != -1) { if (!Sreachtree(T[t].left)) return false; if (T[t].k < last) return false; last = T[t].k; if (!Sreachtree(T[t].right)) return false; } return true; }

对一棵树是否为最小堆方法:

前序遍历每一个节点,判断根节点的v(k2)值是否小于左右节点的v值

注:标准最小堆满足完全二叉树,但在本题中不需要满足这个特性也可以被认为是最小堆,故对左右节点地址是否同时为NULL(-1)特判,详见代码第三行

代码:

bool MinHeap(Tree t) {
	if (t != -1&&(T[t].left != -1 || T[t].right != -1)){
		if ((T[t].left != -1&&(T[t].v >= T[T[t].left].v))||((T[t].v >= T[T[t].right].v) && (T[t].right != -1)))
			return false;
		if (!MinHeap(T[t].left) || !MinHeap(T[t].right))
			return false;
	}
	return true;
}

 

完整代码:

#include<iostream>
#include<stdio.h>
#include<vector>
#define Tree int
#define Element int
using namespace std;
int last = LONG_MIN;
struct treenode {
    Element k, v;
    Tree left;
    Tree right;
}T[1005];
Tree Buildtree(treenode T[]) {
    //建树,存在T数组中
    //这里的树并不是指针指向下一节点,而是指向节点编号
    int n, check[100] = { 0 };
    Tree cl, cr;
    Tree root = -1;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> T[i].k>>T[i].v >> cl >> cr;
        T[i].left = cl;
        if (cl !=-1) {
            check[T[i].left] = 1;
        }
        T[i].right = cr ;
        if (cr != -1) {
            check[T[i].right] = 1;
        }
    }
    //以下步骤寻找根节点,不是任何节点的左右节点即为根节点
    for (int i = 0; i < n; i++) {
        if (!check[i]) {
            root = i;
            break;
        }
    }
    return root;
}
bool Sreachtree(Tree t) {
    if (t != -1) {
        if (!Sreachtree(T[t].left))
            return false;
        if (T[t].k < last)
            return false;
        last = T[t].k;
        if (!Sreachtree(T[t].right))
            return false;
    }
    return true;
}
bool MinHeap(Tree t) {
    if (t != -1&&(T[t].left != -1 || T[t].right != -1)){
        if ((T[t].left != -1&&(T[t].v >= T[T[t].left].v))||((T[t].v >= T[T[t].right].v) && (T[t].right != -1)))
            return false;
        if (!MinHeap(T[t].left) || !MinHeap(T[t].right))
            return false;
    }
    return true;
}
int main() {
    Tree t;
    t = Buildtree(T);
    (Sreachtree(t) && MinHeap(t)) ? printf("YES") : printf("NO");
    return 0;
}

参考文章:

 
posted @ 2020-11-27 12:13  XAN不会coding  阅读(207)  评论(0)    收藏  举报