当前位置:首页 » 操作系统 » 二叉树的遍历非递归算法

二叉树的遍历非递归算法

发布时间: 2025-02-27 21:32:45

⑴ 非递归的二叉树前序遍历算法有什么用途

  1. 递归和非递归只是解决问题的方法的不同,本质还是一样的。

2. 递归算法相对于非递归算法来说效率通常都会更低

2.1 递归算法会有更多的资源需要压栈和出栈操作(不仅仅是参数,还有函数地址等)

2.2 由于编译器对附加的一些栈保护机制会导致递归执行的更加低效

3. 使用循环代替递归算法,通常可以获得更好的执行效率和空间效率,在二叉树层次较深的情况下,采用非递归方式遍历能够有效的提升遍历的性能。

⑵ 二叉树先序非递归遍历c语言算法

#include "stdio.h"
#include "stdlib.h"
#define STACK_INIT_SIZE 10 //栈的初始长度
#define STACKINCREMENT 5 //栈的追加长度

typedef struct bitree{
char data;
struct bitree *lchild,*rchild;
}bitree; //二叉树结点定义

typedef struct {
bitree **base;
bitree **top;
int stacksize;
}sqstack; // 链栈结点定则宽义top栈顶 base栈底 且栈元素是指向二叉树结点的二级指针
//建立一个空栈
int initstack(sqstack *s)
{s->base=(bitree *)malloc(STACK_INIT_SIZE*sizeof(bitree)); //栈底指向开辟空间
if(!s->base) exit(1); //抛出异常
s->top=s->base; //栈顶=栈尾 表示栈空
s->stacksize=STACK_INIT_SIZE; //栈长度为开辟空间大小
return 1;
}
//进栈
int push(sqstack *s,bitree *e)
{if(s->top-s->base>=s->stacksize) //如果栈满 追加开辟空间
{s->base=(bitree *)realloc (s->base,(s->stacksize+STACKINCREMENT)* sizeof(bitree));
if(!s->base) exit(1); //抛出异常
s->top=s->纯盯枯base+s->stacksize; //感觉这一句没用
s->stacksize+=STACKINCREMENT;}
*(s->top)=e;s->top++; //进栈 栈顶后移
return 1;
}
//出栈
int pop(sqstack *s,bitree **e)
{if(s->top==s->base) return 0; //栈空 返回0
--s->top;*e=*(s->top); //做洞栈顶前移 取出栈顶元素给e
return 1;}
//取栈顶
int gettop(sqstack *s,bitree **e) //去栈顶元素 注意top指向的是栈顶的后一个
{if(s->top==s->base) return 0; //所以 s->top-1
*e=*(s->top-1);
return 1;
}
/*------------------------非递归-----先序建立二叉树----------------------------------*/
bitree *createprebitree()
{char ch;bitree *ht,*p,*q;
sqstack *s;
s=malloc(sizeof(bitree)); //加上这一句为s 初始化开辟空间
ch=getchar();
if(ch!='#'&&ch!='\n') /* 输入二叉树先序顺序 是以完全二叉树的先序顺序
不是完全二叉树的把没有的结点以#表示 */
{ht=(bitree *)malloc(sizeof(bitree));
ht->data=ch;
ht->lchild=ht->rchild=NULL;
p=ht;
initstack(s);
push(s,ht); //根节点进栈
while((ch=getchar())!='\n') // 算
{if(ch!='#') {q=(bitree *)malloc(sizeof(bitree)); // 法
q->data=ch; //
if(p==*(s->top-1)) p->lchild=q; // 核
else p->rchild=q; //
push(s,q);p=q; // 心
} //
else {if(p==*(s->top-1)) p->lchild=NULL; // 的
else p->rchild=NULL; //
pop(s,&p);} // 步
//
} // 骤
return ht;
}
else return NULL;
}
/*--------------------------递归---------先序建立二叉树-------------------------------*/
void CreateBiTree(bitree **T) {
//按先序次序输入二叉树中的结点的值(一个字符),空格字符表示空树,
//构造二叉链表表示二叉树
char ch;
scanf("%c",&ch);
if(ch=='#') *T=NULL;
else{
*T=(bitree * )malloc(sizeof(bitree));
if(!*T) exit(1);
(*T)->data=ch; //生成根结点
CreateBiTree(&(*T)->lchild); //构造左子树
CreateBiTree(&(*T)->rchild); //构造右子树
}
}
/*--------------------------非递归-------中序建立二叉树-------------------------------*/
/*--------------------------递归---------中序建立二叉树-------------------------------*/
/*--------------------------非递归-------后序建立二叉树-------------------------------*/
/*--------------------------递归---------后序建立二叉树-------------------------------*/

