PTA 二叉搜索树和二叉平衡树

二叉搜索树
给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{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

思路: 先用insert迭代插入。难点在判断上,利用了一个这样的逻辑:加入旗帜变量flag,区分基准树的某个节点数字有无出现过。当新输入的数字遍历整个基准树时,如果DATA值相等但flag表明之前没有出现过,则这两个树肯定是不一样的。 需要注意的是,要规避读入数据和下一行可能连在一起的情况,正因为如此才引入了flag变量。在发现有不一致时立刻改变flag值(flag = 0表示到目前位置全一致),但继续接收本行数据。

#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>

using namespace std;
typedef  struct TreeNode* Tree;

class TreeNode
{
public:
	Tree BulidTree(int N);
	int Judge(Tree T, int N);

	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);
	}
	
private:
	int V;
	Tree Left, Right;
	int flag;

	
	Tree NewNode(int V);
	Tree Insert(int V, Tree T);
	int check(Tree T, int V);
};



 Tree TreeNode::BulidTree(int N) 
{
	Tree T;
	int i, V;

	cin >> V;
	T = NewNode(V);
	for (i = 1; i < N; i++)
	{
		cin >> V;
		T = Insert(V, T);
	}
	return T;
}

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

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

int TreeNode::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 TreeNode::Judge(Tree T, int N)
{
	int i, V, flag = 0;//flag等于0时表示到目前为止还一致
	//为了避免将下一行的数和当前行的数混起来
	cin >> V;	
	if (V != T->V)
		flag = 1;
	else T->flag = 1;

	for (i = 1; i < N; i++)
	{
		cin >> V;
		if ((!flag) && (!check(T, V)))//当目前为0且刚好找到不一致
			flag = 1;//将flag置1,且读完N个数
	}
	if (flag) return 0;
	else  return 1;

}

int main() 
{	
	TreeNode TN;
	Tree T;
	int N, L;
	vector<string> vec;

	cin >> N >> L;
	while (N)
	{
		T = TN.BulidTree(N);
		for (int i = 0; i < L; i++)
		{
			if (TN.Judge(T, N))
				vec.push_back("Yes");
			else
				vec.push_back("No");
			
			TN.ResetT(T);
		}
		TN.FreeTree(T);

		cin >> N ;
		if (N != 0 ) 
			cin >> L;
	}
	
	for (int i = 0; i < vec.size(); i++)
	{
		if (i < vec.size() - 1)
			cout << vec[i] << "\n";
		else
			cout << vec[i];
	}
	return 0;
}

二叉平衡树
04-树5 Root of AVL Tree (25分)
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.
Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.

Output Specification:
For each test case, print the root of the resulting AVL tree in one line.

Sample Input 1:
5
88 70 61 96 120
Sample Output 1:
70
Sample Input 2:
7
88 70 61 96 120 90 65
Sample Output 2:
88

思路:常规的二叉平衡树的构建。主要考察了平衡树的四种旋转修改的写法。需要格外注意的是,LR旋转和RL旋转,由两次单旋组成。比如说LR先由B,C进行一次R单旋转返回C,再由C和A做一次L单旋转返回结果。 故写函数是要先写好LL和RR单旋。

#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>

using namespace std;
typedef  struct TreeNode* Tree;
struct TreeNode
{
	int Data;
	Tree Left;
	Tree Right;
	int Height;
};

int Max(int a, int b)
{
	return a > b ? a : b;
}


Tree NewNode(int num)
{
	Tree T = (Tree)malloc(sizeof(struct TreeNode));
	T->Data = num;
	T->Left = T->Right = NULL;
	T->Height = 0;
	return T;
}

int GetHeight(Tree T)
{
	if (NULL == T)
		return 1;
	int l = GetHeight(T->Left);
	int r = GetHeight(T->Right);
	T->Height = Max(l, r) + 1;
	return T->Height;
}

//左单旋
Tree LL_Rotation(Tree A)
{
	Tree B = A->Left;//定义参与旋转的三兄弟的中间节点B
	A->Left = B->Right;//将中间节点的右子树粘好
	B->Right = A;

	//更新Height参数
	A->Height = Max(GetHeight(A->Left), GetHeight(A->Right)) + 1;//变身后,A(同时也是B的右子树)高度
	B->Height = Max(GetHeight(B->Left), A->Height) + 1;//更新变身后的根节点B的高度
	return B;
}

//右单旋
Tree RR_Rotation(Tree A)
{
	Tree B = A->Right;
	A->Right = B->Left;
	B->Left = A;

	A->Height = Max(GetHeight(A->Left), GetHeight(A->Right)) + 1;
	B->Height = Max(GetHeight(B->Right), A->Height) + 1;//更新B的高度
	return B;
}

Tree LR_Rotation(Tree A)
{//注意:A必须有一个左子结点B,且B必须有一个右子结点C
	A->Left = RR_Rotation(A->Left);//将B与C做单旋,返回C
								   //一次单旋后,画图发现扭回了LL型式;

	return LL_Rotation(A); //将A与C做单旋,返回
}



