代码中所用到的结构体定义
typedef struct Node
{
char ch;//存放数据
struct Node *lchild, *rchild;
struct Node *next;
} TreeNode, *BiTree; //定义树节点的结构体
二叉树的交互式建立及二叉树的三种遍历
二叉树的交互式建立
- 二叉树的交互式建立运用了递归的算法,以先输入数据,判断是否合法,再以(L R T)的形式进行二叉树的建立,其中,以‘#’作为递归结束符。
BiTree createBiTree()//建立二叉树
{
char e;
scanf("%c",&e);//输入数据
getchar();
if(e=='#')//判断是否有后续结点
return NULL;
else
{
BiTree n=(BiTree)malloc(sizeof(TreeNode));//申请空间
n->lchild=NULL;
n->rchild=NULL;
n->ch=e;
printf("Please enter the left child of %c\n",e);
n->lchild=createBiTree();//创建左儿子
printf("Please enter the right child of %c\n",e);
n->rchild=createBiTree();//创建右儿子
return n;
}
}
二叉树的前序遍历(T L R)
void preOrderTraverse(BiTree p)//前序遍历
{
if(p==NULL)//判断是否遍历到底结点
return;
else
{
printf("%c",p->ch);
preOrderTraverse(p->lchild);//遍历左子树
preOrderTraverse(p->rchild);//遍历右子树
}
}
二叉树的中序遍历(L T R)
void inOrderTraverse(BiTree p)//中序遍历
{
if(p->lchild!=NULL)//判断是否存在左儿子
{
inOrderTraverse(p->lchild);//向左儿子走一步
}
printf("%c",p->ch);
if(p->rchild!=NULL)//判断是否存在右儿子
{
inOrderTraverse(p->rchild);
return;
}
else if(p->rchild==NULL)
{
return;
}
}
二叉树的后序遍历(L R T)
void postOrderTraverse(BiTree p)//后序遍历
{
if(p->lchild!=NULL)//判断是否存在左儿子
{
postOrderTraverse(p->lchild);//左走一步
}
if(p->rchild!=NULL)//判断是否存在右儿子
{
postOrderTraverse(p->rchild);//右走一步
}
printf("%c",p->ch);
return;
}
根据前序与中序序列构造二叉树,并返回根节点
解决思想
- 可以运用递归的方法,解决方向是,在先序遍历中,找到根节点,即第一个数据为根节点。
- 再寻找中序排列中与前序序列第一个一样的数据,即寻找树的根节点。
- 寻找到后,以根节点为中心,将中序序列分成左子树的序列和右子树的序列,同时也将先序序列分成左子树序列和右子树序列。
- 进行递归,在递归过程中,将当前根结点的左儿子指针指向左子树返回的根节点,右儿子指针指向右子树返回来的根结点。
- 直到递归结束。
BiTree* BinaryTreeFromOrderings(char inorder[], char preorder[],int inorder_index,int preorder_index, int length)
{
//函数功能:根据前序与中序序列构造二叉树,并返回根节点
//参数说明:inorder:中序序列字符数组,preorder:前序序列字符数组,inorder_index:记录中序序列索引,preorder_index:记录前序序列索引,length:序列长度
int i,j,k,l,m,n,i1,j1;
int x,y;
char e1;
char pr1[100],pr2[100];
char in1[100],in2[100];
memset(pr2,0,100);
memset(pr1,0,100);
memset(in1,0,100);
memset(in2,0,100);
BiTree n2,bt1,bt2;
e1=preorder[0];
for(i=0;i<strlen(inorder);i++)
{
if(inorder[i]==e1)//寻找中序排列中与前序序列第一个一样的数据
{
x=i;
break;
}
}
n2=(BiTree)malloc(sizeof(TreeNode));
n2->lchild=NULL;
n2->rchild=NULL;
n2->ch=e1;//建立根节点
for(j=0;j<x;j++)
{
in1[j]=inorder[j];//复制中序排列中根结点左边的数据
}
y=x+1;
for(k=1,n=0;k<x+1;n++,k++)
{
pr1[n]=preorder[k];//复制先序排列中根结点左边的数据
}
if(x!=0)//如果根节点左边存在数据,则将当前根结点的左儿子指向该数据的根结点
{
n2->lchild=BinaryTreeFromOrderings(in1,pr1,0,0,strlen(pr1));
}
for(l=y,m=0;l<strlen(inorder);m++,l++)//复制中序排列中根结点右子树的数据
{
in2[m]=inorder[l];
}
for(i1=0,j1=y;j1<strlen(inorder);i1++,j1++)//复制前序排列中根结点右子树的数据
{
pr2[i1]=preorder[j1];
}
if(m!=0)//如果根节点右边存在数据,则将当前根结点的右儿子指向该数据的根结点
{
n2->rchild=BinaryTreeFromOrderings(in2,pr2,0,0,strlen(pr2));
}
return n2;
}
二叉树的结构对称判断和数据对称判断
二叉树的结构对称
- 其实结构对称的思想很简单,只需先遍历一下根节点,将树分为左子树和右子树,借助队列,两棵子树均以层次遍历的方法进行遍历,只是左子树的遍历顺序为从左到右,右子树的顺序为从右到左,只要保证每一步的遍历结果一样,直到遍历结束,则表示结构对称。
int isSymmetrical(BiTree root)
{
//判断以root为根节点的二叉树是否是镜像对称的
int left1=0,right1=0;
int left2=0,right2=0;
BiTree root1,root2;
pQueue que;
que=InitQueue();//初始化队列
que->back=EnQueue(que,root);
root=DeQueue(que);
if(root->lchild!=NULL)//左儿子不空则标记
{
left1=1;
}
if(root->rchild!=NULL)//右儿子不空则标记
{
right1=1;
}
if(left1!=0&&right1!=0)//判断该结点左右是否相等都有儿子
{
left1=0;//清空
right1=0;//清空
que->back=EnQueue(que,root->lchild);
que->back=EnQueue(que,root->rchild);
while(isEmpty(que))//使用两个对称结点,判断是否对称,当队列为空时,退出循环
{
root1=DeQueue(que);
root2=DeQueue(que);
if(root1->lchild!=NULL)
{
left1=1;
}
if(root2->rchild!=NULL)
{
right2=1;
}
if((left1==1)&&(right2==1))
{
que->back=EnQueue(que,root1->lchild);
que->back=EnQueue(que,root2->rchild);
}
if(left1!=right2)
{
return 0;
}
if(root1->rchild!=NULL)
{
right1=1;
}
if(root2->lchild!=NULL)
{
left2=1;
}
if((right1==1)&&(left2==1))//两个结点是否镜像对称
{
que->back=EnQueue(que,root1->rchild);
que->back=EnQueue(que,root2->lchild);
}
if(right1!=left2)
{
return 0;
}
left1=0;
left2=0;
right1=0;
right2=0;
}
if(isEmpty(que)==0)//队列为空,返回1
{
return 1;
}
}
else if(right1==0&&left1==0)//只有根结点时
{
return 1;
}
else
{
return 0;
}
}
二叉树的数据对称
- 由于上面已经对二叉树的结构进行判断,故只需在结构对称的基础下,对二叉树的L T R遍历结果等于R T L的遍历结果,即可判断其为数据对称的二叉树
int isSymmetricalPlus(BiTree root)//判断二叉树的数据和结构是否镜像对称
{
int i;
postOrderTraversePlus1(root);//LRT遍历
postOrderTraversePlus2(root);//RLT遍历
for(i=0;i<strlen(a);i++)//判断遍历结果是否一样
{
if(a[i]!=b[i])
break;
}
if(i==strlen(a))//全部相等
{
return 1;
}
else
{
return 0;
}
}
整个程序的源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
char a[100];//用于存放按L R T遍历的数据
int i0=0;
char b[100];//用于存放按R L T遍历的数据
int j0=0;
typedef struct Node
{
char ch;//存放数据
struct Node *lchild, *rchild;
struct Node *next;
} TreeNode, *BiTree; //定义树节点的结构体
typedef struct queue{
/* 队列 */
BiTree front; //队首指针
BiTree back; //队尾指针
/* 可自由添加需要用的变量 */
}Queue,*pQueue;
Queue *InitQueue(){
/* 初始化队列 */
Queue* que = (Queue *)malloc(sizeof(Queue));//申请空间
assert(que);//判断是否申请成功
que->back=NULL;
que->front=que->back;
return que;
}
int isEmpty(Queue *que){
/* 判断队列是否为空 */
if(que->back==NULL)
{
return 0;//为空
}
else
{
return 1;//不为空
}
}
BiTree EnQueue(pQueue que,BiTree n){
/* 入队 */
if(que->back==NULL)//队列为空的情况下进行入队
{
que->back=n;
que->front=n;
return que->back;
}
else//队列不为空的情况下进行入队
{
que->back->next=n;
que->back=n;
return que->back;
}
}
BiTree DeQueue(Queue *que){
/* 出队 */
BiTree p;
p=que->front;
if(que->back==que->front)//队列只剩一个结点的情况下
{
que->back=NULL;
que->front=que->back;
return p;
}
else//队列还有大于等于二个的结点
{
que->front=que->front->next;
return p;
}
}
BiTree createBiTree()//建立二叉树
{
char e;
scanf("%c",&e);//输入数据
getchar();
if(e=='#')//判断是否有后续结点
return NULL;
else
{
BiTree n=(BiTree)malloc(sizeof(TreeNode));//申请空间
n->lchild=NULL;
n->rchild=NULL;
n->ch=e;
printf("Please enter the left child of %c\n",e);
n->lchild=createBiTree();//创建左儿子
printf("Please enter the right child of %c\n",e);
n->rchild=createBiTree();//创建右儿子
return n;
}
}
void preOrderTraverse(BiTree p)//前序遍历
{
if(p==NULL)//判断是否遍历到底结点
return;
else
{
printf("%c",p->ch);
preOrderTraverse(p->lchild);//遍历左子树
preOrderTraverse(p->rchild);//遍历右子树
}
}
void inOrderTraverse(BiTree p)//中序遍历
{
if(p->lchild!=NULL)//判断是否存在左儿子
{
inOrderTraverse(p->lchild);//向左儿子走一步
}
printf("%c",p->ch);
if(p->rchild!=NULL)//判断是否存在右儿子
{
inOrderTraverse(p->rchild);
return;
}
else if(p->rchild==NULL)
{
return;
}
}
void postOrderTraverse(BiTree p)//后序遍历
{
if(p->lchild!=NULL)//判断是否存在左儿子
{
postOrderTraverse(p->lchild);//左走一步
}
if(p->rchild!=NULL)//判断是否存在右儿子
{
postOrderTraverse(p->rchild);//右走一步
}
printf("%c",p->ch);
return;
}
BiTree* BinaryTreeFromOrderings(char inorder[], char preorder[],int inorder_index,int preorder_index, int length)
{
//函数功能:根据前序与中序序列构造二叉树,并返回根节点
//参数说明:inorder:中序序列字符数组,preorder:前序序列字符数组,inorder_index:记录中序序列索引,preorder_index:记录前序序列索引,length:序列长度
int i,j,k,l,m,n,i1,j1;
int x,y;
char e1;
char pr1[100],pr2[100];
char in1[100],in2[100];
memset(pr2,0,100);
memset(pr1,0,100);
memset(in1,0,100);
memset(in2,0,100);
BiTree n2,bt1,bt2;
e1=preorder[0];
for(i=0;i<strlen(inorder);i++)
{
if(inorder[i]==e1)//寻找中序排列中与前序序列第一个一样的数据
{
x=i;
break;
}
}
n2=(BiTree)malloc(sizeof(TreeNode));
n2->lchild=NULL;
n2->rchild=NULL;
n2->ch=e1;//建立根节点
for(j=0;j<x;j++)
{
in1[j]=inorder[j];//复制中序排列中根结点左边的数据
}
y=x+1;
for(k=1,n=0;k<x+1;n++,k++)
{
pr1[n]=preorder[k];//复制先序排列中根结点左边的数据
}
if(x!=0)//如果根节点左边存在数据,则将当前根结点的左儿子指向该数据的根结点
{
n2->lchild=BinaryTreeFromOrderings(in1,pr1,0,0,strlen(pr1));
}
for(l=y,m=0;l<strlen(inorder);m++,l++)//复制中序排列中根结点右子树的数据
{
in2[m]=inorder[l];
}
for(i1=0,j1=y;j1<strlen(inorder);i1++,j1++)//复制前序排列中根结点右子树的数据
{
pr2[i1]=preorder[j1];
}
if(m!=0)//如果根节点右边存在数据,则将当前根结点的右儿子指向该数据的根结点
{
n2->rchild=BinaryTreeFromOrderings(in2,pr2,0,0,strlen(pr2));
}
return n2;
}
int isSymmetrical(BiTree root)
{
//判断以root为根节点的二叉树是否是镜像对称的
int left1=0,right1=0;
int left2=0,right2=0;
BiTree root1,root2;
pQueue que;
que=InitQueue();//初始化队列
que->back=EnQueue(que,root);
root=DeQueue(que);
if(root->lchild!=NULL)//左儿子不空则标记
{
left1=1;
}
if(root->rchild!=NULL)//右儿子不空则标记
{
right1=1;
}
if(left1!=0&&right1!=0)//判断该结点左右是否相等都有儿子
{
left1=0;//清空
right1=0;//清空
que->back=EnQueue(que,root->lchild);
que->back=EnQueue(que,root->rchild);
while(isEmpty(que))//使用两个对称结点,判断是否对称,当队列为空时,退出循环
{
root1=DeQueue(que);
root2=DeQueue(que);
if(root1->lchild!=NULL)
{
left1=1;
}
if(root2->rchild!=NULL)
{
right2=1;
}
if((left1==1)&&(right2==1))
{
que->back=EnQueue(que,root1->lchild);
que->back=EnQueue(que,root2->rchild);
}
if(left1!=right2)
{
return 0;
}
if(root1->rchild!=NULL)
{
right1=1;
}
if(root2->lchild!=NULL)
{
left2=1;
}
if((right1==1)&&(left2==1))//两个结点是否镜像对称
{
que->back=EnQueue(que,root1->rchild);
que->back=EnQueue(que,root2->lchild);
}
if(right1!=left2)
{
return 0;
}
left1=0;
left2=0;
right1=0;
right2=0;
}
if(isEmpty(que)==0)//队列为空,返回1
{
return 1;
}
}
else if(right1==0&&left1==0)//只有根结点时
{
return 1;
}
else
{
return 0;
}
}
void postOrderTraversePlus1(BiTree p)//后续遍历PLus
{
if(p->lchild!=NULL)
{
postOrderTraversePlus1(p->lchild);
}
if(p->rchild!=NULL)
{
postOrderTraversePlus1(p->rchild);
}
a[i0]=p->ch;//存入数组
i0++;
return;
}
void postOrderTraversePlus2(BiTree p)//RLT遍历
{
if(p->rchild!=NULL)
{
postOrderTraversePlus2(p->rchild);
}
if(p->lchild!=NULL)
{
postOrderTraversePlus2(p->lchild);
}
b[j0]=p->ch;//存入数组
j0++;
return;
}
int isSymmetricalPlus(BiTree root)//判断二叉树的数据和结构是否镜像对称
{
int i;
postOrderTraversePlus1(root);//LRT遍历
postOrderTraversePlus2(root);//RLT遍历
for(i=0;i<strlen(a);i++)//判断遍历结果是否一样
{
if(a[i]!=b[i])
break;
}
if(i==strlen(a))//全部相等
{
return 1;
}
else
{
return 0;
}
}
void task1()
{
printf("start task (1) Create Tree in PreOrder\n\n");
BiTree bt;
bt=createBiTree();//创建树
if(bt==NULL)//如果为空树就结束
{
return;
}
printf("preOrderTraverse\n");
preOrderTraverse(bt);
printf("\n\n");
printf("inOrderTraverse\n");
inOrderTraverse(bt);
printf("\n\n");
printf("postOrderTraverse\n");
postOrderTraverse(bt);
printf("\n");
printf("whether the tree is symmetrical?\n\n");
if((isSymmetricalPlus(bt)==1&&isSymmetrical(bt)==1))//判断是否结构对称
{
printf("It's data&&structure mirror symmetrical\n\n");
}
else
{
printf("It's not data&&structure mirror symmetrical\n\n");
}
}
void task2_3(){
int i,j,n;
printf("start task (2) Input the preOrder and inOrder Sequence ,Then build the tree\n");
char pr[100];
char in[100];
memset(pr,0,100);
memset(in,0,100);
BiTree bt;
printf("Please input the number of elem\n");
scanf("%d",&n);
getchar();
printf("please input the preorder seqence\n");
for(i=0;i<n;i++)
{
scanf("%c",&pr[i]);
getchar();
}
printf("please input the inorder seqence\n");
for(j=0;j<n;j++)
{
scanf("%c",&in[j]);
getchar();
}
if(strlen(pr)!=0)
{
bt=BinaryTreeFromOrderings(in, pr,0,0,strlen(pr));
printf("\n");
printf("preOrderTraverse\n");
preOrderTraverse(bt);
printf("\n\n");
printf("inOrderTraverse\n");
inOrderTraverse(bt);
printf("\n\n");
printf("postOrderTraverse\n");
postOrderTraverse(bt);
printf("\n\n");
}
printf("start task (3):whether the tree is symmetrical?\n\n");
if(strlen(pr)==0||isSymmetrical(bt)==1)//判断是否结构对称
{
printf("It's structure mirror symmetrical\n\n");
}
else
{
printf("It's not structure mirror symmetrical\n\n");
}
if(strlen(pr)==0||(isSymmetricalPlus(bt)==1&&isSymmetrical(bt)==1))//判断是否数据和结构对称
{
printf("It's data&&structure mirror symmetrical\n\n");
}
else
{
printf("It's not data&&structure mirror symmetrical\n\n");
}
}
int main()
{
memset(a,0,100);
memset(b,0,100);
task1();
printf("\n\n");
task2_3();
return 0;
}