数据结构(五)——树和二叉树之二叉树遍历、先序和中序构建二叉树、二叉树的的结构对称判断

代码中所用到的结构体定义

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值