二叉树递归非递归遍历.docx

上传人:b****5 文档编号:8231969 上传时间:2023-01-30 格式:DOCX 页数:42 大小:270.70KB
下载 相关 举报
二叉树递归非递归遍历.docx_第1页
第1页 / 共42页
二叉树递归非递归遍历.docx_第2页
第2页 / 共42页
二叉树递归非递归遍历.docx_第3页
第3页 / 共42页
二叉树递归非递归遍历.docx_第4页
第4页 / 共42页
二叉树递归非递归遍历.docx_第5页
第5页 / 共42页
点击查看更多>>
下载资源
资源描述

二叉树递归非递归遍历.docx

《二叉树递归非递归遍历.docx》由会员分享,可在线阅读,更多相关《二叉树递归非递归遍历.docx(42页珍藏版)》请在冰豆网上搜索。

二叉树递归非递归遍历.docx

二叉树递归非递归遍历

《数据结构》——算法设计

学号:

姓名:

专业班级:

成绩:

评语:

 

设计1:

二叉树遍历

设计要求:

1.根据二叉树遍历思想,分别实现先序遍历、中序遍历、后序遍历、层次遍历的算法

2.遍历算法可以尝试使用递归或非递归的方法实现。

若需要使用堆栈或队列,请直接使用C++自带的stack和queue对象。

设计分析

(说明自己实现了哪几个算法,对每个算法的设计思想做简单扼要的说明)

建立Tree类

类中的元素有

TreeNode*Root;//树的根节点

boolFind;//查找开关

boolFound;//判断是否找到指定编号的树叶

intpos;//结点数量

ElemType*data;//结点值的数组

算法1.先序遍历的递归实现

(只需要写出核心代码和运行结果,对代码和结果做分析说明)

算法代码:

voidTree:

:

PreOrder(TreeNode*t)//protected先序遍历输出树中所有的值

{

if(t)

{

cout<data;

PreOrder(t->LeftChild);

PreOrder(t->RightChild);

}//if

}//PreOrder

voidTree:

:

PreOrder(boolenter)//public先序遍历

{

PreOrder(Root);

if(enter)cout<

}//PreOrder

调用代码:

#defineElemTypeint

intmain()

{

ElemTypedata[9]={1,2,NULL,3,NULL,NULL,4,NULL,NULL};

TreeT1;

TreeNode*t;

T1.MakeNode(t,5,true,NULL);

T1.InitTree(data,9);//根据data和数组长度为9建立二叉树

T1.insertLeftChild(5,t);//在编号为5的树结点的左孩子插入数字5

T1.MakeNode(t,6,true,NULL);

T1.insertRightChild(5,t);//在编号为5的树结点的右孩子插入数字6

T1.MakeNode(t,9,true,NULL);

T1.insertLeftChild(10,t);//在编号为10的树结点的左孩子插入数字9

T1.PreOrder(true);

return0;

}

代码分析:

代码的访问顺序:

访问1,输出1;

访问2,输出2;

访问NULL(2的左孩子);

访问3,输出3;

访问5,输出5;

访问9,输出9;

访问NULL(9的左孩子);

访问NULL(9的右孩子);

访问NULL(5的右孩子);

访问6,输出6;

访问NULL(6的左孩子),访问NULL(6的右孩子);

访问4,输出4;

访问NULL(4的左孩子),访问NULL(4的右孩子);

输出1235964

运行结果:

 

算法2.先序遍历的非递归实现

算法代码:

voidTree:

:

Non_Recursive_PreOrder(TreeNode*T)//protected非递归先序遍历

{

/*——————————————————————————

首先进行p的输出。

存储的内容基本上是右结点。

遍历左边缘不断输出,然后转到右结点入栈,继续

左边缘不断输出。

等到再无左边缘的时候逆向输出

所有右孩子。

———————————————————————————*/

stacks;

TreeNode*p=T,*q;

s.push(p);//把Root推入栈内

while(!

s.empty())//如果s不空

{

cout<data;

q=p->RightChild;

if(q)s.push(q);//如果q(p的右孩子)不空则将q推入栈

p=p->LeftChild;

if(!

p)//如果p(p的左孩子)为空则回到(p的右孩子)

{

p=s.top();

s.pop();

}//if

}//while

}//Non_recursive_PreOrder

StatusTree:

:

Non_Recursive_PreOrder(boolenter)//非递归先序遍历

{

Non_Recursive_PreOrder(Root);

if(enter)cout<

returnOK;

}//Non_recursive_PreOrder

调用代码:

intmain()

