实验五 二叉树及其应用
(必做题)设计并验证如下算法:按中序建立两棵二叉树的二叉链表结构,判断两棵二叉树是否相等。
如先序扩展序列972#1##6#53##4##8##可确定唯一的二叉树,但它的中序扩展序列为#2#1#7#6#3#5#4#9#8#,两个结点之间有且仅有一个’#’,无法确定唯一的二叉树。因此在中序序列上,为每个子树加上括号,变成:(((#2(#1#))7(#6((#3#)5(#4#))))9(#8#)),有点类似广义表了,则可确定唯一的二叉树。
如何判断两棵二叉树的结构是一样的、且对应的每个结点都有着相同的值。
对于①如何判断两棵二叉树的结构是一样的、对应的每个结点都有着相同的值
有两种方法:一种是递归比较。另一种是二叉树的遍历。
先说二叉树的遍历。由于先序遍历 再加上 中序遍历能唯一确定一棵二叉树。故,对这两棵树分别进行先序和中序遍历,比较这两棵树的先序遍历序列和中序遍历序列,如果都一样则说明这两棵二叉树是一样的。这里用了两次遍历。时间复杂度为O(2N)
由于二叉树的中序遍历和先序/后序遍历比较容易,故不用代码实现了。
下面来看如何用递归来判断两棵二叉树是不是一样的。
我们的思路如下:首先比较根结点是不是一样的;如果根结点一样,再继续比较根的左右孩子是不是一样的,这是一个递归过程。
public boolean sameTree2(BinaryNode<T> root1, BinaryNode<T> root2){
//树的结构不一样
if((root1 == null && root2 != null) || (root1 != null && root2 == null))
return false;
//两棵树最终递归到终点时
if(root1 == null && root2 == null)
return true;
if(root1.element.compareTo(root2.element) != 0)
return false;
else
return sameTree2(root1.left, root2.left) && sameTree2(root1.right, root2.right);
}
第3行的if语句是输入的两棵树的初始情况判断。
第6行的理解如下:若两棵树是一样的,那么它们不断递归比较结点,最终二棵树的叶子结点都比较完了,即都比较到了空结点,此时它们就是相同的。
第10行到第13行则是整个正常的递归过程:先判断当前的根结点是不是一样的,如果不是直接返回false(第11行),如果当前的根结点是一样的,则继续递归比较当前根结点的左子树和右子树(第13行),只有当左右子树都是true是, 位与(&&)操作才返回true。
这种方式对两棵二叉树只遍历了一次就可以判断两棵树是否相同,而且当树不相同时,是不需要遍历完整棵树的(第10行if成立时,立即return)。相比于,上面提到的中序遍历加先序遍历,不管二棵树是否相同,都需要遍历 整棵树。
故这种递归方法的最坏时间复杂度为O(N)
Status Createtree(Bitree &root,int begin,int end,char s[MAXSIZE]) {
if (begin>end) {
root=NULL;
return OK;
}
int i=begin,num=0,endl=end;
while(i<=end) {
if (s[i]=='(') num++;
if (s[i]==')') num--;
if (s[i]!='('&&s[i]!=')'&&s[i]!='#') {
if (num==0) break;
}
i++;
}
root=(BiNode *)malloc(sizeof(BiNode));
root->data=s[i];
Bitree stack[MAXSIZE],p=root;
int top=0,mid=i;
while(p||top>=0) {
if(!p) {
stack[top++]=p;
p=p->lchild;
} else {
p=stack[top--];
i=mid+1;
end=end-2;
while(i<=end) {
if (s[i]=='(') num++;
if (s[i]==')') num--;
if (s[i]!='('&&s[i]!=')'&&s[i]!='#') {
if (num==0) break;
}
i++;
}
if(i>end) {
p=NULL;
break;
} else {
p=(BiNode *)malloc(sizeof(BiNode));
p->data=s[i];
p=p->rchild;
}
}
}
return OK;
}
2019年11月29日 20:23:37
#include
#include
#include
#include
#include
#include
#include
#include
#define TURE 1
#define FLASE 0
#define ERROR 0
#define OVERFLOW -2
#define OK 1
#define INFLASEBLE -1
#define STACKSIZE 50
#define MAXSIZE 200
typedef char DataType;
typedef int Status;
typedef struct BiNode {
DataType data;
BiNode *lchild;
BiNode *rchild;
}*Bitree,BitNode;
Status Createtree(Bitree *root,int begin,int end,char s[MAXSIZE]) {
if (begin>end) {
*root=NULL;
return OK;
}
int i=begin,num=0;
while(i<=end) {
if (s[i]=='(') num++;
if (s[i]==')') num--;
if (s[i]!='('&&s[i]!=')'&&s[i]!='#') {
if (num==0) break;
}
i++;
}
*root=(BiNode *)malloc(sizeof(BiNode));
(*root)->data=s[i];
Createtree(&(*root)->lchild,begin+1,i-2,s);
Createtree(&(*root)->rchild,i+2,end-1,s);
return OK;
}
void Preorder(Bitree root) {
if(root!=NULL) {
printf("%c",root->data);
Preorder(root->lchild);
Preorder(root->rchild);
}
}
void InOrder(Bitree root){
Bitree stack[MAXSIZE];
Bitree p = root;
int top=-1;
while(p || top>=0){
if(p != NULL){
stack[++top]=p;
p = p->lchild;
}
else{
p = stack[top--];
printf("%c",p->data);
p = p->rchild;
}
}
}
bool SameJudge(Bitree root1,Bitree root2) {
if (root1==NULL&&root2==NULL) return true;
if ((root1==NULL&&root2!=NULL)||(root1!=NULL&&root2==NULL)||root1->data!=root2->data)
return false;
return SameJudge(root1->lchild,root2->lchild)&&SameJudge(root1->rchild,root2->rchild);
}
int main() {
while(1) {
char s[MAXSIZE];
printf("请输入第一棵树:\n");
scanf("%s",s);
int i=0,j=0;
Bitree root1,root2;
int len=strlen(s);
Createtree(&root1,0,len-1,s);
printf("请输入第二棵树:\n");
scanf("%s",s);
len=strlen(s);
Createtree(&root2,0,len-1,s);
printf("第一棵树的前序遍历为:\n");
Preorder(root1);
printf("\n第一棵树的中序遍历为:\n ");
InOrder(root1);
printf("\n");
printf("第二棵树的前序遍历为:\n");
Preorder(root2);
printf("\n第二棵树的中序遍历为:\n ");
InOrder(root2);
printf("\n");
if (SameJudge(root1,root2)) printf("两棵树相同\n");
else printf("两棵树不相同\n");
printf("\n\n\n\n\n\n\n\n\n");
}
return 0;
}
//先序扩展序列972#1##6#53##4##8##可确定唯一的二叉树
//中序扩展序列#2#1#7#6#3#5#4#9#8#
//无法确定唯一的二叉树
//(((#2(#1#))7(#6((#3#)5(#4#))))9(#8#))
//(((2(1))7(6((3)5(4))))9(8))类似广义表
/*
9
/ \
7 8
/\
2 6
\ \
1 5
/\
3 4
下面空看为#结束符
*/
//(((#2(#0#))7(#6((#3#)5(#4#))))9(#8#))
(必做题)设计并验证如下算法:输入一棵二叉树的广义表形式,建立该二叉树的二叉链表结构,并求其总结点数目。例如,对“设计并验证如下算法:按层次遍历二叉树,打印结点所在层次,并且求二叉树的宽度”所示二叉树,按下列形式读入字符:C(E(I,J),F(,G(K,H))#。
#include
#include
#include
#include
#include
#include
#include
#include
#define TURE 1
#define FLASE 0
#define ERROR 0
#define OVERFLOW -2
#define OK 1
#define INFLASEBLE -1
#define STACKSIZE 50
#define MAXSIZE 200
typedef char DataType;
typedef int Status;
typedef struct BiTnode {
DataType data;
struct BiTnode *lchild, *rchild;
}*BiTree,BitNode;
Status CreateBiTree(BiTree *T, DataType *str);
Status OutTree(BiTree T);
int main() {
int len = 0;
char ch, str[MAXSIZE];
BiTree T;
printf("请输入广义表,以‘#’结束:");
while ((ch=getchar())!='\n') {
str[len++] = ch;
}
if (CreateBiTree(&T, str)) {
printf("创建成功!");
} else {
printf("创建失败!");
}
OutTree(T);
return 0;
}
Status CreateBiTree(BiTree *T, DataType *str) {
BiTree Stack[MAXSIZE], p = NULL;
int top = 0, k = 0, j = 0;
char ch;
*T = NULL;
ch = str[j];
while (ch!='#') {
switch (ch) {
case '(':
Stack[top++] = p;
k = 1;
break;
case ')':
top--;
break;
case ',':
k = 2;
break;
default:
p = (BiTree)malloc(sizeof(BitNode));
p->data = ch;
p->lchild = p->rchild = NULL;
if (*T==NULL) {
*T = p;
} else {
switch (k) {
case 1:
Stack[top - 1]->lchild = p;
break;
case 2:
Stack[top - 1]->rchild = p;
break;
}
}
break;
}
ch = str[++j];
}
return OK;
}
Status OutTree(BiTree T) {
BitNode *queue[MAXSIZE];
BitNode *p;
int front, rear, n=0,count=0,widcount=0;
front = rear = 0;
queue[rear++] = NULL;
p = T;
if (p!=NULL) {
queue[rear++] = p;
}
do {
p = queue[front++];
if (p==NULL) {
queue[rear++] = NULL;
n++;
printf("\n");
} else {
printf("第%d层次:%c\n",n,p->data);
count++;
if(p->lchild==NULL && p->rchild==NULL) widcount++;
if (p->lchild!=NULL) {
queue[rear++] = p->lchild;
}
if (p->rchild!=NULL) {
queue[rear++] = p->rchild;
}
}
} while (front!=rear-1);
printf("\n\n二叉树的宽度为:%d\n",widcount);
printf("二叉树总结点数目为:%d\n",count);
return OK;
}
//c(e(i,j),f(,g(k,h))#
/*
c
/ \
e f
/\ /
i j g
/\
k h
*/
参考版
已知某二叉树采用广义表形式作为输入,请写一个非递归算法,建立二叉树的二叉链表存储结构。采用广义表形式表示二叉树的约定如下:
(1)表中的一个字母表示一个结点的数据信息;
(2)每个根节点作为由子树构成的表的名字放在表的前面;
(3)每个结点的左子树与右子树之间用逗号分开;如果只有右子树而无左子树,则逗号不能省略;
(4)整个广义表的末尾由一个特殊符号‘@’作为表的结束标志。
A(B(D),C(F(,E),G))@
表示一棵二叉树,该二叉树的根节点为A,其左孩子结点为B,右孩子结点为C,而D是B的左孩子结点,F和G分别是C的左右结点。E是F的右孩子结点。这课二叉树的图形表示
如图所示
本题类似于算术表达式求值和先序遍历的非递归过程。主要问题是建立某结点的左子树后,如何建立该结点的右子树。为此设置一个栈,用来存放根结点的指针,便于构造二叉树。这里采用栈是因为在顺序读取广义表所表示的二叉树结点具有后进先出的特性。
算法步骤:
依次读取广义表中的字符,根据不同情况按照以下方式处理:
(1)遇到左括号,可能接下来读取的元素是左孩子,需要将双亲结点入栈,同时将标志k置为1;
(2)遇到逗号,下一个读取的元素一定是右孩子,将标志置为2;
(3)遇到右括号,表明当前层读取结束,需要回退到上一层,上一层的栈元素将成为新的双亲结点;
(4)遇到字符,创建一个新结点,将当前字符ch存入数据域,然后将该结点插入对应的子树中。根据k的值进行以下处理:
①k为1,则使该结点成为栈顶元素结点的左孩子结点;
②k为2,则使该结点成为栈顶元素结点的右孩子结点。
#include
#include
#include
typedef char DataType;
#define MAXSIZE 200
using namespace std;
typedef struct BiTnode
{
DataType data;
struct BiTnode *lchild, *rchild;
}*BiTree,BitNode;
int CreateBiTree(BiTree *T, DataType *str);
void DispBTNode(BiTree T);
int CreateBiTree(BiTree *T, DataType *str)
{
BiTree S[MAXSIZE], p = NULL;
int top = 0, k = 0, j = 0;
char ch;
*T = NULL;
ch = str[j];
while (ch!='@')
{
switch (ch)
{
case '(':
S[top++] = p;
k = 1;
break;
case ')':
top--;
break;
case ',':
k = 2;
break;
default:
p = (BiTree)malloc(sizeof(BitNode));
p->data = ch;
p->lchild = p->rchild = NULL;
if (*T==NULL)
{
*T = p;
}
else
{
switch (k)
{
case 1:
S[top - 1]->lchild = p;
break;
case 2:
S[top - 1]->rchild = p;
break;
}
}
break;
}
ch = str[++j];
}
return 1;
}
void main()
{
int n, len = 0;
char ch, str[MAXSIZE];
BiTree T;
cout << "请输入广义表,以‘@’结束:" << endl;
while ((ch=getchar())!='\n')
{
str[len++] = ch;
}
n = CreateBiTree(&T, str);
if (n==1)
{
cout << "创建成功!" << endl;
}
else
{
cout << "创建失败!" << endl;
}
DispBTNode(T);
system("pause");
}
void DispBTNode(BiTree T)
{
BitNode *qu[MAXSIZE];
BitNode *p;
int front, rear, n;
n = 0;
front = rear = 0;
qu[rear++] = NULL;
p = T;
if (p!=NULL)
{
qu[rear++] = p;
}
do
{
p = qu[front++];
if (p==NULL)
{
qu[rear++] = NULL;
n++;
printf("\n");
}
else
{
cout << "第" << n << "层:" << p->data << endl;
if (p->lchild!=NULL)
{
qu[rear++] = p->lchild;
}
if (p->rchild!=NULL)
{
qu[rear++] = p->rchild;
}
}
} while (front!=rear-1);
}