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