c语言数据结构中树先序的递归遍历的可以在tc环境下调试出来源代码,C语言实现二叉树的递归遍历与非递归遍历...

本文实现了对二叉树的递归遍历和非递归遍历,固然还包括了一些栈操做。算法

二叉树的遍历本质上其实就是入栈出栈的问题,递归算法简单且容易理解,可是效率始终是个问题。非递归算法能够清楚的知道每步实现的细节,可是乍一看不想递归算法那么好理解,各有各的好处吧。接下来根据下图讲讲树的遍历。指针

03aba83d16263451ca62ddf862b79964.png

一、先序遍历:先序遍历是先输出根节点,再输出左子树,最后输出右子树。上图的先序遍历结果就是:ABCDEFcode

二、中序遍历:中序遍历是先输出左子树,再输出根节点,最后输出右子树。上图的中序遍历结果就是:CBDAEFblog

三、后序遍历:后序遍历是先输出左子树,再输出右子树,最后输出根节点。上图的后序遍历结果就是:CDBFEA递归

其中,后序遍历的非递归算法是最复杂的,我用了一个标识符isOut来代表是否须要弹出打印。由于只有当节点的左右子树都打印后该节点 才能弹出栈打印,因此标识isOut为1时打印,isOut初始值为0,这主要是为了处理非叶子节点。由后序遍历的原理决定,左右子树都被打印该节点才能打印,因此该节点确定会被访问2次,第一次的时候不要打印,第二次打印完右子树的时候打印。叶子节点打印完后将isOut置为1。(纯粹是本身想的,应该还有逻辑更简单的算法)内存

isOut处理具体以下:it

全部节点入栈的时候初始化为0;

叶子节点打印输出后将isOut置为1;

非叶子节点分两种状况。若是存在左子树,则输出左子树后将isOut置为1,此时指针已得到其右子树节点;若是不存在左子树,则将isOut置为1,此时指针已得到其右子树节点;在代码中分别体如今                                                                                                                                                                                                                                                     if ( (p->lchild) && (p->lchild->isOut == 1) )                                                                                                                                                                                                                            {//若是存在左子树,而且左子树已经遍历完,则说明该节点已经入栈,不用再次Push,直接走向右子树

p->isOut = 1;

p = p->rchild;

}和                                                                                                                                                                                                                                                                                                 if (!StackEmpty(s))

{

GetTop(s,p);

if ( p->lchild == NULL )

p->isOut = 1; //右子树已输出,将父节点isOut置1

};

遇到isOut=1的时候,说明左右子树都已输出,因此该节点也出栈打印出来。

以中序遍历为例,看看栈的内容是如何变化的:io

72d377b671bc1235573fa2ddc4f38fb8.png

具体的代码实现以下:class

#include

#include

#define STACKINITSIZE 100

#define STACKINCREASESIZE 20

typedef char ElemType;

//树结构

typedef struct tree

{

ElemType data;

struct tree * lchild;

struct tree * rchild;

unsigned int isOut;   //专为后序遍历设置的,0为不须要被输出,1为须要被输出

}TreeNode,*Tree;

//栈结构

typedef struct stack

{

Tree * base;

Tree * top;

int stacksize;

}Sqstack;

/*****************栈的操做声明********************/

//初始化栈

void InitStack( Sqstack &s );

//元素入栈

void Push( Sqstack &s, Tree e );

//得到栈顶元素

void GetTop( Sqstack s, Tree &e );

//弹出栈顶元素

void Pop( Sqstack &s, Tree &e );

//判断栈是否为空,为空返回1,不然返回0

int StackEmpty( Sqstack s );

/*****************栈的操做声明********************/

/*****************树的操做声明********************/

//建立树,以先序序列创建树

void CreateTree(Tree &t);

//递归先序遍历

void PreOrder(Tree t);

//非递归先序遍历

void PreOrder1(Tree t);

//递归中序遍历

void InOrder(Tree t);

//非递归中序遍历

void InOrder1(Tree t);

//递归后序遍历

void PostOrder(Tree t);

//非递归后序遍历

void PostOrder1(Tree t);

/*****************树的操做声明********************/

int main()

{

Tree T;

printf("\n按先序序列输入结点序列,'#'表明空:");

CreateTree(T);

printf("\n非递归先序遍历的结果:");

PreOrder1(T);

printf("\n递归先序遍历的结果:  ");

PreOrder(T);

printf("\n非递归中序遍历的结果:");

InOrder1(T);

printf("\n递归中序遍历的结果:  ");

InOrder(T);

printf("\n非递归后序遍历的结果:");

PostOrder1(T);

printf("\n递归后序遍历的结果:  ");

PostOrder(T);

printf("\n");

}

