数据结构:判断是否为同一棵二叉搜索树

本文是代码新手在学习二叉搜索树时的反思和经验分享。作者通过自己的错误代码,揭示了在使用递归处理二叉树时容易出现的逻辑问题,特别是关于标志位清零和释放的处理。文章提醒读者,仅仅模仿代码是不够的,需要理解思路并亲自实践。通过重新梳理和编写,即使是简单的题目也能深入理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言碎语

作为一个代码小白,在自学的过程中,最舒服的好像就是有讲解、有提示、甚至直接是有源码……然而,照着写永远是无法进步的,因为,很可能最后错了自己都不知道错在了哪!

就比如下面这个,照着MOOC小白教程写的,然,错了,并且错的一点头绪也没有。贴在这,警醒自己!!

/* 判断是否是同一颗二叉搜索树 */
/*
### 解题思路:
一种简单粗暴的方法,判断相同结点的左右两边子树是否按顺序相同。
一种比较笨的方法:按照给定的序列建一棵二叉搜索树,然后需要判断的再建一棵树,然后比较;
其实有了这个笨方法之后,就可以加以改进,比如知建一棵树,然后通过给定顺序来判断(这里就需要一个标志来记录)

*/

#include <cstdio>
#include <cstdlib>

typedef struct TreeNode *Tree;
struct TreeNode {
    int v;
    Tree Left;
    Tree Right;
    int flag;
};
Tree NewNode(int V);
Tree Insert(Tree T, int V);
Tree MakeTree(int N);
int check(Tree T, int V);
int Judge(Tree T, int N);
void ResetT(Tree T);
void FreeTree(Tree T);

int main()
{
    int N, L;
    Tree T;
    //先把一棵树建好,然后判断的顺序读进去进行比较
    //相同:标志为0,不相同,标志为1,直接打印
    scanf("%d", &N);
    while (N) {
        scanf("%d", &L);
        T = MakeTree(N);
        for (int i = 0; i < L; i++) {
        if (Judge(T, N))
            printf("N0\n");
        else
            printf("Yes\n");
            ResetT(T);
        }
        FreeTree(T);
        scanf("%d", &N);//保证下一次循环正常进行。
    }

    return 0;

}

Tree NewNode(int V)
{
    Tree T = (Tree)malloc(sizeof(struct TreeNode));
    T->v = V;
    T->Left = T->Right = NULL;
    T->flag = 0;
    return T;
}

Tree Insert(Tree T, int V)
{
    if (!T)
        T = NewNode(V);
    else {
        if (V > T->v)
            T->Right = Insert(T->Right, V);
        else if (V < T->v)
            T->Left = Insert(T->Left, V);
    }
    return T;
}

Tree MakeTree(int N)
{
    Tree T;
    int V;
     scanf("%d", &V);
     T = NewNode(V);
     //建树的过程。先结点,然后插入
     for (int i = 0; i < N; i++) {
        scanf("%d", &V);
        T = Insert(T, V);
     }
}

int check(Tree T, int V)
{
    if (T->flag) {
        if (V < T->v)
            return check(T->Left, V);
        else if (V > T->v)
            return check(T->Right, V);
        else
            return 0;//注意这里是访问过一次的结点
    }
    else {
        if (V == T->v) {
            T->flag = 1;
            return 1;
        }
        else
            return 0;
    }
}

//只建立一棵树进行判断,那么怎么读入需要判断的结点就是需要思考的了
int Judge(Tree T, int N)
{

    int V, flag = 0;
    scanf("%d", &V);
    //如果直接return的话,这一行还没有读完,需要再处理
    if (V != T->v)
        flag = 1;
    else
        T->flag = 1;//表示已经读取过
    for (int i = 1; i < N; i++) {
        scanf("%d", &V);
        if ((!flag) && (!check(T,V)))
            flag = 1;//未读取+检查不相等
    }
    return flag;
}

void ResetT(Tree T)
{
    if (T->Left)
        ResetT(T->Left);
    if (T->Right)
        ResetT(T->Right);
    T->flag = 0;
}

void FreeTree(Tree T)
{
    if (T->Left)
        FreeTree(T->Left);
    if (T->Right)
        FreeTree(T->Right);
    free(T);
}

上述的代码一定是有问题,但是因为不是按照自己思路写的,所以基本上就看不出错误在哪里了。如果是自己动手,理清思路写一遍,(虽然也有可能错得没有头绪)但至少思路是清晰的。

比如:

#include <cstdio>
#include <cstdlib> //需要malloc

typedef struct TreeNode *Tree;
struct TreeNode {
    int v;
    Tree Left;
    Tree Right;
    int flag;//访问后置为1
};

Tree MakeTree(int N);
Tree NewNode(int V);//传入的是结点数据
Tree Insert(Tree T, int V);
int Judge(Tree T, int N);
int check(Tree T, int V);
void ZeroFlag(Tree T);
void FreeTree(Tree T);

int main()
{
    int N;
    scanf("%d", &N);
    while (N) {
        int L;
        scanf("%d", &L);
        Tree T = MakeTree(N);
        for (int i = 0; i < L; i++) {
            if (Judge(T, N))
                printf("No\n");
            else
                printf("Yes\n");
            ZeroFlag(T);
        }
        FreeTree(T);
        scanf("%d", &N);
    }
    return 0;
}

Tree MakeTree(int N)
{
    Tree T;
    int V;
    scanf("%d", &V);
    T = NewNode(V);
    for (int i = 1; i < N; i++) {
        scanf("%d", &V);
        T = Insert(T, V);
    }
    //最后返回T,相当于根结点的位置
    return T;

}

Tree NewNode(int V)
{
    Tree T = (Tree)malloc(sizeof(struct TreeNode));
    T->v = V;
    T->Left = T->Right = NULL;
    T->flag = 0;
    return T;
}

Tree Insert(Tree T, int V)
{
    if (!T)
        T = NewNode(V);
    else {
        if (V > T->v)
            T->Right = Insert(T-
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值