/*-----------------------非递归------先序输出二叉树------------------------------*/
void preordertraverse(bitree *h)
{sqstack m;
initstack(&m);
while(h||m.base!=m.top)
{if(h) {push(&m,h);printf("%c",h->data);h=h->lchild;}
else{pop(&m,&h);
h=h->rchild;}
}
}
/*------------------------非递归-----中序输出二叉树----------------------------*/
void inordertraverse(bitree *h)
{sqstack m;
initstack(&m);
while(h||m.base!=m.top)
{if(h) {push(&m,h);h=h->lchild;}
else {
pop(&m,&h);
printf("%c",h->data);
h=h->rchild;
}
}
}
/*---------------------非递归----后序遍历二叉树----------------------------------*/
void postordertraverse(bitree *h)
{
sqstack m;
initstack(&m);
while(h||m.base!=m.top)
{if(h) {
push(&m,h);
h=h->lchild;}
else {
bitree *r; //使用r结点表示访问了右子树 代替标志域
gettop(&m,&h);
if(h->rchild&&h->rchild!=r)
{h=h->rchild;
push(&m,h);
h=h->lchild;}
else{pop(&m,&h);
printf("%c",h->data);
r=h;h=NULL;}
}
}
}
//层次遍历二叉树 用队列 哈哈以后做
/*-------------------------------主过程-------------------------------*/
int main()
{bitree *ht;
printf("先序非递归建立一个二叉树:");
if((ht=createprebitree())!=NULL) //非递归建立
//CreateBiTree(&ht);
//if(ht!=NULL) //递归建立
{
printf("先序遍历输出二叉树:");
preordertraverse(ht);
putchar('\n');
printf("中序遍历输出二叉树:");
inordertraverse(ht);
putchar('\n');
printf("后序遍历输出二叉树:");
postordertraverse(ht);
putchar('\n');
}
else printf("空二叉树\n");
}

⑶ 先序遍历二叉树的非递归算法

InitStack(S);//初始化栈
p=T;//取栈顶
while(P||!StackEmpty(S)){ //P存在或者栈非空
if(p) { //p非空,即左子树或者右子树存在
Push(S,p); //将左子树入栈
p=p->lchild; //取下一个左子树
}
else{
Pop(S,p); //出栈,相当于先序遍历了,因为左子树都TMD入栈了,现在反向输出
p=p->rchild; //弹出一个左子树,就同时取其右子树右子树,然后又跳到这个if的最开头那里,p存在的那个分支。接下来再取右子树的左子树
}
}

//其实,用递归也许你更能理解一些。但是,递归本质上也是压栈,只不过是程序压栈,还不如这个效率高

⑷ 二叉树前序遍历法举例!急急急!!!

二叉树的三种金典遍历法

1.前序遍历法:

前序遍历(DLR)

前序遍历(DLR)

前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树。

若二叉树为空则结束返回,否则:

(1)访问根结点

(2)前序遍历左子树

(3)前序遍历右子树

注意的是:遍历左右子树时仍然采用前序遍历方法。

如上图所示二叉树

前序遍历,也叫先根遍历,遍历的顺序是,根,左子树,右子树

遍历结果:ABDECF

中序遍历,也叫中根遍历,顺序是左子树,根,右子树

遍历结果:DBEAFC

后序遍历,也叫后根遍历,遍历顺序,左子树,右子树,根

遍历结果:DEBFCA

2.中序遍历法:

中序遍历

中序遍历(LDR)

中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。在遍历左、右子树时,仍然先遍历左子树,再访问根结点,最后遍历右子树。即:

若二叉树为空则结束返回,否则:

(1)中序遍历左子树

(2)访问根结点

(3)中序遍历右子树。