{

ElemTypedata[9]={1,2,NULL,3,NULL,NULL,4,NULL,NULL};

TreeT1;

TreeNode*t;

T1.MakeNode(t,5,true,NULL);

T1.InitTree(data,9);//根据data和数组长度为9建立二叉树

T1.insertLeftChild(5,t);//在编号为5的树结点的左孩子插入数字5

T1.MakeNode(t,6,true,NULL);

T1.insertRightChild(5,t);//在编号为5的树结点的右孩子插入数字6

T1.MakeNode(t,9,true,NULL);

T1.insertLeftChild(10,t);//在编号为10的树结点的左孩子插入数字9

T1.Non_Recursive_PreOrder(true);

return0;

}

代码分析:

不断遍历左孩子,如果有右孩子就入栈。

遍历到NULL的时候就读取栈首元素(即最近的一个右结点)。

然后重复以上过程。

访问1,输出1,4入栈;

访问2.输出2,3入栈;

访问NULL,3出栈;

访问3,输出3,6入栈;

访问5,输出5;

访问9;输出9;

访问NULL,6出栈;

访问6,输出6;

访问NULL,4出栈;

访问4,输出4;

运行结果:

算法3中序遍历的递归实现

算法代码:

voidTree:

:

InOrder(boolenter)//public中序遍历

{

InOrder(Root);

if(enter)cout<

}//InOrder

voidTree:

:

InOrder(TreeNode*t)//protected中序遍历输出树中所有的值

{

if(t)

{

InOrder(t->LeftChild);

cout<data;

InOrder(t->RightChild);

}//if

}//InOrder

调用代码:

intmain()

{

ElemTypedata[9]={1,2,NULL,3,NULL,NULL,4,NULL,NULL};

TreeT1;

TreeNode*t;

T1.MakeNode(t,5,true,NULL);

T1.InitTree(data,9);//根据data和数组长度为9建立二叉树

T1.insertLeftChild(5,t);//在编号为5的树结点的左孩子插入数字5

T1.MakeNode(t,6,true,NULL);

T1.insertRightChild(5,t);//在编号为5的树结点的右孩子插入数字6

T1.MakeNode(t,9,true,NULL);

T1.insertLeftChild(10,t);//在编号为10的树结点的左孩子插入数字9

T1.InOrder(true);

return0;

}

代码分析:

访问1;

访问2,输出2;

访问3;访问5;

访问9,输出9;

访问5,输出5;

访问3,输出3;

访问6,输出6;

访问1,输出1;

访问4,输出4;

运行结果:

算法4中序遍历的非递归实现

算法代码:

StatusTree:

:

Non_Recursive_IndexOrder(boolenter)//非递归中序遍历

{

Non_Recursive_IndexOrder(Root);

if(enter)cout<

returnOK;

}//Non_recursive_IndexOrder

voidTree:

:

Non_Recursive_IndexOrder(TreeNode*T)//protected非递归中序遍历

{

/*————————————————————————————

首先不断遍历左边缘但不输出只入栈,

直到碰到NULL后(此时p=NULL)返回父结点输出父结点。

然后转到右结点入栈,继续遍历左边缘不输出

只入栈。

一直遍历到某个度为0的右结点的右孩子的时候

结束一支分支的遍历。

另一支分支的遍历相同。

这一支分支的遍历

结束后中序遍历结束。

—————————————————————————————*/

stacks;

TreeNode*p=T;

s.push(NULL);

while

(1)

{

while(p)

{

s.push(p);//栈是回溯法的主要工具

p=p->LeftChild;

}//while遍历左边缘直到NULL

if(!

s.top())break;//如果栈到达栈底则跳出

p=s.top();//p=NULL的时候返回其父结点或爷结点

s.pop();//弹出父结点

cout<data;//输出父结点

p=p->RightChild;//调用父结点的右孩子

}//while

}//Non_recursive_IndexOrder

调用代码:

intmain()

{

ElemTypedata[9]={1,2,NULL,3,NULL,NULL,4,NULL,NULL};

TreeT1;

TreeNode*t;

T1.MakeNode(t,5,true,NULL);

T1.InitTree(data,9);//根据data和数组长度为9建立二叉树

T1.insertLeftChild(5,t);//在编号为5的树结点的左孩子插入数字5

T1.MakeNode(t,6,true,NULL);

T1.insertRightChild(5,t);//在编号为5的树结点的右孩子插入数字6

T1.MakeNode(t,9,true,NULL);

T1.insertLeftChild(10,t);//在编号为10的树结点的左孩子插入数字9

T1.Non_Recursive_IndexOrder(true);

return0;

}

代码分析:

