递归非递归的二叉树遍历(递归前中后,非递归前中后,层次遍历,凹入打印法等)
2016-05-30 21:28
393 查看
由于所有的递归算法都可以借助于堆栈转换成循环结构的非递归算法。方法一:形式化模拟转换。方法二:根据要求解问题的特点设计借助于堆栈的循环结构算法。而此次正好是利用第二种按方法求解。
堆栈结构体如下:
(1)初始化设置一个堆栈。
(2)把根结点指针入栈。
(3)当堆栈非空,循环执行步骤①到步骤③:
①出栈取得一个结点指针,访问该结点;
②若该结点的右子树非空,则将该结点的右子树指针入栈;
③若该结点的左子树非空,则将该结点的左子树指针入栈;
若二叉树为空,则算法结束;否则:
①访问根结点;
②先序遍历根结点的左子树;
③先序遍历根结点的右子树
堆栈结构体如下:
(1)初始化设置一个堆栈。
(2)把根结点指针入栈。
(3)当堆栈非空或则指针t非空,循环执行步骤①到步骤③:
①若指针t非空,则将t入栈,一直遍历其左孩子;
②若堆栈非空,则弹出栈顶元素并访问,并指向其右孩子;
若二叉树为空,则算法结束;否则:
①中序遍历根结点的左子树;
②访问根结点;
③中序遍历根结点的右子树
由于后序遍历的算法叫其他的遍历难,所以一定得自己画图,边体会代码的运行过程
若二叉树为空,则算法结束;否则:
①后序遍历根结点的左子树;
②后序序遍历根结点的右子树;
③访问根结点
队列
堆栈
树的遍历等函数BiTreeTraverse.h
二叉树创建BiTree.h
【程序运行结果】
以上内容参考《数据结构——使用C语言(第五版)》,可能有些地方解释的不太清楚,欢迎指出
1.1非递归前序遍历:
首先利用下图来设计非递归前序遍历算法思想:堆栈结构体如下:
#define size 100 typedef struct { DataType data[size]; int tag[100]; //这个是在非递归后序中用到 int top ; }SeqStack ;
(1)初始化设置一个堆栈。
(2)把根结点指针入栈。
(3)当堆栈非空,循环执行步骤①到步骤③:
①出栈取得一个结点指针,访问该结点;
②若该结点的右子树非空,则将该结点的右子树指针入栈;
③若该结点的左子树非空,则将该结点的左子树指针入栈;
void preOrder2(BiTreeNode *root) { BiTreeNode *t; SeqStack S; //定义一个顺序堆栈 StackInitiate(S); StackPush(&S,root); while(StackNotEmpty(S)!=NULL) { SatckPop(&S,&t); //出栈访问 printf("%3c",t->data); if(root->rightChild!=NULL) //右孩子非空,右孩子入栈 { SatckPush(&S,root->rightChild); } if(root->leftChild!=NULL) //左孩子非空,左孩子入栈 { StackPush(&S,root->leftChild); } } }
1.2递归法前序遍历
递归法先序遍历思想:若二叉树为空,则算法结束;否则:
①访问根结点;
②先序遍历根结点的左子树;
③先序遍历根结点的右子树
void PreOrder(BiTreeNode *root) { if(root!=NULL) //二叉树非空 { printf("%c ",root->data); //访问根结点; PreOrder(root->leftChild); //先序遍历根结点的左子树 PreOrder(root->rightChild); //先序遍历根结点的右子树 } }
1.3层次遍历(与前序遍历基本相同,就是前序使用堆栈,层次遍历使用队列)
void LayOrder(BiTreeNode *root) //层次遍历 { BiTreeNode *d; SeqCQueue Q; QueueInitiate(&Q); QueueAppend(&Q,root); while(QueueNotEmpty(Q)) { QueueDelete(&Q,&d); printf("%3c",d->data); if(d->leftChild) QueueAppend(&Q,d->leftChild); if(d->rightChild) QueueAppend(&Q,d->rightChild); } }
2.1非递归法中序遍历
利用下图来设计非递归中序遍历算法思想:堆栈结构体如下:
#define size 100 typedef struct { DataType data[size]; int tag[100]; //这个是在非递归后序中用到 int top ; }SeqStack ;
(1)初始化设置一个堆栈。
(2)把根结点指针入栈。
(3)当堆栈非空或则指针t非空,循环执行步骤①到步骤③:
①若指针t非空,则将t入栈,一直遍历其左孩子;
②若堆栈非空,则弹出栈顶元素并访问,并指向其右孩子;
void InOrder(BiTreeNode *root) { BiTreeNode *t; SeqStack S; StackInitiate(&S); StackPush(&S,root); t=root->leftChld; while(StackNotEmpty(S)!=NULL||t!=NULL) //当堆栈非空或则指针t非空 { while(t!=NULL) { StackPush(&S,t); //t入栈 t=t->leftChild; //遍历其左孩子 } if(StackNotEmpty(S)) { StackPop(&S,&t); //弹出栈顶元素并访问,并指向其右孩子 printf("%c",t->data); t=t->rightChild; } } }
2.2二叉树的中序递归算法
递归法中序遍历思想:若二叉树为空,则算法结束;否则:
①中序遍历根结点的左子树;
②访问根结点;
③中序遍历根结点的右子树
void InOrder(BiTreeNode *root) { if(root!=NULL) //二叉树非空 { InOrder(root->leftChild); //先序遍历根结点的左子树 printf("%c",root->data); //访问根结点; InOrder(root->rightChild); //先序遍历根结点的右子树 } }
3.1二叉树的后序非递归遍历算法
后序遍历算法要明白的是,当访问结点的左子树是,该结点标志位0,之后获取(非弹出栈中的结点),访问其右子树,这是标志位为1.void PostOrder2(BiTreeNode *root) { SeqStack S; StackInitiate(&S); while((root!=NULL)||StackNotEmpty(S)) { while(root) { StackPush(&S,root); //访问结点的左子树时,tag为0 S.tag[S.top]=0; root=root->leftChild; } while((StackNotEmpty(S))&&(S.tag[S.top]==1)) { StackPop(&S,&root); printf("%3c",root->data); } if(StackNotEmpty(S)) { StackTop(S,&root); //获取栈顶元素 S.tag[S.top]=1; //tag为1 root= root->rightChild; } else root=NULL; } }
由于后序遍历的算法叫其他的遍历难,所以一定得自己画图,边体会代码的运行过程
3.2二叉树的递归后序
递归法后序遍历思想:若二叉树为空,则算法结束;否则:
①后序遍历根结点的左子树;
②后序序遍历根结点的右子树;
③访问根结点
void PostOrder(BiTreeNode *root) { if(root!=NULL) //二叉树非空 { InOrder(root->leftChild); //先序遍历根结点的左子树 InOrder(root->rightChild); //先序遍历根结点的右子树 printf("%c",root->data); //访问根结点; } }
4应用
main函数#include<stdlib.h> #include<stdio.h> typedef char DataType; #define MaxQueueSize 100 #define MaxStackSize 100 #include"BiTree.h" #include"Queue.h" #include"SeqStack.h" #include"BiTreeTraverse.h" void Visit(DataType item) //用来输出字符,就是个printf语句 { printf("%c ",item); } void PrintBiTree(BiTreeNode *root,int n) //打印二叉树,这里使用的是凹入表示法 { int i; if(root==NULL) return; PrintBiTree(root->rightChild,n+1); for(i=0;i<n-1;i++) printf(" "); if(n>0) { printf("---"); printf("%c\n",root->data); } PrintBiTree(root->leftChild,n+1); } BiTreeNode *Search(BiTreeNode *root,DataType x) //查找二叉树的某一个字符是否在该树种 { BiTreeNode *find=NULL; if(root!=NULL) { if(root->data==x) find=root; else { find=Search(root->leftChild,x); if(find==NULL) find=Search(root->rightChild,x); } } return find; } main() { BiTreeNode *root,*p,*find; char x='E'; Initiate(&root); p=InsertLeftNode(root,'A'); p=InsertLeftNode(p,'B'); p=InsertLeftNode(p,'D'); p=InsertRightNode(p,'G'); p=InsertRightNode(root->leftChild,'C'); InsertLeftNode(p,'E'); InsertRightNode(p,'F'); PrintBiTree(root,0); printf("前序遍历:"); PreOrder(root->leftChild,Visit); printf("\n中序遍历:"); InOrder(root->leftChild,Visit); printf("\n后序遍历:"); PostOrder(root->leftChild,Visit); printf("\n非递归前序遍历:"); PreOrder2(root->leftChild); printf("\n非递归中序遍历:"); InOrder2(root->leftChild); printf("\n非递归后序遍历:"); PostOrder2(root->leftChild); printf("\n层次遍历:"); LayOrder(root->leftChild); find=Search(root,x); if(find!=NULL) printf("\n数据元素%c在二叉树中\n",x); else printf("\n数据元素%c不在二叉树中\n",x); Destroy(&root); }
队列
typedef struct { BiTreeNode *queue[MaxQueueSize]; int rear; int front; int count; }SeqCQueue; void QueueInitiate(SeqCQueue *Q) { Q->rear=0; Q->front=0; Q->count=0; } int QueueNotEmpty(SeqCQueue Q) { if(Q.count!=0) return 1; else return 0; } int QueueAppend(SeqCQueue *Q,BiTreeNode *x) { if(Q->count>0&&Q->rear==Q->front) { printf("队列已满无法插入!\n"); return 0; } else { Q->queue[Q->rear]=x; Q->rear=(Q->rear+1)%MaxQueueSize; Q->count++; return 1; } } int QueueDelete(SeqCQueue *Q,BiTreeNode **d) { if(Q->count==0) { printf("队列已空无数据元素出队列!\n"); return 0; } else { *d=Q->queue[Q->front]; Q->front=(Q->front+1)%MaxQueueSize; Q->count--; return 1; } }
堆栈
typedef struct { BiTreeNode *stack[MaxStackSize]; int tag[100]; int top; //top表示顺序堆栈数组stack的当前栈顶位置 }SeqStack; void StackInitiate(SeqStack *S) { S->top=0; //初始化栈顶下标值 } int StackNotEmpty(SeqStack S) //判断顺序堆栈S是否为空,非空返回1,否则返回0 { if(S.top<=0)return 0; else return 1; } int StackPush(SeqStack *S,BiTreeNode *x)//把数据元素x存入顺序堆栈S中,入栈成功返回1,否则返回0 { if(S->top>=MaxStackSize) { printf("堆栈已满,无法插入!\n"); return 0; } else { S->stack[S->top]=x; S->top++; return 1; } } int StackPop(SeqStack *S,BiTreeNode **d) //取出顺序堆栈S的栈顶元素值由参数d带回,出栈成功则返回1,否则返回0 { if(S->top<=0) { printf("堆栈已空无数据元素出栈!\n"); return 0; } else { S->top--; //得注意top--,--top的差别 *d=S->stack[S->top]; return 1; } } int StackTop(SeqStack S,BiTreeNode **d) //取栈顶数据元素值由参数d带回,成功返回1,不成功返回0 { if(S.top<=0) { printf("堆栈已空!\n"); return 0; } else { *d=S.stack[S.top-1]; return 1; } }
树的遍历等函数BiTreeTraverse.h
void PreOrder(BiTreeNode *root,void visit(DataType item)) //递归前序遍历
{
if(root!=NULL)
{
visit(root->data);
PreOrder(root->leftChild,visit);
PreOrder(root->rightChild,visit);
}
}
void InOrder(BiTreeNode *root,void visit(DataType item)) //递归中序遍历
{
if(root!=NULL)
{
InOrder(root->leftChild,visit);
visit(root->data);
InOrder(root->rightChild,visit);
}
}
void PostOrder(BiTreeNode *root,void visit(DataType item)) //递归后序遍历
{
if(root!=NULL)
{
PostOrder(root->leftChild,visit);
PostOrder(root->rightChild,visit);
visit(root->data);
}
}
void InOrder2(BiTreeNode *root) //非递归中序遍历
{
BiTreeNode *t;
SeqStack S;
StackInitiate(&S);
StackPush(&S,root);
t=root->leftChild;
while(StackNotEmpty(S)||t!=NULL)
{
while(t!=NULL)
{
StackPush(&S,t);
t=t->leftChild;
}
if(StackNotEmpty(S))
{
StackPop(&S,&t);
printf("%3c",t->data);
t=t->rightChild;
}
}
}
void PreOrder2(BiTreeNode *root) //非递归中序遍历
{
BiTreeNode *t;
SeqStack S;
StackInitiate(&S);
StackPush(&S,root);
while(StackNotEmpty(S))
{
StackPop(&S,&t);
printf("%3c",t->data);
if(t->rightChild!=NULL)
{
StackPush(&S,t->rightChild);
}
if(t->leftChild!=NULL)
{
StackPush(&S,t->leftChild);
}
}
}
void PostOrder2(BiTreeNode *root) //非递归后序遍历
{
SeqStack S;
StackInitiate(&S);
while((root!=NULL)||StackNotEmpty(S))
{
while(root)
{
StackPush(&S,root);
S.tag[S.top]=0;
root=root->leftChild;
}
while((StackNotEmpty(S))&&(S.tag[S.top]==1))
{
StackPop(&S,&root);
printf("%3c",root->data);
}
if(StackNotEmpty(S))
{
StackTop(S,&root);
S.tag[S.top]=1;
root= root->rightChild;
}
else root=NULL;
}
}
void LayOrder(BiTreeNode *root) //层次遍历 { BiTreeNode *d; SeqCQueue Q; QueueInitiate(&Q); QueueAppend(&Q,root); while(QueueNotEmpty(Q)) { QueueDelete(&Q,&d); printf("%3c",d->data); if(d->leftChild) QueueAppend(&Q,d->leftChild); if(d->rightChild) QueueAppend(&Q,d->rightChild); } }
二叉树创建BiTree.h
typedef struct Node //结构体的定义 { DataType data; struct Node *leftChild; struct Node *rightChild; } BiTreeNode; void Initiate(BiTreeNode **root) //初始化 { *root=(BiTreeNode *)malloc(sizeof(BiTreeNode)); (*root)->leftChild=NULL; (*root)->rightChild=NULL; } BiTreeNode *InsertLeftNode(BiTreeNode *curr,DataType x) //左插入结点 { BiTreeNode *s,*t; if(curr==NULL) return NULL; t=curr->leftChild; s=(BiTreeNode *)malloc(sizeof(BiTreeNode)); s->data=x; s->leftChild=t; s->rightChild=NULL; curr->leftChild=s; return curr->leftChild; } BiTreeNode *InsertRightNode(BiTreeNode *curr,DataType x) //右插入结点 { BiTreeNode *s,*t; if(curr==NULL) return NULL; t=curr->rightChild; s=(BiTreeNode *)malloc(sizeof(BiTreeNode)); s->data=x; s->rightChild=t; s->leftChild=NULL; curr->rightChild=s; return curr->rightChild; } void Destroy(BiTreeNode **root) //撤销二叉树 { if((*root)!=NULL&&(*root)->leftChild!=NULL) Destroy(&(*root)->leftChild); if((*root)!=NULL&&(*root)->rightChild!=NULL) Destroy(&(*root)->rightChild); free(*root); } BiTreeNode *DeleteLeftTree(BiTreeNode *curr) //左删除子树 { if(curr==NULL||curr->leftChild==NULL) return NULL; Destroy(&curr->leftChild); curr->leftChild=NULL; return curr; } BiTreeNode *DeleteRightTree(BiTreeNode *curr) //右删除子树 { if(curr==NULL||curr->rightChild==NULL) return NULL; Destroy(&curr->rightChild); curr->rightChild=NULL; return curr; }
【程序运行结果】
以上内容参考《数据结构——使用C语言(第五版)》,可能有些地方解释的不太清楚,欢迎指出
相关文章推荐
- 作业
- BZOJ1013 球形空间产生器sphere
- http
- CentOS7.1 Xshell 经常掉线 Connection closed by foreign host
- NestedScrollView的使用
- linux(centos)搭建SVN服务器
- 计算机图形学(二)输出图元_16_字符函数
- nodejs操作mongodb
- 对Framebuffer的操作
- F(k)<(维护+枚举)\(找规律+递推+枚举)>
- C语言的字符串输入输出
- VIJOS 1052贾老二算算术 (高斯消元)
- 正确使用iOS常量(const)、enum以及宏(#define)
- 存储过程和数据导入
- 工作踩得坑之二条件删除链表中的元素
- 51nod 平均数(二分+树状数组)
- jq 修改input 标签的值
- 第二节课作业 学生等级改为商铺登记 150206306
- matlab绘图之title函数
- db.properties文件配置备忘