赞
踩
先序遍历:①访问当前结点,②遍历左子树,③遍历右子树
中序遍历:①遍历左子树,②访问当前结点,③遍历右子树
后序遍历:①遍历左子树,②遍历右子树,③访问当前结点
递归写法易懂,按照遍历原则递归即可,详见代码21~41行
非递归先序和中序遍历套路相似,后序遍历比较麻烦,因为先序和中序都是在右子树之前就输出了根结点,而后序必须记住根结点,等待右子树遍历完才能输出根结点。非递归遍历必须借助栈
初始p为根结点
非递归中序与先序的思路一致,只是输出时机不同。
初始p为根结点
非递归的先序和后序,在进入右子树之后,父结点就因出栈而丢弃了。而后序遍历必须记住父结点以便右子树访问结束后输出父结点。故不能再用先序或中序的思路。这里我写了3种方法。资料上常见的是方法1,但我觉得方法3最容易理解,最不易出错。
注意:①初始p为根结点。②用p==NULL标记为左子树已访问(不存在也视为已访问),③栈始终保存根结点root到当前结点p之间的所有结点
【方法1】
注意:
①初始p为根结点。
②用p==NULL标记为左子树已访问(不存在也视为已访问),
③栈始终保存根结点root到当前结点p之间的所有结点
④用last标记上一个输出的结点,若last是当前结点p的右子树,则表示右子树已访问
【方法2】
与方法1很相似,但省去了last指针。后序遍历重要性质:若p是右孩子,则下一个访问的一定是其父结点。
注意:
①初始p为根结点。
②用p==NULL标记为左子树已访问(不存在也视为已访问),
③栈始终保存根结点root到当前结点p之间的所有结点
【方法3】
该方法与前两种大有不同,但最容易理解并记住。
注意:last 记录上一个输出的结点。
代码中执行函数createTree()并输入ABD##E##C#FG##H##可以建立如下二叉树,
先序序列:ABDECFGH
中序序列:DBEACGFH
后序序列:DEBGHFCA
【代码】
- #include<stdio.h>
- #include<stdlib.h>
- struct node{
- char data;
- struct node *lchild,*rchild;
- };
-
- node* createTree() //先序建树,样例ABD##E##C#FG##H##
- {
- char ch=getchar();
- if(ch!='#'){
- node* p=(node*)malloc(sizeof(node));
- p->data = ch;
- p->lchild = createTree();
- p->rchild = createTree();
- return p;
- }
- return NULL;
- }
-
- void display_pre(node *rt) //递归先序
- {
- if(rt==NULL)return;
- putchar(rt->data);
- display_pre(rt->lchild);
- display_pre(rt->rchild);
- }
- void display_mid(node *rt) //递归中序
- {
- if(rt==NULL)return;
- display_mid(rt->lchild);
- putchar(rt->data);
- display_mid(rt->rchild);
- }
- void display_back(node *rt) //递归后序
- {
- if(rt==NULL)return;
- display_back(rt->lchild);
- display_back(rt->rchild);
- putchar(rt->data);
- }
-
- void display_pre_stack(node *rt) //非递归先序
- {
- node *p=rt,*st[100]; //st栈
- int top=0; //栈实时大小
- while(p||top>0){
- if(p){
- printf("%c",p->data);
- st[top++]=p;
- p=p->lchild;
- }else{
- p=st[--top];
- p=p->rchild;
- }
- }
- }
-
- void display_mid_stack(node *rt) //非递归中序
- {
- node *p=rt,*st[100]; //st栈
- int top=0; //栈实时大小
- while(p||top>0){
- if(p){
- st[top++]=p;
- p=p->lchild;
- }else{
- p=st[--top];
- printf("%c",p->data);
- p=p->rchild;
- }
- }
- }
-
- void display_back_stack1(node *rt) //非递归后序(方法1)
- {
- node *last=NULL, *p=rt, *st[100];
- int top=0; //栈元素数量
- while(p||top>0)
- {
- while(p) //p作为左子树还未访问
- {
- st[top++]=p;
- p=p->lchild;
- }
- p=st[top-1]; //此时p的左孩子已访问或不存在
- if(p->rchild && last != p->rchild)//p右孩子存在&&未访问
- {
- p=p->rchild;
- }
- else
- {
- printf("%c",p->data);
- top--; //出栈
- last=p;
- p=NULL; //p标记为NULL,告诉下一次循环别误入左孩子,因为已访问
- }
- }
- }
-
- void display_back_stack2(node *rt) //非递归后序(方法2)
- {
- node *p=rt, *st[100];
- int top=0;//栈元素数量
- while(p||top>0)
- {
- while(p) //直入最左孩子,若p为NULL,则左孩子已访问
- {
- st[top++]=p;
- p=p->lchild;
- }
- p=st[top-1]; //此p的左孩子已访问或不存在
- if(p->rchild) //有右则右
- {
- p=p->rchild;
- }
- else //无右则输出
- {
- printf("%c",p->data);
- top--;
- while(top>0 && st[top-1]->rchild == p) //若p是右孩子,则下一个输出的必为其父
- {
- p=st[--top]; //取其父,并输出
- printf("%c",p->data);
- }
- p=NULL; //标记为NULL,告诉下一次循环别进入左孩子了
- }
- }
- }
-
- void display_back_stack3(node *rt) //非递归后序(方法3)
- {
- node *last=NULL, *p, *st[100];
- int top=0; //栈元素数量
- st[top++]=rt;
- while(top>0)
- {
- p=st[top-1]; //取栈顶为p
- while(p->lchild && p->lchild!=last && p->rchild!=last) //p左子树存在&&未访问
- {
- p=p->lchild;
- st[top++]=p;
- }
- if(p->rchild && p->rchild!=last) //p右子树存在&&未访问
- {
- p=p->rchild;
- st[top++]=p;
- }
- else //左右均已访问,输出p
- {
- printf("%c",p->data);
- top--; //p出栈
- last=p;
- }
- }
- }
-
-
- int main() //测试
- {
- printf("建树:");
- node *root = createTree();
- display_pre(root); puts(" ----递归先序");
- display_mid(root); puts(" ----递归中序");
- display_back(root); puts(" ----递归后序\n");
-
- display_pre_stack(root); puts(" ----非递归先序");
- display_mid_stack(root); puts(" ----非递归中序");
- display_back_stack1(root); puts(" ----非递归后序(方法1)");
- display_back_stack2(root); puts(" ----非递归后序(方法2)");
- display_back_stack3(root); puts(" ----非递归后序(方法3)");
- }
【运行结果】
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。