二叉树递归非递归遍历Word文档下载推荐.docx
- 文档编号:21368271
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:42
- 大小:270.70KB
二叉树递归非递归遍历Word文档下载推荐.docx
《二叉树递归非递归遍历Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《二叉树递归非递归遍历Word文档下载推荐.docx(42页珍藏版)》请在冰豆网上搜索。
PreOrder(TreeNode*t)//protected先序遍历输出树中所有的值
{
if(t)
{
cout<
<
t->
data;
PreOrder(t->
LeftChild);
RightChild);
}//if
}//PreOrder
voidTree:
PreOrder(boolenter)//public先序遍历
PreOrder(Root);
if(enter)cout<
endl;
调用代码:
#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.先序遍历的非递归实现
Non_Recursive_PreOrder(TreeNode*T)//protected非递归先序遍历
/*——————————————————————————
首先进行p的输出。
存储的内容基本上是右结点。
遍历左边缘不断输出,然后转到右结点入栈,继续
左边缘不断输出。
等到再无左边缘的时候逆向输出
所有右孩子。
———————————————————————————*/
stack<
TreeNode*>
s;
TreeNode*p=T,*q;
s.push(p);
//把Root推入栈内
while(!
s.empty())//如果s不空
p->
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);
returnOK;
//根据data和数组长度为9建立二叉树
//在编号为10的树结点的左孩子插入数字9
T1.Non_Recursive_PreOrder(true);
不断遍历左孩子,如果有右孩子就入栈。
遍历到NULL的时候就读取栈首元素(即最近的一个右结点)。
然后重复以上过程。
访问1,输出1,4入栈;
访问2.输出2,3入栈;
访问NULL,3出栈;
访问3,输出3,6入栈;
访问5,输出5;
访问9;
输出9;
访问NULL,6出栈;
访问NULL,4出栈;
访问4,输出4;
算法3中序遍历的递归实现
InOrder(boolenter)//public中序遍历
InOrder(Root);
}//InOrder
InOrder(TreeNode*t)//protected中序遍历输出树中所有的值
InOrder(t->
//在编号为5的树结点的右孩子插入数字6
T1.InOrder(true);
访问1;
访问3;
访问5;
算法4中序遍历的非递归实现
Non_Recursive_IndexOrder(boolenter)//非递归中序遍历
Non_Recursive_IndexOrder(Root);
}//Non_recursive_IndexOrder
Non_Recursive_IndexOrder(TreeNode*T)//protected非递归中序遍历
/*————————————————————————————
首先不断遍历左边缘但不输出只入栈,
直到碰到NULL后(此时p=NULL)返回父结点输出父结点。
然后转到右结点入栈,继续遍历左边缘不输出
只入栈。
一直遍历到某个度为0的右结点的右孩子的时候
结束一支分支的遍历。
另一支分支的遍历相同。
这一支分支的遍历
结束后中序遍历结束。
—————————————————————————————*/
TreeNode*p=T;
s.push(NULL);
while
(1)
while(p)
s.push(p);
//栈是回溯法的主要工具
p=p->
}//while遍历左边缘直到NULL
s.top())break;
//如果栈到达栈底则跳出
p=s.top();
//p=NULL的时候返回其父结点或爷结点
s.pop();
//弹出父结点
//输出父结点
//调用父结点的右孩子
//在编号为5的树结点的左孩子插入数字5
T1.Non_Recursive_IndexOrder(true);
入栈,访问左孩子,入栈,访问左孩子。
重复进行,一直到访问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后序遍历的递归实现
PostOrder(boolenter)//public后序遍历
PostOrder(Root);
}//PostOrder
PostOrder(TreeNode*t)//protected后序遍历输出树中所有的值
PostOrder(t->
T1.PostOrder(true);
访问2;
访问NULL(9的左孩子),访问NULL(9的右孩子),输出9;
访问5,访问NULL(5的右孩子),输出5;
访问3,访问6,访问NULL(6的左孩子),访问NULL(6的右孩子),输出6;
访问1,访问4,访问NULL(4的左孩子),访问NULL(4的右孩子),输出4;
算法6后序遍历的非递归实现
Non_Recursive_PostOrder(boolenter)//非递归后序遍历
Non_Recursive_PostOrder(Root);
}//Non_Recursive_PostOrder
Non_Recursive_PostOrder(TreeNode*T)//protected非递归后序遍历
先进行左边缘遍历,入栈,并记载访问次数为1(tag=0)。
直到p=NULL,然后返回父结点,父结点访问次数为2(tag=1)。
p转到父结点的右孩子。
重复以上步骤。
如果栈顶结点被第三次访问,则输出该结点,弹出。
//用于存储树结点
bool>
s1;
//用于存储结点暂离状态
//没有此句函数直接结束
while
(1)//如果s不空
s1.push(false);
}//while用于存储左边缘树结点,全部暂离
if(s1.top())
s1.pop();
cout<
p=NULL;
}//if第二次访问结点结点已待命,将结点和状态全部弹出,输出结点。
令p=NULL,避免第四次读取结点。
else
s1.push(true);
p=s.top()->
}//else如果结点是暂离,让其准备,当第二次碰见它时就输出。
此时访问右孩子
}//Non_recursive_PostOrder
T1.Non_Recursive_PostOrder(true);
(第一次访问结点入栈状态为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;
⑥循环:
由于栈首元素是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;
⑩循环:
由于栈首元素是true,2出栈,true出栈,输出2,p=NULL;
十一:
循环:
NULL,跳出循环;
false换成true;
访问4
十二:
4入栈,false入栈;
NULL(4的左孩子),跳出循环;
False换成true;
访问NULL;
十三:
4出栈,true出栈,输出4,p=NULL;
十四:
NULL,跳出循环;
1出栈,true出栈,输出1,p=NULL;
到达栈底,退出遍历。
算法7层次遍历
LevelOrder(TreeNode*t)//protected层次遍历
/*——————————————————
读取每一层的时候把下一层存进队列中。
———————————————————*/
TreeNode*p=t;
queue<
q;
do
if(p)
q.push(p->
p=q.front();
q.pop();
}//do
q.empty());
}//LevelOrder
LevelOrder(boolenter)//public层次遍历
LevelOrder(Root);
//根据data和数组长度为9建立二叉树
T1.insertLeftChild(10,t)//在编号为10的树结点的左孩子插入数字9
T1.LevelOrder(true);
完整代码:
#include<
iostream>
string>
stack>
qu
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 二叉 递归 遍历