数据结构—— 树:是否同一棵二叉搜索树

Posted 大彤小忆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构—— 树:是否同一棵二叉搜索树相关的知识,希望对你有一定的参考价值。

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

  输入样例: 输入样例第一行的4 24代表第一组的二叉搜索树有4个结点,2代表后面有两棵树需要与前面比较是否一样;第二行3 1 4 2代表输入的第一组序列;后面的第三四行代表需要与第一组序列比较是否一样的若干组序列。第五行的2 14代表第二组的二叉搜索树有2个结点,1代表后面有一棵树需要与前面比较是否一样;第六行2 1代表输入的第二组序列;后面的第七行代表需要与第二组序列比较是否一样的若干组序列。第八行0代表结束比较,退出程序。

在这里插入图片描述
  求解思路: 两个序列是否对应相同搜索树的判别。
        1. 分别建两棵搜索树的判别方法
          ⋄ \\diamond 根据两个序列分别建树,再判别树是否一样
        2. 不建树的判别方法
在这里插入图片描述
        3. 建一棵树,再判别其他序列是否与该树一致
          ① 搜索树表示
          ② 建搜索树T
          ③ 判别一序列是否与搜索树T一致

  搜索树表示:

typedef struct TreeNode *Tree;
struct TreeNode {
    int v;  //用v表示结点的信息
    Tree Left, Right;  //用链表形式表示树
    int flag;  //flag为某个结点是否被访问过的标志,用来判别一个序列是否与树一样,如果某个结点未被访问,flag=0,否则flag=1
};

  程序框架搭建:

int main()
{
    对每组数据
        ∙读入N和L
        ∙根据第一行序列建树T
        ·依据树T分别判别后面的L个序列是否能与T形成同一搜索树并输出结果
    
    return 0;
}

  需要设计的函数: 1. 读数据建搜索树T
           2. 判别序列是否与T构成一样的搜索树

int main()
{
    int N, L;
    Tree T;

    cin >> N;
    while(N){
        cin >> L;
        T = Make Tree(N);
        for (int i = 0; i < L; i++) 
        {
            if (Judge(T, N))
                cout<< "是" << endl;
            else 
                cout<< "否" << endl;
            ResetT(T);  //清除T中的标记flag
        }
        Free Tree(T);
        cin >> N; 
    }
    return 0;
}

  如何判别:

在这里插入图片描述
    问题: 如何判别序列3 2 4 1是否与树T一致?
    方法: 在树T中按顺序搜索序列3 2 4 1中的每个数,如果每次搜索所经过的结点在前面均出现过,则一致;否则如果某次搜索中遇到前面未出现的结点,则不一致。

  判断是否同一棵二叉搜索树的完整实现代码如下所示。

#include<iostream>
using namespace std;

/*
	题目:对于不同的输入序列,判断是否为同一个二叉搜索树。
	求解思路:
			1、搜素树表示;
			2、建搜索树T;
			3、判断一序列是否与搜索树T一致。
*/

//搜索树表示
typedef struct TreeNode *Tree;
struct TreeNode
{
	int v;  //用v表示结点的信息
	Tree Left, Right;  //用链表形式表示树
	int flag;  //flag为某个结点是否被访问过的标志,用来判别一个序列是否与树一样,如果某个结点未被访问,flag=0,否则flag=1
};

Tree MakeTree(int N);
Tree NewNode(int V);
Tree Insert(Tree T, int V);
int Judge(Tree T, int N);
void ResetT(Tree T);
void FreeTree(Tree T);

//程序框架搭建
int main()
{
	int N, L;  // N个结点,L个序列
	Tree T;

	cin >> N;
	while (N)
	{
		cin >> L;
		T = MakeTree(N);  //根据第一行序列建N个结点的树T
		for (int i = 0; i < L; i++)  //依据树T分别判别后面的L个序列是否能与T形成同一搜索树并输出结果
		{
			if (Judge(T, N))
				cout << "是" << endl;
			else
				cout << "否" << endl;
			ResetT(T); //清除T中的标记flag
		}
		FreeTree(T);
		cin >> N;
	}

	system("pause");

	return 0;
}

//如何构建搜索树
Tree MakeTree(int N)
{
	Tree T;
	int V;

	cin >> V;  //首先读入第一个元素放入V中
	T = NewNode(V);  //为T构造新结点
	for (int i = 1; i < N; i++)
	{
		cin >> 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为空
	{
		T = NewNode(V);  //通过NewNode(V)为T构造第一个结点
	}
	else  //T不为空
	{
		if (V > T->v)
			T->Right = Insert(T->Right, V);
		else
			T->Left = Insert(T->Left, V);
	}
	return T;
}

//如何判别(已经访问过的结点要进行标记,使flag=1)
//在树T中按顺序搜索序列中的每个数,如果每次搜索所经过的结点在前面均出现过,则一致;
//                             否则如果某次搜索中遇到前面未出现的结点,则不一致。
int check(Tree T, int V)
{
	if (T->flag)  //某个结点被访问过(因为之前的V == T->v,才使得flag =1)
	{
		if (V < T->v)
			return check(T->Left, V);
		else if (V > T->v)
			return check(T->Right, V);
		else  //如果V == T->v,意味着这个序列中有两个元素出现了两次以上,即重复出现,认为不一致
			return 0;
	}
	else  //某个结点未被访问过
	{
		if (V == T->v)  //如果未被访问过的结点刚好是所搜索的,使flag=1
		{
			T->flag = 1;
			return 1;
		}
		else  //否则未被访问过的结点不是所搜索的,即遇到前面未出现的结点,使flag=0
			return 0;
	}
}

int Judge(Tree T, int N)
{
	int V, same = 1;
	//same:1代表目前还一致,0代表已经不一致

	cin >> V;

	if (V != T->v)  //序列第一个元素与T的根结点不一致
		same = 0;  //两棵树已经不一致
	else
		T->flag = 1;

	for (int i = 1; i < N; i++)
	{
		cin >> V;
		if ((same) && (!check(T, V)))
			same = 0;
	}

	if (!same)
		return 0;
	else
		return 1;
}

//清除T中各个结点的标记
void ResetT(Tree T)
{
	if (T->Left)
		ResetT(T->Left);
	if (T->Right)
		ResetT(T->Right);
	T->flag = 0;
}

//释放T的空间
void FreeTree(Tree T)
{
	if (T->Left)
		FreeTree(T->Left);
	if (T->Right)
		FreeTree(T->Right);
	free(T);
}

  运行上述代码,进行测试。

  输入如下所示。

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

  代码运行输出的测试效果如下图所示。

在这里插入图片描述

以上是关于数据结构—— 树:是否同一棵二叉搜索树的主要内容,如果未能解决你的问题,请参考以下文章

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

04-树4 是否同一棵二叉搜索树 (25 分)

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

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

数据结构—— 树:是否同一棵二叉搜索树

基础数据结构——是否同一棵二叉搜索树