Tree RL_Rotation(Tree A)
{//注意:A必须有一个左子结点B,且B必须有一个右子结点C
	A->Right = LL_Rotation(A->Right);//将B与C做单旋,返回C
									 //一次单旋后,画图发现扭回了RR型式;

	return RR_Rotation(A); //将A与C做单旋,返回
}



Tree Insert(Tree T, int num)
{
	if (!T)
		T = NewNode(num);
	else if (num < T->Data)
	{
		T->Left = Insert(T->Left, num);

		//cout << "here is " << GetHeight(T->Left)<< " " << GetHeight(T->Right);
		//若需要左旋调整
		if (GetHeight(T->Left) - GetHeight(T->Right) == 2)
		{
			if (num < T->Left->Data)
			{
				T = LL_Rotation(T);
				//cout << T->Left->Data<<"LL \n";
			}
			else
			{
				T = LR_Rotation(T);
				//cout << T->Left->Data<<"LR \n";
			}
		}
	} //if else 插入左子树结束

	else if (num > T->Data)
	{
		T->Right = Insert(T->Right, num);

		//cout << "here is " << T->Right->Data << " " << GetHeight(T->Right)<<"\n";
		//若需要右旋调整
		if (GetHeight(T->Left) - GetHeight(T->Right) == -2)
		{
			if (num > T->Right->Data)
			{
				T = RR_Rotation(T);
				//cout << T->Right->Data<<"RR \n";
			}
			else
			{
				T = RL_Rotation(T);
				//cout << "RL \n";
			}
		}
	} //if else 插入右子树结束

	T->Height = Max( GetHeight(T->Left), GetHeight(T->Right) )+1;//更新T的高度
	return T;

}

int GetRoot(int Num)
{
	int InsertNum;
	Tree T;
	T = NULL;

	if (Num != 0) {
		for (int i = 0; i < Num; i++)
		{
			cin >> InsertNum;
			T = Insert(T, InsertNum);

		}

		return T->Data;
	}
	else
		return 0;
}
int main()
{
	int Num;
	cin >> Num;

	cout << GetRoot(Num);

	return 0;
}

04-树6 Complete Binary Search Tree (30分)
A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:

The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
Both the left and right subtrees must also be binary search trees.
A Complete Binary Tree (CBT) is a tree that is completely filled, with the possible exception of the bottom level, which is filled from left to right.

Now given a sequence of distinct non-negative integer keys, a unique BST can be constructed if it is required that the tree must also be a CBT. You are supposed to output the level order traversal sequence of this BST.

Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤1000). Then N distinct non-negative integer keys are given in the next line. All the numbers in a line are separated by a space and are no greater than 2000.

Output Specification:
For each test case, print in one line the level order traversal sequence of the corresponding complete binary search tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input:
10
1 2 3 4 5 6 7 8 9 0

Sample Output:
6 3 8 1 5 7 9 0 2 4

题目大意:让你搞出一个N个节点的二叉树,这个树既是搜索二叉树又是完全二叉树。最后按完全二叉树的脚标顺序输出。

思路:看见完全二叉树,考虑用数组来装。利用T[x].Left = 2x,T[x].Right = 2x+1的特性(要线确定脚标在N界内),就可以用脚标来建立一个没有DATA的空树(有位置关系没有具体数据)。随后用中序遍历搜索二叉树是递增的特性,来将排好序的numerlist一个个填入完全二叉树的数组中。 最后再输出数组即可。

#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>

using namespace std;

const int MaxSize = 1000;

typedef  struct TreeNode* Tree;
struct TreeNode 
{
	int Data;
	int Left;
	int Right;
};
TreeNode T[1000];
int numlist[1000];//存放输入数据

//用数组构建一个不存放数据的完全二叉树
void BuildCBT(int N) 
{
	for (int j = 0; j < N + 1; j++)//初始化
	{
		T[j].Left = -1;
		T[j].Right = -1;
	}

	int i = 1;
	for (; i * 2 <= N; i++)//有儿子的写上
	{
		T[i].Left = i * 2;
		if((i*2+1) <= N)
			T[i].Right = i * 2 + 1;
	}	
}

int index = 0;
//中序遍历搜索二叉树是按小到大排列的,填入数字
void Midorder(int i)
{	
	if (i != -1) {
		Midorder(T[i].Left);
		T[i].Data = numlist[index++];
		Midorder(T[i].Right);
	}
}


int main() 
{	
	int N;
	cin >> N;
	if (0 == N) return 0;
	for (int i = 0; i < N; i++)
		cin >> numlist[i];
	sort(numlist, numlist + N);//以小到大排列

	BuildCBT(N);
	Midorder(1);

	for (int i = 1; i <= N; i++)
	{
		if (i < N)
			cout << T[i].Data << " ";
		else
			cout << T[i].Data;
	}

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值