注意的是:遍历左右子树时仍然采用中序遍历方法。

3.后序遍历法:

后序遍历

简介

后序遍历是二叉树遍历的一种。后序遍历指在访问根结点、遍历左子树与遍历右子树三者中,首先遍历左子树,然后遍历右子树,最后遍历访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。后序遍历有递归算法和非递归算法两种。

递归算法

算法描述:

(1)若二叉树为空,结束

(2)后序遍历左子树

(3)后序遍历右子树

(4)访问根结点

伪代码

PROCEDUREPOSTRAV(BT)

IFBT<>0THEN

{

POSTRAV(L(BT))

POSTRAV(R(BT))

OUTPUTV(BT)

}

RETURN

c语言描述

structbtnode

{

intd;

structbtnode*lchild;

structbtnode*rchild;

};

voidpostrav(structbtnode*bt)

{

if(bt!=NULL)

{

postrav(bt->lchild);

postrav(bt->rchild);

printf("%d",bt->d);

}

}

非递归算法

算法1(c语言描述):

voidpostrav1(structbtnode*bt)

{

structbtnode*p;

struct

{

structbtnode*pt;

inttag;

}st[MaxSize];

}

inttop=-1;

top++;

st[top].pt=bt;

st[top].tag=1;

while(top>-1)/*栈不为空*/

{

if(st[top].tag==1)/*不能直接访问的情况*/

{

p=st[top].pt;

top--;

if(p!=NULL)

{

top++;/*根结点*/

st[top].pt=p;

st[top].tag=0;

top++;/*右孩子结点*/

st[top].pt=p->p->rchild;

st[top].tag=1;

top++;/*左孩子结点*/

st[top].pt=p->lchild;

st[top].tag=1;

}

}

if(st[top].tag==0)/*直接访问的情况*/

{

printf("%d",st[top].pt->d);

top--;

}

}

}

算法2:

voidpostrav2(structbtnode*bt)

{

structbtnode*st[MaxSize],*p;

intflag,top=-1;

if(bt!=NULL)

{

do

{

while(bt!=NULL)

{

top++;

st[top]=bt;

bt=bt->lchild;

}

p=NULL;

flag=1;

while(top!=-1&&flag)

{

bt=st[top];

if(bt->rchild==p)

{

printf("%d",bt->d);

top--;

p=bt;

}

else

{

bt=bt->rchild;

flag=0;

}

}

}while(top!=-1)

printf(" ");

}

}

老曹回答必属佳作记得给分谢谢合作!

⑸ 数据结构的中序遍历二叉树的结点的非递归算法


如图

⑹ 如何不用递归遍历二叉树

非递归的方法是用存储代替计算,就是在建立树时,实现了存储展开,相当于存储了未来需要遍历的路径,所以就快了。递归是送快递,一层层往下递,非递归是先建好区域仓库,由各地仓库储存发货,所以速度更快,但需要仓库储存(内存占用更多)。
二叉树遍历在数据结构中用得多,这种算法是从kb时代的内存来的,主要用于理解概念,提升编程时的思想用。
实际用途中
如果用于商业一般用数据库代替,根本用不到二叉树,是用存储代替计算。速度快,可以用内存数据库,如我用h2 database的Memory Mode 在java下可以实现1秒1百万次插入。用sqlite内存模式代替以前在c++需要手工管理的数据结构。数据量大一个电脑存不下时,用hadoop/spark/redis,对分布式大数据支持比较好。
如果用于计算量大的任务或内核结构,可以用矩阵数组,链表,k/v这种比较直观模式存储。
对于树和图这种在内存中复杂的数据结构,尽量不要在生产环境下使用,容易内存泄露,用简单方式代替。对于图结构,可以使用图数据库,如neo4j。对于树结构,可以在数据库中存储一棵树。实际上数据库的存储多用树,如B树、B-树、B+树、B*树。
当然如果你写加密算法,这种要求极高的程序时,还是需要考虑性能最大化的,否则一般用存储代替遍历计算,因为内存和硬盘,现在很便宜了,而cpu还是一种宝贵的资源。

⑺ 二叉树的遍历非递归算法中应注意哪些问题

