中国大学MOOC ZJU-数据结构-树(中)
04-树7 二叉搜索树的操作集 (30分)
本题要求实现给定二叉搜索树的5种常用操作。
函数接口定义:
BinTree Insert( BinTree BST, ElementType X );
BinTree Delete( BinTree BST, ElementType X );
Position Find( BinTree BST, ElementType X );
Position FindMin( BinTree BST );
Position FindMax( BinTree BST );
其中BinTree结构定义如下:
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
};
函数Insert将X插入二叉搜索树BST并返回结果树的根结点指针;
函数Delete将X从二叉搜索树BST中删除,并返回结果树的根结点指针;如果X不在树中,则打印一行Not Found并返回原树的根结点指针;
函数Find在二叉搜索树BST中找到X,返回该结点的指针;如果找不到则返回空指针;
函数FindMin返回二叉搜索树BST中最小元结点的指针;
函数FindMax返回二叉搜索树BST中最大元结点的指针。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
};
void PreorderTraversal( BinTree BT ); /* 先序遍历,由裁判实现,细节不表 */
void InorderTraversal( BinTree BT ); /* 中序遍历,由裁判实现,细节不表 */
BinTree Insert( BinTree BST, ElementType X );
BinTree Delete( BinTree BST, ElementType X );
Position Find( BinTree BST, ElementType X );
Position FindMin( BinTree BST );
Position FindMax( BinTree BST );
int main()
{
BinTree BST, MinP, MaxP, Tmp;
ElementType X;
int N, i;
BST = NULL;
scanf("%d", &N);
for ( i=0; i<N; i++ ) {
scanf("%d", &X);
BST = Insert(BST, X);
}
printf("Preorder:"); PreorderTraversal(BST); printf("\n");
MinP = FindMin(BST);
MaxP = FindMax(BST);
scanf("%d", &N);
for( i=0; i<N; i++ ) {
scanf("%d", &X);
Tmp = Find(BST, X);
if (Tmp == NULL) printf("%d is not found\n", X);
else {
printf("%d is found\n", Tmp->Data);
if (Tmp==MinP) printf("%d is the smallest key\n", Tmp->Data);
if (Tmp==MaxP) printf("%d is the largest key\n", Tmp->Data);
}
}
scanf("%d", &N);
for( i=0; i<N; i++ ) {
scanf("%d", &X);
BST = Delete(BST, X);
}
printf("Inorder:"); InorderTraversal(BST); printf("\n");
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
10
5 8 6 2 4 1 0 10 9 7
5
6 3 10 0 5
5
5 7 0 10 3
输出样例:
Preorder: 5 2 1 0 4 8 6 7 10 9
6 is found
3 is not found
10 is found
10 is the largest key
0 is found
0 is the smallest key
5 is found
Not Found
Inorder: 1 2 4 6 8 9
BinTree Insert( BinTree BST, ElementType X )
{
if(!BST){/*找到地方了,插进去*/
BinTree node = (BinTree)malloc(sizeof(struct TNode));
node->Left = node->Right = NULL;
node->Data = X;
return node;
}/*根据BST的性质查找结点*/
else if(X > BST->Data)
BST->Right = Insert(BST->Right,X);
else if(X < BST->Data)
BST->Left = Insert(BST->Left,X);
return BST;
}
BinTree Delete( BinTree BST, ElementType X )
{
Position temp;
if(!BST){
printf("Not Found\n");
return BST;
}
else if(X > BST->Data)
BST->Right = Delete(BST->Right,X);
else if(X < BST->Data)
BST->Left = Delete(BST->Left,X);
else if(X == BST->Data){/*这里其实有两个办法删除,即找该结点右子树的最小值或找该结点左子树的最大值*/
if(BST->Right && BST->Left){
temp = FindMin(BST->Right);
BST->Data = temp->Data;
BST->Right = Delete(BST->Right, BST->Data);
}
else{
temp = BST;
if(!BST->Left)
BST = BST->Right;
else
BST = BST->Left;
free(temp);
}
}
return BST;
}
Position Find( BinTree BST, ElementType X )
{
if(!BST)
return NULL;
else if(X > BST->Data)
return Find(BST->Right,X);
else if(X < BST->Data)
return Find(BST->Left,X);
else
return BST;
}
//最小值一定最左
Position FindMin( BinTree BST )
{
if(!BST)
return NULL;
while(BST->Left)
BST = BST->Left;
return BST;
}
//最大值一定最右
Position FindMax( BinTree BST )
{
if(!BST)
return NULL;
while(BST->Right)
BST = BST->Right;
return BST;
}
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
下面介绍四种旋转
右单旋
其实右单旋,左单旋的名字其实是非常有误导性的,至少我第一次记错了。所谓左单旋,并不是树的一部分向左旋转,而是一开始结点插入在某结点(所谓“发现者”)的左子树的左子树上,树是需要向右旋转的。右单旋同理。
左右旋:对于根的右子树先进行左单旋,再返回根的右单旋。
右左旋:先对左子树行右单旋,再返回对根的左单旋。
左单旋
左右旋
右左旋
#include <cstdio>
#include <cstdlib>
#include<algorithm>
using namespace std;
struct node{
int val;
node* left;
node* right;
};
typedef node* AVLTree;
node* NewNode(int val)
{
node* temp = (node*)malloc(sizeof(node));
temp->val = val;
temp->left = temp->right = NULL;
return temp;
}
node* SingleLeftRotation(node* tree)
{
node* temp = tree->left;
tree->left = temp->right;
temp->right = tree;
return temp;
}
node* SingleRightRotation(node* tree)
{
node* temp = tree->right;
tree->right = temp->left;
temp->left = tree;
return temp;
}
node* LeftRightRotation(node* tree)
{
tree->left = SingleRightRotation(tree->left);
return SingleLeftRotation(tree);
}
node* RightLeftRotation(node* tree)
{
tree->right = SingleLeftRotation(tree->right);
return SingleRightRotation(tree);
}
int GetHeight(node *tree)
{
if(!tree)
return 0;
else
return max(GetHeight(tree->left),GetHeight(tree->right))+1;
}
node* InsertNode(node* tree,int v)
{
if(!tree){
tree = NewNode(v);
}
else{
if(v > tree->val){
tree->right = InsertNode(tree->right,v);//插入的地方在右边
if(GetHeight(tree->right) - GetHeight(tree->left) == 2){//失衡了
if(v > tree->right->val)//插入到右子树的右边,右单旋
tree = SingleRightRotation(tree);
else if(v < tree->right->val)//插入到右子树的左边,右左旋
tree = RightLeftRotation(tree);
}
}
else if(v < tree->val){
tree->left = InsertNode(tree->left,v);//插入到左子树上
if(GetHeight(tree->left) - GetHeight(tree->right) == 2){//失衡了
//不建议对子树的高度进行储存,现用现算,否则不易更新
if(v > tree->left->val)//左子树的右子树上,左右旋
tree = LeftRightRotation(tree);
else if(v < tree->left->val)//左子树的左子树上,左单旋
tree = SingleLeftRotation(tree);
}
}
}
return tree;
}
int main(void)
{
int n,v;
node* tree = NULL;
scanf("%d", &n);
for(int i = 0;i < n; i++){
scanf("%d", &v);
tree = InsertNode(tree,v);
}
printf("%d",tree->val);
return 0;
}
04-树4 是否同一棵二叉搜索树 (25分)
给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{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
鸣谢青岛大学周强老师补充测试数据!
思路:
先按模板建一棵树,然后再按数据查找,如果:
①查找的路径上的数据标记为false(注意是路径!不是查找的终点),则BST不一样。查找走过的路上的结点之前一定查找过;
②如果查找到叶子结点,查找的值和叶子结点的值不一样,则BST不一样;
③如果查找完了没有返回false,则说明BST一样。
#include<cstdio>
#include<cstdlib>
struct treenode
{
int val;
treenode *right,*left;
bool flag;
};
treenode* newnode(int val)//创建一个新结点
{
treenode* tree = (treenode*)malloc(sizeof(treenode));
tree->left = NULL;
tree->right = NULL;
tree->flag = 0;
tree->val = val;
return tree;
}
treenode* insert(treenode* tree,int v)//插入一个结点
{
if(tree == NULL)
tree = newnode(v);
else{
if(v > tree->val)
tree->right = insert(tree->right,v);
else
tree->left = insert(tree->left,v);
}
return tree;
}
treenode* maketree(int n)//建树
{
int i,v;
scanf("%d",&v);
treenode* tree = newnode(v);
for(i = 1;i < n; i++){
scanf("%d",&v);
tree = insert(tree,v);
}
return tree;
}
void reset(treenode* tree)//将BSTflag归零,防止上次测试干扰下次
{
if(tree->left)
reset(tree->left);
if(tree->right)
reset(tree->right);
tree->flag = false;
}
bool check(treenode* tree,int v)
{
if(tree->flag){
if(v > tree->val)
return check(tree->right,v);
else if(v < tree->val)
return check(tree->left,v);
else//之前查找过了又查找过一次
return false;
}
else{//这个结点没查找过,如果相等,则找到了,不相等,则查找的路径上右未被查找的元素,返回false
if(v != tree->val)
return false;
else{
tree->flag = true;
return true;
}
}
}
bool judge(treenode* tree,int n)
{
int v;
bool flag = false;//标记,如果不相同则为true,相同则为false
scanf("%d",&v);
if(tree->val != v)//检查根结点
flag = true;//不匹配直接不相同
else
tree->flag = true;//继续检查子树的结点
for(int i = 1;i < n; i++){
scanf("%d",&v);//即使因为根判断不相同以后也要把这一行的数据全部读完
if(!flag && !check(tree,v))//flag为true时直接跳过check
flag = true;
}
if(flag)
return false;
else
return true;
}
void freetree(treenode*tree)//防止内存泄漏,否则容易段错误
{
if(tree->left)
freetree(tree->left);
if(tree->right)
freetree(tree->right);
free(tree);
}
int main(void)
{
int n,l;
scanf("%d", &n);
treenode* tree;
while(n){
scanf("%d", &l);
tree = maketree(n);
for(int i = 0; i < l; i++){
if(judge(tree,n))
printf("Yes\n");
else
printf("No\n");
reset(tree);
}
freetree(tree);
scanf("%d",&n);
}
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
思路:
给出的数据从小到大排序后其实是为CBT的后序遍历。
从小到大排序后,树根结点的位置 = 左子树的结点数 + 1;
由此递归解决问题。
#include<cstdio>
#include<cmath>
#include<algorithm>
int level_order[1010] = {0};//记录层序遍历的顺序
bool cmp(int a,int b)//从小到大排序
{
return a < b;
}
int getleftlen(int n)//给出树的结点数求出左子树的结点数
{
int left_height = log2(n);
int left_len = pow(2,left_height-1)-1;
int others = n - 2*left_len-1;
if(others <= pow(2,left_height-1))
left_len += others;
else
left_len += pow(2,left_height-1);
return left_len;
}
void levelorder(int left,int right,int in[],int pos)
{
if(left > right)
return;
int n = right - left + 1;
int left_len = getleftlen(n);
level_order[pos] = in[left+left_len];
levelorder(left+left_len+1,right,in,2*pos+2);
levelorder(left,left+left_len-1,in,2*pos+1);
}
int main(void)
{
int n;
scanf("%d",&n);
int in_order[1010] = {0};
for(int i = 0; i < n; i++)
scanf("%d",&in_order[i]);
std::sort(in_order,in_order+n,cmp);
levelorder(0,n-1,in_order,0);
for(int i = 0; i < n-1; i++)
printf("%d ",level_order[i]);
printf("%d",level_order[n-1]);
return 0;
}
上一篇: Bootstrap基本CSS样式
下一篇: 修改this的指向