/*****************栈的操做定义********************/

//初始化栈

void InitStack( Sqstack &s )

{

s.base = (Tree *)malloc(STACKINITSIZE*sizeof(Tree));

if ( !s.base )

{

printf("InitStack内存分配出错\n");

}

s.top = s.base;

s.stacksize = STACKINITSIZE;

}

//元素入栈

void Push( Sqstack &s, Tree e )

{

if ( s.top - s.base >= s.stacksize )

{

s.base = (Tree *)realloc(s.base,(s.stacksize+STACKINCREASESIZE)*sizeof(Tree));

if ( !s.base )

{

printf("Push内存分配出错\n");

return ;

}

s.top = s.base + s.stacksize;

s.stacksize += STACKINCREASESIZE;

}

e->isOut = 0;

*s.top++ = e;

}

//得到栈顶元素

void GetTop( Sqstack s, Tree &e )

{

e = *(s.top - 1);

}

//弹出栈顶元素

void Pop( Sqstack &s, Tree &e )

{

if ( s.top == s.base )

{

printf("栈为空\n");

return ;

}

e = *(--s.top);

}

//判断栈是否为空,为空返回1,不然返回0

int StackEmpty( Sqstack s )

{

if ( s.top == s.base )

return 1;

return 0;

}

/*****************栈的操做定义********************/

/*****************树的操做定义********************/

//建立树,以先序序列创建树

void CreateTree(Tree &t)

{

char ch;

scanf("%c",&ch);

if ( ch == '#' )

t = NULL;

else

{

t = (Tree)malloc(sizeof(TreeNode));

if ( !t )

{

printf("分配内存出错!");

return ;

}

t->data = ch;

CreateTree(t->lchild);

CreateTree(t->rchild);

}

}

//递归先序遍历

void PreOrder(Tree t)

{

if ( t )

{

printf("%c",t->data);

PreOrder(t->lchild);

PreOrder(t->rchild);

}

}

//非递归先序遍历

void PreOrder1(Tree t)

{

Tree p = t;

Sqstack s;

InitStack(s);

while ( p || !StackEmpty(s) )

{

if ( p )

{

printf("%c",p->data);

Push(s,p);

p = p->lchild;

}

else

{

Pop(s,p);

p = p->rchild;

}

}

}

//递归中序遍历

void InOrder(Tree t)

{

if ( t )

{

InOrder(t->lchild);

printf("%c",t->data);

InOrder(t->rchild);

}

}

//非递归中序遍历

void InOrder1(Tree t)

{

Tree p = t;

Sqstack s;

InitStack(s);

while ( p || !StackEmpty(s) )

{

if ( p )

{

Push(s,p);

p = p->lchild;

}

else

{

Pop(s,p);

printf("%c",p->data);

p = p->rchild;

}

}

}

//递归后序遍历

void PostOrder(Tree t)

{

if ( t )

{

PostOrder(t->lchild);

PostOrder(t->rchild);

printf("%c",t->data);

}

}

//非递归后序遍历

void PostOrder1(Tree t)

{

t->isOut = 0;

Tree p = t;

Sqstack s;

InitStack(s);

while ( p || !StackEmpty(s) )

{

if ( p )

{

if ( p->isOut )

{//左右子树都已输出,则该节点也输出

Pop(s,p);

printf("%c",p->data);

if (!StackEmpty(s))

GetTop(s,p); //获得弹出节点元素的父节点

else

p = NULL;

}

else

{

if ( (p->lchild) && (p->lchild->isOut == 1) )

{//若是存在左子树,而且左子树已经遍历完,则说明该节点已经入栈,不用再次Push,直接走向右子树

p->isOut = 1;

p = p->rchild;

}

else

{

Push(s,p);

p = p->lchild;

}

}

}

else

{

if (!StackEmpty(s))

GetTop(s,p);

else

p = NULL;

if ( p->rchild )

{

p = p->rchild;

}

else

{

Pop(s,p);

printf("%c",p->data);

p->isOut = 1;

if (!StackEmpty(s))

{

GetTop(s,p);

if ( p->lchild == NULL )

p->isOut = 1; //右子树已输出,将父节点isOut置1

}

else

p = NULL;

}

}

}

}         运行结果以下:

9b3bf4287f9f0e14f300f16a93a87c98.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值