- 题目:建立以左右孩子链接结构表示的二叉树,实现二叉树的先序、中序、后序的递归和非递归方式遍历,分层遍历、统计树的高度。
- 树结点
struct node{
char ch;
struct node *lson, *rson;
};
- 栈结点
struct Stack{
struct node *loc;
struct Stack *next;
};
- 二叉树建立的函数
二叉树的建立在逻辑上是按照先根顺序建立的,但是输入数据的时候是一对一对输入,根结点在主函数中输入,然后在函数中一次性输入其左右儿子,若都不为空,则递归调用这个函数,继续输入这个左儿子的左右儿子,右结点也是一样,若是输入‘#’则表示这个结点结束了没有数据,在程序中不占内存,在上一个结点的后序中是NULL。
void InputMyTree(struct node *root, FILE *fp)//二叉树的输入
{ char lef, rig;
struct node *index = root;
printf("Please input your lson and rson\n");
scanf("%c%c", &lef, &rig);
getchar();
printf("%c%c\n", lef, rig);
fprintf(fp , "%c%c", lef, rig);
if(lef == '#') {
root->lson = NULL; }
else {
//NodesNumber+=1;
root->lson = (struct node *)malloc(sizeof(struct node));
root = root->lson;
root->ch = lef;
InputMyTree(root, fp); }
if(rig == '#') {
index->rson = NULL; }
else {
//NodesNumber+=1;
index->rson = (struct node *)malloc(sizeof(struct node));
index = index->rson;
index->ch = rig;
InputMyTree(index, fp); }
}
- 递归式先序遍历二叉树的函数
递归式先序遍历,得到根结点后访问,然后递归调用这个函数本身,先遍历根的左儿子,若其不为空则访问结点的数据,然后继续调用这个函数,若空则遍历右儿子,若右儿子不为空则访问结点的数据,空则结束函数。
代码:
void RootFirst1(struct node *root, FILE *fp) //先序遍历:递归
{
if(root == NULL) {
return;
}
fprintf(fp, "%c", root->ch);
printf("%c\n", root->ch);
RootFirst1(root->lson, fp);
RootFirst1(root->rson, fp);
}
- 中序遍历二叉树的函数
与先序遍历类似,先遍历左儿子,然后输出根结点,然后遍历右儿子,用的是递归调用函数本身的方法。
void RootSecond1(struct node *root, FILE *fp)//中序遍历:递归
{
if(root->lson != NULL) {
RootSecond1(root->lson, fp);
}
fprintf(fp, "%c", root->ch);
if(root->rson != NULL) {
RootSecond1(root->rson, fp);
}
}
- 递归式后序遍历二叉树
与递归先序遍历类似,只不过是先遍历左右儿子然后访问根结点。
void RootThird1(struct node *root, FILE *fp) //后序遍历:递归
{ if(root->lson != NULL) {
RootThird1(root->lson, fp); }
if(root->rson != NULL) {
RootThird1(root->rson, fp); }
fprintf(fp, "%c", root->ch);
}
- 非递归先序遍历二叉树的函数
非递归先序遍历二叉树用到了栈,定义了一个搜索指针P,在一个while()循环中将用p沿着左儿子的方向从根结点向下搜索,并且将沿途的结点都入栈(包括根结点),顺便进行访问,直到p指向NULL,while()循环结束,再出栈,将栈顶元素给p,然后将p的右儿子,赋值给p,重复以上步骤,便相当于遍历了右儿子,若右儿子为空则while()循环不进行,会直接退栈,向入栈的反方向遍历右儿子。
void RootFirst2(struct node *root, FILE *fp) //先序遍历:非递归
{
struct Stack *phead = NULL;
struct node *p = root;
do {
while(p != NULL) {
phead = insert(phead, p);
fprintf(fp, "%c", p->ch);//打印根结点数据
p = p->lson;
}
if(phead != NULL) {
p = phead->loc;
phead = phead->next;//退栈
p = p->rson;//遍历右儿子
}
} while(p != NULL || phead != NULL);//判断p=nil AND 栈空
}
- 非递归中序遍历二叉树的函数
与非递归先序遍历二叉树非常相似,只是改变了访问结点的时机,因为是先遍历左儿子再遍历右儿子的顺序,所以访问节点数据的时机只在出栈的时候,在第一个while()循环结束时,首先将左儿子的数据(当时是栈顶)访问,然后退栈,遍历右儿子,重复,找到一个没有左右儿子的结点的时候,访问结点然后退栈,因为右儿子为空,所以会再次退栈访问根,然后再次判断右儿子,访问根,这样,直到搜索指针和栈都为空,整个循环结束,函数也结束。
void RootSecond2(struct node *root, FILE *fp)//中序遍历:非递归
{ struct Stack *phead = NULL;
struct node *p = root;
do {
while(p != NULL) {
phead = insert(phead, p);
p = p->lson;
}
if(phead != NULL) {
fprintf(fp, "%c" , phead->loc->ch);//访问栈顶元素
p = phead->loc;
phead = phead->next;//退栈
p = p->rson;//回到do_while开头遍历右儿子
}
} while(p != NULL || phead != NULL);//判断p=nil AND 栈空
}
- 非递归后序遍历二叉树
非递归后序遍历比前两个非递归的复杂,因为要先访问左右儿子,所以,在搜索指针指到二叉树叶子的下一个,即NULL的时候,要退栈访问左儿子,但是此时不能直接再次遍历右儿子,而是要在遍历结束时加一个判断,若是当前结点右儿子为空或者右儿子已经遍历过,才能退栈。
代码:
void RootThird2(struct node *root, FILE *fp) //后序遍历:非递归
{ struct Stack *phead = NULL;
struct node *p = root, *temp, *index;
while(p != NULL || phead != NULL){
while(p != NULL) {
phead = insert(phead, p);
index = p;
p = p->lson;
}
if(phead != NULL) {
p = phead->loc;//栈顶给P
if(p->rson == NULL || temp == p->rson) {
///printf("Anode:%c\n", p->ch);
fprintf(fp, "%c", p->ch);
phead = phead->next;//退栈
temp = p;
p = NULL;
} else {
p = p->rson;//遍历右儿子
}
}
}
}
- 分层遍历二叉树
这个函数用到了队列,在循环开始前就将根结点入队,循环开始,将队列开头的结点给指针P,队首指针后移,访问P指向的数据,然后将P非空的左右儿子入队,结束本次循环,就相当于根节点下面的“一层”入队了,然后第二、三次循环,将第二层的数据访问,并且将第三层的结点入队……这样循环直到队列为空结束,就将二叉树分层遍历结束了。
void level(struct node *root, FILE *fp)//分层遍历
{
struct node *p = root;
struct Stack *lead = (struct Stack *)malloc(sizeof(struct Stack)),
*tail = (struct Stack *)malloc(sizeof(struct Stack));
lead->next = tail;
tail->loc = NULL;
tail->next = NULL;
//
lead->loc = root;
while(lead->loc != NULL) {
printf("Aqueue\n");
p = lead->loc;
fprintf(fp, "%c", p->ch);
if(p->lson != NULL) {
tail->loc = p->lson;//左儿子入队
tail->next = (struct Stack *)malloc(sizeof(struct Stack));
tail = tail->next;
tail->loc = NULL;
tail->next = NULL;
}
if(p->rson != NULL) {
tail->loc = p->rson;//右儿子入队
tail->next = (struct Stack *)malloc(sizeof(struct Stack));
tail = tail->next;
tail->loc = NULL;
tail->next = NULL;
}
lead = lead->next;//出队
}
}