以前,我总以为,树象征着生命,象征的生机;
后来,我遇到了那个它,我才知道,树会让你死亡,还是死无全尸的那种。。。
你以为的树:
实际中的树:
好家伙,先序后序中序,后序先序中序,中序后序先序,绕死一个算一个!!!
话不多说,题来(如果我被绑架了我就眨眨眼 )
题目1:
按先序序列建立二叉树,并输出该二叉树的中序遍历和后序遍历
输入:
先序序列:ABDH##I##E##CF#J##G##(#表示空)
输出:
中序序列:HDIBEAFJCG
后序序列: HIDEBJFGCA
注意:当只输入一个#时,需返回空二叉树
图解:
题目2:
给定一棵二叉树的后序和中序遍历序列,构造该二叉树,并输出该二叉树的前序遍历
输入:
后序序列: 3424321
中序序列: 3241423
输出:
前序序列: 1234243
注意:当输入的后序和中序遍历序列不能够构造出二叉树时,应输出:Unable to build a binary tree,这里的不能构造二叉树包括序列长度不一致、序列所含字符不一致以及不能够构造一棵二叉树等。
图解:
题目3:
给定一棵二叉树,返回该二叉树的叶子节点数和宽度
输入:
二叉树根节点:T
输出:
二叉树的叶子节点数:5
二叉树的宽度:4
图解:
题目4:
给定两棵二叉树,判断两棵二叉树是否等价。等价输出1,否则输出0
输入:
二叉树根节点:T
输出:
图1:1
图2:0
图解:
想必很多小伙伴们看完题后嗖嗖嗖地就把代码敲出来了吧(是我不配),就让我独自承受脱发的痛苦吧。
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define N 21 //后序序列和中序序列字符的最大个数为N-1
int FLAG; //标识能否由后序序列和中序序列建立二叉树,能为1,否为0
typedef struct Node
{
char data;
struct Node *lchild, *rchild;
}TreeNode, *BiTree; //定义树节点的结构体
//函数功能:先序建立二叉树,并返回指向该二叉树的指针
BiTree CreateBiTree(void)
{
BiTree bt = NULL;
char data;
if((data = getchar()) != '\n')
{
if(data == '#')
{
bt = NULL; //字符#表示节点为空
}
else
{
bt = (BiTree)malloc(sizeof(TreeNode));
if(!bt)
{
printf("OVERFLOW\n!");
exit(0);
}
bt->data = data; //树根
bt->lchild = CreateBiTree(); //先序建立左子树
bt->rchild = CreateBiTree(); //先序建立右子树
}
}
return bt;
}
//函数功能:先序遍历二叉树
void PreOrderTraverse(BiTree T)
{
if(T)
{
printf("%c", T->data); //访问节点
PreOrderTraverse(T->lchild); //先序遍历左子树
PreOrderTraverse(T->rchild); //先序遍历右子树
}
return;
}
//函数功能:中序遍历二叉树
void InOrderTraverse(BiTree T)
{
if(T)
{
InOrderTraverse(T->lchild); //中序遍历左子树
printf("%c", T->data); //访问节点
InOrderTraverse(T->rchild); //中序遍历右子树
}
return;
}
//函数功能:后序遍历二叉树
void PostOrderTraverse(BiTree T)
{
if(T)
{
PostOrderTraverse(T->lchild); //后序遍历左子树
PostOrderTraverse(T->rchild); //后序遍历右子树
printf("%c", T->data); //访问节点
}
return;
}
//判断能否根据后序序列和中序序列构造二叉树,此函数的判定内容为后序序列和中序序列所含的字符是否相同
//说明:如果后序序列和中序序列能构造二叉树,那么其递归的左子树和右子树所含字符始终相同,当有任意一对左右子树含有不同字符时,输入的序列不能构成二叉树
void Judge(char post[], char in[], int num)
{
for(int i = 0; i < num; i++)
{
if(!strchr(in, post[i])) //后序序列含有中序序列所不含有的字符,不能构成二叉树
{
FLAG = 0;
return;
}
}
for(int i = 0; i < num; i++) //中序序列含有后序序列所不含有的字符,不能构成二叉树
{
if(!strchr(post, in[i]))
{
FLAG = 0;
return;
}
}
}
//函数功能:根据后序序列与中序序列构造二叉树,并返回指向该二叉树的指针
//参数说明:post[]为后序序列,in[]为中序序列,num为字符个数
BiTree PostInCreate(char post[], char in[], int num)
{
BiTree bt = NULL;
int i, num_left = 0, num_right = 0;
char post_left[N], in_left[N], post_right[N], in_right[N];
Judge(post, in, num); //判断后序序列和前序序列能否构成二叉树
if(num > 0 && FLAG) //序列不为空且能够构成二叉树
{
bt = (BiTree)malloc(sizeof(TreeNode));
bt->data = post[num-1]; //树根为后序序列的最后一个字符
for(i = 0; i < num; i++)
{
if(in[i] == bt->data) //求出树根在中序序列中的位置
break;
}
num_left = i; //左子树的节点个数
num_right = num-i-1; //右子树的节点个数
for(i = 0; i < num_left; i++)
{
post_left[i] = post[i]; //左子树的后序序列
in_left[i] = in[i]; //左子树的中序序列
}
for(i = 0; i < num_right; i++)
{
post_right[i] = post[num-num_right-1+i]; //右子树的后序序列
in_right[i] = in[num-num_right+i]; //右子树的中序序列
}
bt->lchild = PostInCreate(post_left, in_left, num_left); //根据后序序列与中序序列构造左子树
bt->rchild = PostInCreate(post_right, in_right, num_right); //根据后序序列与中序序列构造右子树
}
return bt;
}
//函数功能:计算并返回叶子节点的数量
int CountLeafSum(BiTree T)
{
if(!T) //空树
return 0;
if(T->lchild == NULL && T->rchild == NULL) //只含树根节点
return 1;
return (CountLeafSum(T->lchild) + CountLeafSum(T->rchild)); //叶子节点的数量等于左子树叶子节点的数量+右子树叶子结点的数量
}
//函数功能:计算并返回二叉树的高度
int CountHeight(BiTree T)
{
int ldepth, rdepth;
if(!T) //空树
return 0;
if(T->lchild == NULL && T->rchild == NULL) //只含树根节点
return 1;
ldepth = CountHeight(T->lchild); //左子树的高度
rdepth = CountHeight(T->rchild); //右子树的高度
return ((ldepth > rdepth ? ldepth : rdepth) + 1); //二叉树的高度是其左子树和右子树中较高的一个子树的高度加1
}
//函数功能:求出一个二叉树每一层的节点数量
//参数说明:数组count[]记录每一层的节点数
void GetWidth(BiTree T, int count[], char LEVEL[])
{
struct Queue{
BiTree Node;
int level;
}Q[N];
int front = 0, rear = 0;
if(!T) //空树,直接返回
return;
else
{
Q[front].Node = T; //队头为树根
Q[front].level = 1; //树根的层级为1
while(front <= rear)
{
if(Q[front].Node->lchild) //队头树根的左子树存在
{
Q[++rear].Node = Q[front].Node->lchild; //队尾插入左子树的树根
Q[rear].level = Q[front].level + 1; //左子树树根的层级为当前树根的层级加1
}
if(Q[front].Node->rchild) //队头树根的右子树存在
{
Q[++rear].Node = Q[front].Node->rchild; //队尾插入右子树的树根
Q[rear].level = Q[front].level + 1; //右子树树根的层级为当前树根的层级加1
}
front++; //队头指针下移
}
for(int i = 0; i <= rear; i++)
{
LEVEL[i+1] = Q[i].Node->data; //层序遍历
LEVEL[0]++; //记录节点个数
count[Q[i].level-1]++; //遍历整个队列,统计各层级的节点数
}
return;
}
}
//函数功能:判断两树是否等价,是返回1,否返回0
//参数说明:T1:第一棵二叉树,T2:第二棵二叉树
int IsEquivalent(BiTree T1, BiTree T2)
{
int x = 0;
if(!T1 && !T2) //两棵树均为空树
{
x = 1;
}
else if((!T1 && T2) || (T1 && !T2)) //一棵为空树,另一棵不为空树
{
x = 0;
}
else //两棵树均不为空树
{
if(T1->data == T2->data) //节点信息相同
{
if(IsEquivalent(T1->lchild, T2->lchild)) //左子树等价
{
if(IsEquivalent(T1->rchild, T2->rchild)) //右子树等价
{
x = 1;
}
}
}
}
return x;
}
//任务1:实现二叉树的先序、中序、后序遍历
void Task1(BiTree T)
{
printf("\nStart task (1) Create Tree in PreOrder\n");
if(T)
{
printf("PreOrderTraverse: ");
PreOrderTraverse(T);
printf("\n");
printf("InOrderTraverse: ");
InOrderTraverse(T);
printf("\n");
printf("PostOrderTraverse: ");
PostOrderTraverse(T);
printf("\n");
}
else //空树
{
printf("The BiTree is NULL!\n");
}
}
//任务2:根据后序序列和中序序列构造二叉树,当这两个序列不能构造二叉树时,输出"Can not build a BiTree!"
BiTree Task2(BiTree *T)
{
printf("\nStart task (2) Input the postOrder and inOrder Sequence ,Then build the tree\n");
char post[N] = {0}; //后序序列
char in[N] = {0}; //中序序列
int postlen, inlen;
while(getchar() != '\n')continue;
printf("Please input the postorder sequence(less than %d nodes): ", N);
scanf("%s",post);
while(getchar() != '\n')continue;
printf("Please input the inorder sequence(less than %d nodes): ", N);
scanf("%s",in);
postlen = strlen(post);
inlen = strlen(in);
if(postlen != inlen) //序列长度不同,不能构造二叉树
{
FLAG = 0;
}
else
{
*T = PostInCreate(post, in, postlen); //递归构造二叉树
if(FLAG) //能够构造二叉树
{
printf("PreOrderTraverse: ");
PreOrderTraverse(*T); //先序遍历二叉树
printf("\n");
}
}
if(!FLAG) //不能构造二叉树
{
*T = NULL; //空树
printf("Can not build a BiTree!\n");
}
return *T;
}
//任务3:计算并打印二叉树的叶子节点个数、高度、宽度
void Task3(BiTree T)
{
printf("\nStart task (3) ------------------------------\n");
int maxwidth = 0; //树的宽度,初始化为0
int height;
int i;
int count[N] = {0};
char LEVEL[N] = {0};
height = CountHeight(T); //树的高度
printf("The number of leaf nodes of the tree is: ");
printf("%d\n",CountLeafSum(T)); //打印叶子节点的数量
printf("The height of the tree is: ");
printf("%d\n", height); //打印树的高度
GetWidth(T, count, LEVEL);
for(i = 0; i < height; i++)
{
if(count[i] > maxwidth)
{
maxwidth = count[i];
}
}
printf("LevelOrderTraverse: ");
if(LEVEL[0] == 0)
{
printf("The BiTree is NULL!");
}
for(i = 1; i <= LEVEL[0]; i++)
{
printf("%c", LEVEL[i]);
}
for(i = 0; i < height; i++)
{
printf("\nThe No.%2d level has %d nodes.", i+1, count[i]);
}
printf("\nThe width of the tree is: ");
printf("%d\n", maxwidth); //打印树的宽度
}
//任务4:判断两个二叉树是否等价
void Task4(BiTree T1,BiTree T2)
{
printf("\nStart task (4) Are two Bitrees equivalent?");
printf("(Equal: 1 Unequal: 0)\n");
printf("Their relationship is %d.\n\n",IsEquivalent(T1, T2));
}
int main()
{
BiTree Bt1, Bt2;
char order;
printf("1.Create BiTree_one with PRE 2.Create BiTree_two with POST and IN\n");
printf("3.Count BiTree_one 4.Count BiTree_two 5.Judge whether they are equal\n");
printf("Input your order(q to quit): ");
scanf("%c", &order);
do{
switch (order)
{
case'1':printf("Create BiTree_one in PreOrder(less than %d nodes): ", N);
while(getchar() != '\n')continue;
Bt1=CreateBiTree();
Task1(Bt1);
break;
case'2':FLAG = 1;
Task2(&Bt2);
break;
case'3':Task3(Bt1);
break;
case'4':Task3(Bt2);
break;
case'5':Task4(Bt1, Bt2);
break;
default:exit(0);
}
while(getchar() != '\n')continue;
printf("\nInput your order(q to quit): ");
}while(scanf(" %c", &order));
return 0;
}
虽然说这里有4个题目,但还是要把它们封装成一个程序,并且可以通过循环来让程序能够反复实现我们所需的功能(要是提交4个程序给老师,我怕是不想活了)
敲黑板!!!
可能很多人都觉得我发这些实验有用吗,都没什么干货,题也不分析,知识点也不总结,就给出题干代码来骗赞。。。
你这么说我就不乐意了(还是蛮赞同的*),发题主要是为了看到这篇文章的小伙伴们能够动脑动手敲一敲,在不懂的地方可以参考一下我的代码(帮我找找bug呀 ),里面也有部分解析(我承认确实是部分 ),知识点啥的呢以后会分点细讲的(手动单曲循环《后来》 ),所以还请大家多多包涵和支持,共同进步啊!!!