#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Stack>
#define maxn 100
using namespace std;
typedef struct BiNode
{
int data;
struct BiNode *lchild,*rchild;
}BiNode,*BiTree;
typedef struct
{
BiNode *stack[maxn]; // 存储树节点数组
int top; // 栈顶指针
}BStack,*Stack;
// 栈初始化
Stack InitStack()
{
Stack S;
S=(BStack*)malloc( sizeof (BStack));
if(S)
S->top=-1;
else
printf( "Init stack error!\n" );
return S;
}
int StackEmpty(Stack S) //判断栈是否为空
{
if(S->top==-1) //若为空,则返回
return 1;
else
return 0;
}
int StackFull(Stack S) //判断栈是否满
{
if (S->top==maxn-1) //栈满则返回
return 1;
else
return 0;
}
void Push(Stack &S,BiNode *e) //进栈操作,因为栈要发生变化,所以栈要用引用型
{
if (!(StackFull(S))) //进栈之前要判断栈是否满,若满,则不能进栈
{
S->stack[++S->top]=e;
}
else
return ;
}
BiNode* Pop(Stack &S) // 出栈操作,即弹出栈顶元素,用一个节点保存弹出的栈顶元素,作为返回值
{
BiNode *e;
if (!(StackEmpty(S))) // 出栈之前,要判断栈是否为空,若为空,则无效操作
{
e = S->stack[S->top--]; // 先挪出元素,再移动栈顶指针
return e;
}
else
return NULL;
}
BiNode* GetsTop(Stack S)
{
if (StackEmpty(S))
return NULL;
else
return S->stack[S->top];
}
void Free(Stack &S)
{
free(S);
}
BiTree Create(BiTree &T)
{
BiTree p = T;
int ch;
scanf("%d",&ch);
if(0 == ch )
{
p = NULL;
}
else
{
p = (BiNode *)malloc(sizeof(BiNode));
p->data = ch;
printf("%d'lchild is:\n",p->data);
p->lchild = Create(p->lchild);
printf("%d'rchild is:\n",p->data);
p->rchild = Create(p->rchild);
}
return p;
}
/* 堆栈压未访问的节点(右节点)*/
void Pre_order(BiTree T){
Stack s;
s = InitStack();
if(T){
Push(s,T); //压入根节点
BiTree p;
while(!StackEmpty(s)){ //总体条件循环栈不空
p = Pop(s); //弹出栈顶元素
while(p){ //循环条件取到的栈顶元素存在
printf("%d ",p->data); //先序遍历是先访问根节点,直接输出
if(p->rchild){ //访问根节点是否有右子树,将其入栈 。
Push(s,p->rchild);
}
p = p->lchild; //向左走
}
//左走到尽头,在尽头节点退一个栈,即访问当前节点的右子树。( p = Pop(s) )
}
}
}
/* 堆栈压未访问的节点(根节点)*/
void In_order(BiTree T){
Stack s;
s = InitStack();
if(T){
Push(s,T); //压入根节点
BiTree p;
while(!StackEmpty(s)){ //总体条件循环栈不空
while((p = GetsTop(s))&&p){
Push(s,p->lchild); //此处向左走到尽头将根节点压入 ,但压入了一个空的,
}
p = Pop(s); //弹出空的栈元素
if(p = Pop(s)){ //弹出空栈后的栈顶元素
printf("%d ",p->data);
Push(s,p->rchild); //不管右子树存不存在都压入,因为上步骤弹出空栈可直接处理。(p = Pop(s))
}
}
}
}
/* 对一个结点是否能访问,要看他的左、右子树是否遍历完,
所以每一个结点对应一个标志位 -tag 。tag=0 ,表示该结点暂不能访问; tag=1 ,表示该结点可以访问
其实是区分这次返回是遍历完左子树返回的还是遍历完右子树返回的,如果是左子树返回的那么就不能访问根结点,
如果是右子树返回的就能访问根结点。当搜索到某 P 结点时,先要遍历其左子树,因而将结点地址 P 及tag=0 进栈;
当P 结点的左子树遍历完之后,再遍历其右子树,又将地址 P 及tag=1 进栈;当 P结点右子树遍历完之后( tag=1 ),
便 可对 P结点进行访问 */
void Pos_Order(BiTree T){
Stack s;
s = InitStack();
int flag[maxn];
if(T){
while(s->top!=-1||T){
while(T) //类似左节点入栈
{
s->stack[++s->top] = T;
flag[s->top] = 0;
T = T->lchild;
}
while(s->top!=-1&&flag[s->top]==1){ //循环目的,访问完右节点后直接访问根节点
T = s->stack[s->top--];
printf("%d ",T->data);
}
if(s->top!=-1){
flag[s->top] = 1; //根节点也置flag = 1,上面while循环保证访问完右节点后直接访问根节点
T = s->stack[s->top];
T = T->rchild;
}
else break;
}
}
}
int main()
{
BiTree T;
printf("输入根节点,0输入表示空\n");
T = Create(T);
printf("非递归前序为:");
Pre_order(T);
printf("\n");
printf("非递归中序为:");
In_order(T);
printf("\n");
printf("非递归后序为:");
Pos_Order(T);
return 0;
}
二叉树的非递归实现前中后序遍历
最新推荐文章于 2023-11-03 20:06:50 发布