先序非递归算法
【思路】
假设:T是要遍历树的根指针,若T != NULL
对于非递归算法,引入栈模拟递归工作栈,初始时栈为空。
问题:如何用栈来保存信息,使得在先序遍历过左子树后,能利用栈顶信息获取T的右子树的根指针?
方法1:访问T->data后,将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应扮谈弯为T,出栈,再先序遍历T的右子树。
方法2:访问T->data后,将T->rchild入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T->rchild,出栈,遍历以该指针为根的子树。
【算法1】
void PreOrder(BiTree T, Status ( *Visit ) (ElemType e))

{ // 基于方法一,流程图如右,当型循环
InitStack(S);
while ( T!=NULL || !StackEmpty(S)){
while ( T != NULL ){
Visit(T->data) ;
Push(S,T);
T = T->lchild;
}

if( !StackEmpty(S) ){
Pop(S,T);
T = T->rchild;
}
}
}
【算法2】
void PreOrder(BiTree T, Status ( *Visit ) (ElemType e))

{ // 基于方法二,流程图如右,当型循环
InitStack(S);

while ( T!=NULL || !StackEmpty(S) ){
while ( T != NULL ){
Visit(T->data);
Push(S, T->rchild);
T = T->lchild;
}
if ( !StackEmpty(S) ){
Pop(S,T);
}
}
}
进一步考虑:对于处理流程中的循环体的直到型、当型+直到型的实现。
中序非递归算法
【思路】
T是要遍历树的根指针,中序遍历要求厅闷在遍历完左子树后,访问根,再遍历右子树。
问题:如何用栈来保存信息,使得在中序遍历过左子树后,能利用栈顶信息获取T指针?
方法:先将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,出栈,访问T->data,再中序遍历T的右子树。

【算法】
void InOrder(BiTree T, Status ( *Visit ) (ElemType e))
{ // 流程图如右,当型循环
InitStack(S);

while ( T!=NULL || !StackEmpty(S) ){
while ( T != NULL ){
Push(S,T);
T = T->lchild;
}
if( !StackEmpty(S) ){
Pop(S, T);
Visit(T->data);
T = T->rchild;
}
}
}
进一步考虑:对于处理流程中的循环体的直到型、当型+直到型的实现。
后序非递归算法
【思路】

T是要遍历树的根指针,后序遍历要求在遍历完左右子树后,再访问根。需要判断根结点的左右子树是否均遍历过。
可采用标记法侍升,结点入栈时,配一个标志tag一同入栈(0:遍历左子树前的现场保护,1:遍历右子树前的现场保护)。
首先将T和tag(为0)入栈,遍历左子树;返回后,修改栈顶tag为1,遍历右子树;最后访问根结点。
typedef struct stackElement{
Bitree data;
char tag;
}stackElemType;
【算法】
void PostOrder(BiTree T, Status ( *Visit ) (ElemType e))
{ // 流程图如右,当型循环
InitStack(S);
while ( T!=NULL || !StackEmpty(S) ){
while ( T != NULL ){
Push(S,T,0);
T = T->lchild;
}

while ( !StackEmpty(S) && GetTopTag(S)==1){
Pop(S, T);
Visit(T->data);
}
if ( !StackEmpty(S) ){
SetTopTag(S, 1); // 设置栈顶标记
T = GetTopPointer(S); // 取栈顶保存的指针
T = T->rchild;
}else break;
}
}

热点内容
java输入回车 发布:2025-02-28 00:02:39 浏览:103
荣耀手机怎么切换安卓系统 发布:2025-02-28 00:02:05 浏览:835
如何增加手机运行内存和配置 发布:2025-02-27 23:52:51 浏览:989
邮政网银密码怎么改 发布:2025-02-27 23:51:17 浏览:897
安卓系统空间满了怎么办 发布:2025-02-27 23:46:12 浏览:364
发短信改qq密码怎么发 发布:2025-02-27 23:45:20 浏览:80
战神引擎搭建服务器 发布:2025-02-27 23:45:17 浏览:697
二联压缩机 发布:2025-02-27 23:43:04 浏览:391
库卡脚本 发布:2025-02-27 23:24:15 浏览:659
hl编程 发布:2025-02-27 23:23:31 浏览:662