入栈,访问左孩子,入栈,访问左孩子。

重复进行,一直到访问NULL。

获得父节点(即栈首元素),并输出值,然后访问右结点,如果有,则重复以上过程。

如果为NULL,则再次出栈输出值,继续访问右结点。

访问1,入栈;

访问2,入栈;

访问NULL(2的左孩子),2出栈,输出2;

访问3,入栈;

访问5,入栈;

访问9,入栈;

访问NULL(9的左孩子),9出栈,输出9;

访问NULL(9的右孩子),5出栈,输出5;

访问NULL(5的右孩子),3出栈,输出3;

访问6,入栈;

访问NULL(6的左孩子),6出栈,输出6;

访问NULL(6的右孩子),1出栈,输出1;

访问4,入栈;

访问NULL(4的左孩子),4出栈。

输出4;

访问NULL(4的右孩子),栈空,跳出循环;

运行结果:

算法5后序遍历的递归实现

算法代码:

voidTree:

:

PostOrder(boolenter)//public后序遍历

{

PostOrder(Root);

if(enter)cout<

}//PostOrder

voidTree:

:

PostOrder(TreeNode*t)//protected后序遍历输出树中所有的值

{

if(t)

{

PostOrder(t->LeftChild);

PostOrder(t->RightChild);

cout<data;

}//if

}//PostOrder

调用代码:

intmain()

{

ElemTypedata[9]={1,2,NULL,3,NULL,NULL,4,NULL,NULL};

TreeT1;

TreeNode*t;

T1.MakeNode(t,5,true,NULL);

T1.InitTree(data,9);//根据data和数组长度为9建立二叉树

T1.insertLeftChild(5,t);//在编号为5的树结点的左孩子插入数字5

T1.MakeNode(t,6,true,NULL);

T1.insertRightChild(5,t);//在编号为5的树结点的右孩子插入数字6

T1.MakeNode(t,9,true,NULL);

T1.insertLeftChild(10,t);//在编号为10的树结点的左孩子插入数字9

T1.PostOrder(true);

return0;

}

代码分析:

访问1;

访问2;

访问NULL(2的左孩子);

访问3;

访问5;

访问9;

访问NULL(9的左孩子),访问NULL(9的右孩子),输出9;

访问5,访问NULL(5的右孩子),输出5;

访问3,访问6,访问NULL(6的左孩子),访问NULL(6的右孩子),输出6;访问3,输出3;

访问2,输出2;

访问1,访问4,访问NULL(4的左孩子),访问NULL(4的右孩子),输出4;

访问1,输出1;

运行结果:

 

算法6后序遍历的非递归实现

算法代码:

StatusTree:

:

Non_Recursive_PostOrder(boolenter)//非递归后序遍历

{

Non_Recursive_PostOrder(Root);

if(enter)cout<

returnOK;

}//Non_Recursive_PostOrder

voidTree:

:

Non_Recursive_PostOrder(TreeNode*T)//protected非递归后序遍历

{

/*——————————————————————————

先进行左边缘遍历,入栈,并记载访问次数为1(tag=0)。

直到p=NULL,然后返回父结点,父结点访问次数为2(tag=1)。

p转到父结点的右孩子。

重复以上步骤。

如果栈顶结点被第三次访问,则输出该结点,弹出。

———————————————————————————*/

stacks;//用于存储树结点

stacks1;//用于存储结点暂离状态

TreeNode*p=T;

s.push(NULL);//没有此句函数直接结束

while

(1)//如果s不空

{

while(p)

{

s.push(p);

s1.push(false);

p=p->LeftChild;

}//while用于存储左边缘树结点,全部暂离

if(s1.top())

{

p=s.top();

s1.pop();

s.pop();

cout<data;

p=NULL;

}//if第二次访问结点结点已待命,将结点和状态全部弹出,输出结点。

令p=NULL,避免第四次读取结点。

else

{

s1.pop();

s1.push(true);

p=s.top()->RightChild;

}//else如果结点是暂离,让其准备,当第二次碰见它时就输出。

此时访问右孩子

if(!

s.top())break;//如果栈到达栈底则跳出

}//while

}//Non_recursive_PostOrder

调用代码:

intmain()

{

ElemTypedata[9]={1,2,NULL,3,NULL,NULL,4,NULL,NULL};

TreeT1;

TreeNode*t;

T1.MakeNode(t,5,true,NULL);

T1.InitTree(data,9);//根据data和数组长度为9建立二叉树

T1.insertLeftChild(5,t);//在编号为5的树结点的左孩子插入数字5

T1.MakeNode(t,6,true,NULL);

T1.insertRightChild(5,t);//在编号为5的树结点的右孩子插入数字6

T1.MakeNode(t,9,true,NULL);

T1.insertLeftChild(10,t);//在编号为10的树结点的左孩子插入数字9

T1.Non_Recursive_PostOrder(true);

return0;

}

