二叉树以lson-rson链接方式存储,以菜单方式设计并完成功能任务:建立并存储树、输出前序遍历结果、输出中序遍历结果、输出后序遍历结果、交换左右子树、统计高度,其中对于中序、后序的遍历运算要求采用非递归方式。
建立二叉树采用先序的方法创建一个扩充二叉树。通过递归的方法,先创建一个根结点,然后再穿创建左子树,接着是创建右子树。
前序遍历,(1)采用递归方法 先访问根结点,在遍历左子树,最后遍历右子树。(2)采用非递归的方法,用一个搜索指针,来进行搜索,首先搜索指针p指向根结点,①(a)开始访问,访问完,(b)把p的右孩子入栈,(c)p指向p的左孩子。重复上述(a)(b)(c)三个动作直到p指向空指针。②判断栈是否为空,不为空,则出栈,把这个值赋值给p,,然后重复①②直到栈空并且p指向空。
中序遍历,(1)采用递归方法,和前序遍历相似,只不过访问根结点的顺序变了。先遍历左子树,再访问根结点,最后遍历右子树。(2)非递归的方法:这个方法也是和前序有些相似,可以参考前序的非递归来写,中序是要先遍历左子树,才访问根结点,最后遍历右子树。所以在遍历左子树的时候,先把根结点(包括子树的根结点)入栈,直到搜索指针指向空,再出栈,访问改结点,再把搜索指针指向该结点的右孩子。重复上述几个动作直到栈空并且搜索指针指向空。
后序遍历, (2)递归方法 ,先遍历左子树,后遍历右子树,再访问根结点。 (2)非递归方法:这个和前序、中序的非递归方法还是类似的,不过要多一个标记位,来标记该结点是否能够访问。该标志位可以通过一个标志数组或者在二叉树的结构体重表示,我采用标志数组来实现。首先搜索指针p指向根结点,开始一个大循环,循环的退出条件是p指向空并且栈空,①判断p是否指向空,如果不为空,一直重复一下三个动作,将p入栈,然后标志设为0,p指向p的左孩子。标志数组的下标是和该结点在栈中的次序是相对应的。当p指向空时,此时判断栈是否为空,其结点的标识位是否为1,如果满足这两个条件,就执行以下两个动作,出栈,访问该结点。接着判断栈是否为空,如果不是,栈顶元素的标志位设为1,搜索指针指向栈顶元素的右孩子。如果为空,则跳出整个大循环(ps:如果少了这一步,就会陷入死循环,因为后序遍历,根结点最先入栈,最后被访问,如果栈空了,说明整个树已经遍历结束了,需要退出循环)
交换左右子树,也是采用递归的方法。先将根结点的左右孩子进行交换,然后把左子树的左右孩子进行交换,最后再把右子树的左右孩子进行交换。
统计高度,用样也是递归的方法,先求左右子树的最高值,再加上一。
源程序如下:
#include <stdio.h>
#include <stdlib.h>
struct tree
{
int data;
struct tree *rson;
struct tree *lson;
};
struct stack
{
struct tree *h[30];
int i;
};
void menu(); //菜单函数
struct tree* create(); //建立一个二叉树
void preorder(struct tree *T); //先序遍历
void preorder1(struct tree *T); //递归先序
void preorder2(struct tree *T); //非递归先序
void inorder(struct tree *T); //中序遍历
void inorder1(struct tree *T); //递归中序
void inorder2(struct tree *T); //非递归中序
void postorder(struct tree *T); //后序遍历
void postorder1(struct tree *T); //递归后序
void postorder2(struct tree *T); //非递归后序
void exchange(struct tree *T); //交换左右子树
void height(struct tree*T); //统计高度
int high(struct tree *T);
void quit(); //退出函数
void push(struct stack *s,struct tree *p); //入栈
struct tree* pop(struct stack *s); //出栈
struct tree* gettop(struct stack s); //获取栈顶元素
int stackempty(struct stack s); //栈空判断
int main()
{
struct tree *T;
T=NULL;
int choice;
menu();
scanf("%d",&choice);
while(choice)
{
switch(choice)
{
case 1:printf("\n请输入(0代表空结点):");T=create();break;
case 2:if(T==NULL)
{
printf("\n二叉树为空,请先建立二叉树\n");
break;
}
preorder(T);break;
case 3:if(T==NULL)
{
printf("\n二叉树为空,请先建立二叉树\n");
break;
}
inorder(T);break;
case 4:if(T==NULL)
{
printf("\n二叉树为空,请先建立二叉树\n");
break;
}
postorder(T);break;
case 5:if(T==NULL)
{
printf("\n二叉树为空,请先建立二叉树\n");
break;
}
exchange(T);break;
case 6:if(T==NULL)
{
printf("\n二叉树为空,请先建立二叉树\n");
break;
}
height(T);break;
case 7:quit();break;
default:printf("输入无效,请重新输入:");
}
menu();
scanf("%d",&choice);
}
return 0;
}
void menu() //菜单函数
{
printf("********************************\n");
printf("* 1.建立二叉树 *\n");
printf("* 2.先序遍历二叉树 *\n");
printf("* 3.中序遍历二叉树 *\n");
printf("* 4.后序遍历二叉树 *\n");
printf("* 5.交换二叉树左右子树 *\n");
printf("* 6.二叉树的高度 *\n");
printf("* 7.退出 *\n");
printf("********************************\n\n");
}
struct tree* create() //建立一个二叉树
{
struct tree *p;
int d;
scanf("%d",&d);
if(d==0)
p=NULL;
else
{
p=(struct tree*)malloc(sizeof(struct tree));
p->data=d;
p->lson=create();
p->rson=create();
}
return p;
}
void preorder(struct tree *T) //先序遍历
{
printf("\n递归方法的结果:\n");
preorder1(T);
printf("\n非递归方法的结果:\n\n");
preorder2(T);
printf("\n\n");
}
void preorder1(struct tree *T) //递归先序
{
if(T!=NULL)
{
printf("%d ",T->data);
preorder1(T->lson);
preorder1(T->rson);
}
}
void preorder2(struct tree *T) //非递归先序
{
struct stack s;
s.i=-1;
struct tree*p=T;
while(p!=NULL||!stackempty(s))
{
while(p!=NULL)
{
printf("%d ",p->data);
push(&s,p->rson); //右子树入栈
p=p->lson;
}
if(!stackempty(s))
{
p=pop(&s);
}
}
}
void inorder(struct tree *T) //中序遍历
{
printf("\n递归方法的结果:\n");
inorder1(T);
printf("\n非递归方法的结果:\n\n");
inorder2(T);
printf("\n\n");
}
void inorder1(struct tree *T) //递归中序
{
if(T!=NULL)
{
inorder1(T->lson);
printf("%d ",T->data);
inorder1(T->rson);
}
}
void inorder2(struct tree *T) //非递归中序
{
struct stack s;
s.i=-1;
struct tree*p=T;
while(p!=NULL||!stackempty(s))
{
while(p!=NULL)
{
push(&s,p);
p=p->lson;
}
if(!stackempty(s))
{
p=pop(&s);
printf("%d ",p->data);
p=p->rson;
}
}
}
void postorder(struct tree *T) //后序遍历
{
printf("\n递归方法的结果:\n");
postorder1(T);
printf("\n非递归方法的结果:\n\n");
postorder2(T);
printf("\n\n");
}
void postorder1(struct tree *T) //递归后序
{
if(T!=NULL)
{
postorder1(T->lson);
postorder1(T->rson);
printf("%d ",T->data);
}
}
void postorder2(struct tree *T) //非递归后序
{
struct stack s;
s.i=-1;
struct tree*p=T;
int flag[30]={0};
while(p!=NULL||!stackempty(s))
{
while(p!=NULL)
{
push(&s,p);
flag[s.i]=0;
p=p->lson;
}
while(!stackempty(s)&&flag[s.i]==1)
{
p=pop(&s);
printf("%d ",p->data);
}
if(!stackempty(s))
{
flag[s.i]=1;
p=gettop(s);
p=p->rson;
}
else
break;
}
}
void exchange(struct tree *T) //交换左右子树
{
struct tree* temp;
if(T!=NULL)
{
temp=T->lson;
T->lson=T->rson;
T->rson=temp;
exchange(T->lson);
exchange(T->rson);
}
}
void height(struct tree*T) //统计高度
{
int h=0;
h=high(T);
printf("树的高度为:%d\n",h);
}
int high(struct tree *T)
{
int h;
if(T==NULL)
h=0;
else
{
h=high(T->lson)>high(T->rson)?high(T->lson):high(T->rson);
h+=1;
}
return h;
}
void quit()
{
printf("\n\n谢谢使用,再见\n\n");
exit(0);
}
void push(struct stack *s,struct tree *p) //入栈
{
s->i+=1;
s->h[s->i]=p;
}
struct tree* pop(struct stack *s) //出栈
{
s->i-=1;
return s->h[s->i+1];
}
int stackempty(struct stack s) //栈空判断
{
if(s.i>=0)
return 0;
return 1;
}
struct tree* gettop(struct stack s) //获取栈顶函数
{
return s.h[s.i];
}
总结:在建立二叉树是建立二叉扩充树,可以通过先序,中序,后序三种方法进行建立。前序、中序、后序的非递归方法中,由于是建立的二叉扩充树,所以每个结点都当作一个根结点来进行访问。树的定义是递归的,所以采用递归的方法对树进行运算也就比较容易了。