1、二叉树递归非递归遍历数据结构算法设计学号:姓名: 专业班级: 成绩:评语:设计1:二叉树遍历设计要求:1. 根据二叉树遍历思想,分别实现先序遍历、中序遍历、后序遍历、层次遍历的算法2. 遍历算法可以尝试使用递归或非递归的方法实现。若需要使用堆栈或队列,请直接使用C+自带的stack和queue对象。设计分析(说明自己实现了哪几个算法,对每个算法的设计思想做简单扼要的说明)建立Tree类类中的元素有TreeNode *Root;/树的根节点bool Find;/查找开关bool Found;/判断是否找到指定编号的树叶int pos;/结点数量ElemType *data;/结点值的数组算法1.
2、先序遍历的递归实现(只需要写出核心代码和运行结果,对代码和结果做分析说明)算法代码:void Tree:PreOrder(TreeNode *t)/protected先序遍历输出树中所有的值 if(t) coutdata; PreOrder(t-LeftChild); PreOrder(t-RightChild); /if /PreOrder void Tree:PreOrder(bool enter)/public先序遍历 PreOrder(Root); if(enter)coutendl; /PreOrder调用代码:#define ElemType intint main() ElemT
3、ype data9=1,2,NULL,3,NULL,NULL,4,NULL,NULL; Tree T1; 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
4、(10,t); /在编号为10的树结点的左孩子插入数字9 T1.PreOrder(true); return 0;代码分析:代码的访问顺序:访问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.先序遍历的非递归实现算法代码:void Tree:Non_Recursive_PreOr
5、der(TreeNode*T) /protected非递归先序遍历 /* 首先进行p的输出。存储的内容基本上是右结点。 遍历左边缘不断输出,然后转到右结点入栈,继续 左边缘不断输出。等到再无左边缘的时候逆向输出 所有右孩子。 */ stack s; TreeNode *p=T,*q; s.push(p);/把Root推入栈内 while(!s.empty()/如果s不空 coutdata; q=p-RightChild; if(q)s.push(q); /如果q(p的右孩子)不空则将q推入栈 p=p-LeftChild; if(!p) /如果p(p的左孩子)为空则回到(p的右孩子) p=s.t
6、op(); s.pop(); /if /while /Non_recursive_PreOrder Status Tree:Non_Recursive_PreOrder(bool enter)/非递归先序遍历 Non_Recursive_PreOrder(Root); if(enter)coutendl; return OK; /Non_recursive_PreOrder调用代码:int main() ElemType data9=1,2,NULL,3,NULL,NULL,4,NULL,NULL; Tree T1; TreeNode *t; T1.MakeNode(t,5,true,NULL
7、); 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); return 0;代码分析:不断遍历左孩子,如果有右孩子就
8、入栈。遍历到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 中序遍历的递归实现算法代码:void Tree:InOrder(bool enter)/public中序遍历 InOrder(Root); if(enter)coutLeftChild); coutdata; InOrder(t-RightChild); /if /InOrder调
9、用代码:int main() ElemType data9=1,2,NULL,3,NULL,NULL,4,NULL,NULL; Tree T1; 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)
10、; T1.insertLeftChild(10,t); /在编号为10的树结点的左孩子插入数字9 T1.InOrder(true); return 0;代码分析:访问1;访问2,输出2;访问3;访问5;访问9,输出9;访问5,输出5;访问3,输出3;访问6,输出6;访问1,输出1;访问4,输出4;运行结果:算法4 中序遍历的非递归实现算法代码: Status Tree:Non_Recursive_IndexOrder(bool enter)/非递归中序遍历 Non_Recursive_IndexOrder(Root); if(enter)coutendl; return OK; /Non_re
11、cursive_IndexOrder void Tree:Non_Recursive_IndexOrder(TreeNode*T) /protected非递归中序遍历 /* 首先不断遍历左边缘但不输出只入栈, 直到碰到NULL后(此时p=NULL)返回父结点输出父结点。 然后转到右结点入栈,继续遍历左边缘不输出 只入栈。一直遍历到某个度为0的右结点的右孩子的时候 结束一支分支的遍历。 另一支分支的遍历相同。这一支分支的遍历 结束后中序遍历结束。 */ stack s; TreeNode *p=T; s.push(NULL); while(1) while(p) s.push(p); /栈是回溯
12、法的主要工具 p=p-LeftChild; /while 遍历左边缘直到NULL if(!s.top()break;/如果栈到达栈底则跳出 p=s.top();/p=NULL的时候返回其父结点或爷结点 s.pop();/弹出父结点 coutdata;/输出父结点 p=p-RightChild;/调用父结点的右孩子 /while /Non_recursive_IndexOrder调用代码:int main() ElemType data9=1,2,NULL,3,NULL,NULL,4,NULL,NULL; Tree T1; TreeNode *t; T1.MakeNode(t,5,true,NU
13、LL); 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); return 0;代码分析:入栈,访问左孩子,入栈
14、,访问左孩子。重复进行,一直到访问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的右孩子
15、),栈空,跳出循环;运行结果:算法5 后序遍历的递归实现算法代码: void Tree:PostOrder(bool enter)/public后序遍历 PostOrder(Root); if(enter)coutLeftChild); PostOrder(t-RightChild); coutdata; /if /PostOrder调用代码:int main() ElemType data9=1,2,NULL,3,NULL,NULL,4,NULL,NULL; Tree T1; TreeNode *t; T1.MakeNode(t,5,true,NULL); T1.InitTree(data,
16、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); return 0;代码分析:访问1;访问2;访问NULL(2的左孩子);访问3;访问5;访问9;访问NULL(9的左孩子),
17、访问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 后序遍历的非递归实现算法代码: Status Tree:Non_Recursive_PostOrder(bool enter)/非递归后序遍历 Non_Recursive_PostOrder(Root); if(enter)coutendl; return OK; /Non_Recursive
18、_PostOrdervoid Tree:Non_Recursive_PostOrder(TreeNode*T) /protected非递归后序遍历 /* 先进行左边缘遍历,入栈,并记载访问次数为1(tag=0)。 直到p=NULL,然后返回父结点,父结点访问次数为2(tag=1)。 p转到父结点的右孩子。 重复以上步骤。 如果栈顶结点被第三次访问,则输出该结点,弹出。 */ stack s;/用于存储树结点 stacks1;/用于存储结点暂离状态 TreeNode *p=T; s.push(NULL);/没有此句函数直接结束 while(1)/如果s不空 while(p) s.push(p);
19、 s1.push(false); p=p-LeftChild; /while 用于存储左边缘树结点,全部暂离 if(s1.top() p=s.top(); s1.pop(); s.pop(); coutdata; p=NULL; /if 第二次访问结点结点已待命,将结点和状态全部弹出,输出结点。令p=NULL,避免第四次读取结点。 else s1.pop(); s1.push(true); p=s.top()-RightChild; /else 如果结点是暂离,让其准备,当第二次碰见它时就输出。此时访问右孩子 if(!s.top()break;/如果栈到达栈底则跳出 /while /Non_r
20、ecursive_PostOrder调用代码:int main() ElemType data9=1,2,NULL,3,NULL,NULL,4,NULL,NULL; Tree T1; 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.Make
21、Node(t,9,true,NULL); T1.insertLeftChild(10,t); /在编号为10的树结点的左孩子插入数字9 T1.Non_Recursive_PostOrder(true); return 0;代码分析:(第一次访问结点入栈状态为false,第二次访问结点将状态改成true,第三次访问结点输出结点数据,避免出现第四次访问结点。)(为什么是这样?访问父节点的时候设置状态为false,访问左孩子回到父节点状态改成true,从右孩子回到父节点的时候输出父节点,共三次。)非递归后序遍历的步骤:定义两个栈,第一个栈类型为 第二个栈类型为,以及树节点指针p,将NULL push
22、进栈。循环,如果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入栈
23、,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入栈;
24、访问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,
25、跳出循环;4出栈,true出栈,输出4,p=NULL;十四:循环:NULL,跳出循环;1出栈,true出栈,输出1,p=NULL;到达栈底,退出遍历。运行结果:算法7 层次遍历算法代码:void Tree:LevelOrder(TreeNode *t)/protected层次遍历 /* 读取每一层的时候把下一层存进队列中。 */ TreeNode *p=t; queueq; do if(p) coutdata; q.push(p-LeftChild); q.push(p-RightChild); /if p=q.front(); q.pop(); /do while(!q.empty(); /
26、LevelOrdervoid Tree:LevelOrder(bool enter)/public层次遍历 LevelOrder(Root); if(enter)coutendl; /LevelOrder调用代码:int main() ElemType data9=1,2,NULL,3,NULL,NULL,4,NULL,NULL; Tree T1; 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); return 0;代码分析:运行结果:完整代码:#include#include#include#includequ
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1