代码分析:

(第一次访问结点入栈状态为false,第二次访问结点将状态改成true,第三次访问结点输出结点数据,避免出现第四次访问结点。

(为什么是这样?

访问父节点的时候设置状态为false,访问左孩子回到父节点状态改成true,从右孩子回到父节点的时候输出父节点,共三次。

非递归后序遍历的步骤:

①定义两个栈,第一个栈类型为第二个栈类型为,以及树节点指针p,将NULLpush进栈。

②循环,如果p不为空,则(树节点栈)p入栈,(状态栈)false入栈,表示还没进行第二次访问。

然后不断遍历左孩子。

③如果状态栈首元素为true(此时为第三次访问树节点),获得栈首树节点然后输出数据,出栈。

  否则状态栈首元素为false(此时为第二次访问树节点),将状态改成false,然后访问其右孩子。

④如果到达栈底(NULL)就跳出无限循环。

①循环:

访问1,1入栈,false入栈;访问2,2入栈,false入栈;访问NULL,跳出循环;

由于栈首元素为false,false出栈,true入栈,然后访问2的右孩子;

②循环:

访问3,3入栈,false入栈;访问5,5入栈,false入栈;访问9,9入栈,false入栈;访问NULL,跳出循环。

由于栈首元素为false,false出栈,true入栈,然后访问9的右孩子

③循环:

NULL(9的右孩子),跳出循环

由于栈首元素为true,9出栈,true出栈,输出9,然后(TreeNode*)p赋值为NULL;

④循环:

p为NULL,跳出循环。

由于栈首元素是false,false换成true,访问5的右孩子;

⑤循环:

访问NULL(5的右孩子),跳出循环;

由于栈首元素是true,5出栈,true出栈,输出5,p=NULL;

⑥循环:

访问NULL,跳出循环;

由于栈首元素是false,false换成true,访问3的右孩子;

⑦循环:

访问6,6入栈,false入栈;访问NULL(6的左孩子),跳出循环;

由于栈首元素是false,false换成true,访问6的右孩子;

⑧循环:

访问NULL(6的右孩子),跳出循环;

由于栈首元素是true,6出栈,true出栈,输出6,p=NULL;

⑨循环:

NULL,跳出循环。

由于栈首元素是true,3出栈,true出栈,输出3,p=NULL;

⑩循环:

NULL,跳出循环。

由于栈首元素是true,2出栈,true出栈,输出2,p=NULL;

十一:

循环:

NULL,跳出循环;

false换成true;访问4

十二:

循环:

4入栈,false入栈;NULL(4的左孩子),跳出循环;

False换成true;访问NULL;

十三:

循环:

NULL,跳出循环;

4出栈,true出栈,输出4,p=NULL;

十四:

循环:

NULL,跳出循环;

1出栈,true出栈,输出1,p=NULL;

到达栈底,退出遍历。

运行结果:

算法7层次遍历

算法代码:

voidTree:

:

LevelOrder(TreeNode*t)//protected层次遍历

{

/*——————————————————

读取每一层的时候把下一层存进队列中。

———————————————————*/

TreeNode*p=t;

queueq;

do

{

if(p)

{

cout<data;

q.push(p->LeftChild);

q.push(p->RightChild);

}//if

p=q.front();

q.pop();

}//do

while(!

q.empty());

}//LevelOrder

voidTree:

:

LevelOrder(boolenter)//public层次遍历

{

LevelOrder(Root);

if(enter)cout<

}//LevelOrder

调用代码:

intmain()

{

ElemTypedata[9]={1,2,NULL,3,NULL,NULL,4,NULL,NULL};

TreeT1;

TreeNode*t;

T1.MakeNode(t,5,true,NULL);

T1.InitTree(data,9);//根据data和数组长度为9建立二叉树

T1.insertLeftChild(5,t);//在编号为5的树结点的左孩子插入数字5

T1.MakeNode(t,6,true,NULL);

T1.insertRightChild(5,t);//在编号为5的树结点的右孩子插入数字6

T1.MakeNode(t,9,true,NULL);

T1.insertLeftChild(10,t)//在编号为10的树结点的左孩子插入数字9

T1.LevelOrder(true);

return0;

}

代码分析:

运行结果:

 

完整代码:

#include

#include

#include

#include

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 演讲主持

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1