04-树4 是否同一棵二叉搜索树

275 阅读3分钟

题目描述

给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{2, 1, 3}和{2, 3, 1}插入初始为空的二叉搜索树,都得到一样的结果。于是对于输入的各种插入序列,你需要判断它们是否能生成一样的二叉搜索树。

输入格式

输入包含若干组测试数据。每组数据的第1行给出两个正整数N (≤10)和L,分别是每个序列插入元素的个数和需要检查的序列个数。第2行给出N个以空格分隔的正整数,作为初始插入序列。随后L行,每行给出N个插入的元素,属于L个需要检查的序列。

简单起见,我们保证每个插入序列都是1到N的一个排列。当读到N为0时,标志输入结束,这组数据不要处理。

输出格式

对每一组需要检查的序列,如果其生成的二叉搜索树跟对应的初始序列生成的一样,输出“Yes”,否则输出“No”。

输入样例

4 2
3 1 4 2
3 4 1 2
3 2 4 1
2 1
2 1
1 2
0

输出样例

Yes
No
No

题解

题意理解:判断插入序列生成的二叉搜索树是否相同

方法一

  • 下面是一种最容易想到的办法,即根据序列建树然后判断两树是否相同
  • 需要实现的函数:建树插入函数、两数相等判断函数

插入函数:二叉搜索树的操作集之一

  • 传入的树为空,递归退出条件,找到要插入的位置,新建结点并返回
  • 否则向左右子树继续找插入位置,递归调用函数
  • 当 item 等于 data 元素已存在,什么都不做直接返回原树

创建函数:每读入一个结点就插入到树里去,循环比对每一组数据是否为同一棵树

判断函数:只需将 03-树1 树的同构 中判断是否同构的函数稍作修改,去掉交换左右子树的部分即为判断两棵树是否相等的函数

#include <stdio.h>
#include <stdlib.h>

typedef struct TNode *BST;
struct TNode {
    int data;
    BST left;
    BST right;
};

BST Insert(BST T, int item)
{
    if (!T) {
        T = (BST)malloc(sizeof(struct TNode));
        T->data = item;
        T->left = T->right = NULL;
    } else {
        if (item < T->data)
            T->left = Insert(T->left, item);
        else if (item > T->data)
            T->right = Insert(T->right, item);
    }
    return T;
}

BST Create(int n)
{
    int i, item;
    BST T = NULL;
    for (i = 0; i < n; i++) {
        scanf("%d", &item);
        T = Insert(T, item);
    }
    return T;
}

int Identify(BST T1, BST T2)
{
    if (!T1 && !T2) return 1;

    if ((!T1 && T2) || (T1 && !T2)) return 0;

    if (T1 && T2 && T1->data != T2->data) return 0;

    if (T1 && T2 && T1->data == T2->data)
        return Identify(T1->left, T2->left) && Identify(T1->right, T2->right);
}

int main()
{
    int i, n, l;
    BST T1, T2;

    scanf("%d", &n);
    while (n != 0) {
        scanf("%d", &l);
        T1 = Create(n);
        for (i = 0; i < l; i++) {
            T2 = Create(n);
            if (Identify(T1, T2)) printf("Yes\n");
            else printf("No\n");
        }

        scanf("%d", &n);
    }

    return 0;
}

方法二

  • 课程中给出的方法是只建一棵树,然后根据序列去判断是否与该树相同
  • 需要在树的数据结构定义上加上一个 flag , 0 表示没出现过, 1 表示出现过

判别方法:在树中按顺序搜索序列中的每一个树

  • 如果每次搜索所经过的结点在前面均出现过,则一致
  • 如果某次搜索中遇到前面未出现的结点,则不一致

Check 函数:判断某一个结点一路搜索下来碰到的是不是都在前面出现过,如果有没有碰到过的就返回不一致

Identify 函数:首先判断队首元素,根结点是否一致,一致就 flag = 1 ,不一致就 flag = 0 。然后去逐个判断后面的结点是否插在正确的位置。要注意不能提前返回,不然会出现还有数据没读完就进入下一组数据的 bug 。

#include <stdio.h>
#include <stdlib.h>

typedef struct TNode *BST;
struct TNode {
    int data;
    BST left;
    BST right;
    int flag;
};

BST Insert(BST T, int item)
{
    if (!T) {
        T = (BST)malloc(sizeof(struct TNode));
        T->data = item;
        T->left = T->right = NULL;
        T->flag = 0;
    } else {
        if (item < T->data)
            T->left = Insert(T->left, item);
        else if (item > T->data)
            T->right = Insert(T->right, item);
    }
    return T;
}

BST Create(int n)
{
    int i, item;
    BST T = NULL;
    for (i = 0; i < n; i++) {
        scanf("%d", &item);
        T = Insert(T, item);
    }
    return T;
}

int Check(BST T, int item)
{
    if (T->flag) {
        if (item < T->data) return Check(T->left, item);
        else if (item > T->data) return Check(T->right, item);
        else return 0;
    } else {
        if (item == T->data) {
            T->flag = 1;
            return 1;
        } else
            return 0;
    }
}

int Identify(BST T, int n)
{
    int i, item, flag = 0;
    
    scanf("%d", &item);
    if (item != T->data) flag = 1;
    else T->flag = 1;

    for (i = 1; i < n; i++) {
        scanf("%d", &item);
        if ((!flag) && (!Check(T, item))) flag = 1;
    }

    if (flag) return 0;
    else return 1;
}

void Reset(BST T)
{
    if (T->left) Reset(T->left);
    if (T->right) Reset(T->right);
    T->flag = 0;
}

void Free(BST T)
{
    if (T->left) Free(T->left);
    if (T->right) Free(T->right);
    free(T);
}

int main()
{
    int i, n, l;
    BST T;

    scanf("%d", &n);
    while (n != 0) {
        scanf("%d", &l);
        T = Create(n);
        for (i = 0; i < l; i++) {
            if (Identify(T, n)) printf("Yes\n");
            else printf("No\n");
            Reset(T);
        }
        Free(T);
        scanf("%d", &n);
    }

    return 0;
}