数据结构与算法分析学习笔记(一)--二叉树的遍历(非递归)
题目来自《数据结构题集(C语言版)》,如下:
6.37 试利用栈的基本操作写出先序遍历(二叉树)的非递归算法.
----------------------------------------------------------
先序遍历,就是以结点,左子树,右子树的顺序遍历二叉树.观察并仿照其递归算法执行过程中的状态变化情况.因为是先序遍历,我们在将结点入栈前就可以访问它.如果它不是树叶,那么就优先将非空的左孩子入栈,否则入右孩子.而如果它是树叶,我们甚至不用将它入栈了.但我们要判断它是不是栈顶元素的左孩子并且这个栈顶元素还有个右孩子,如果是这样的话,我们就要访问这个右孩子,以保证不拉下每一个孩子:) 自己的算法如下:
2 {
3 if(!t)return;
4 InitStack(S);
5 do
6 {
7 visit(t);//访问t
8 if(!t->left&&!t->right)//树叶
9 {
10 while(!StackEmpty(S))//栈空时结束
11 {
12 if(GetTop(S,p)&&p->right&&p->right!=t)//树叶是栈顶元素的左孩子,栈顶元素有右孩子
13 {
14 t=p->right;
15 break;
16 }
17 Pop(S,t);//出栈,往树根攀登
18 }
19 }
20 else//不是树叶
21 {
22 Push(S,t);//入栈
23 t=(t->left)?t->left:t->right;//左孩子优先
24 }
25 }while(!StackEmpty(S));//栈空时结束
26 }
接下来
6.38 同6.37题条件,写出后序遍历的非递归算法(提示:为分辨后序遍历时两次进栈的不同返回点,需在指针进栈时同时将一个标志进栈).
----------------------------------------------------------
括号里面的提示搞的我的头很大,首先不知道它什么意思,然后自己想到一个没用什么标志的算法又害怕会不会是错的啊,半天不敢动笔,对自己很不自信啊,小悲剧.写完之后测试没什么错才放心,后来看了别的参考答案才知道那个使用标志的算法,确实很有用,那就是真正的”仿照其递归算法执行过程中的状态变化情况”,是很有意义的.以后如果遇到需要将递归转换为非递归的情况,可以认真观察递归算法的执行流程再加以仿照,也许效率会高一些.
后序遍历,就是以左子树,右子树,结点的顺序遍历二叉树.因为是后序遍历,所以我们在栈顶元素出栈的时候访问它.那么和先序遍历一样,如果栈顶元素不是树叶,那么就优先将其非空的左孩子入栈,否则入右孩子.而如果栈顶元素是树叶,那么它肯定要出栈了.同时,如果它是新的栈顶元素的左孩子,那么说明我们左子树已经访问完了,该访问右子树了(将新的栈顶元素的右孩子入栈);如果它是新的栈顶元素的右孩子,那我们右子树也访问完了,可以访问结点了(将新的栈顶元素出栈并访问它,继续这样判断).自己的算法如下:
2 {
3 if(!t)return;
4 InitStack(S);
5 Push(S,t);
6 while(!StackEmpty(S))
7 {
8 GetTop(S,t);
9 if(!t->left&&!t->right)
10 {
11 visit(t);
12 Pop(S,t);
13 while(!StackEmpty(S))
14 {
15 GetTop(S,p);
16 if(t==p->left&&p->right)
17 {
18 Push(S,p->right);
19 break;
20 }
21 else
22 {
23 GetTop(S,t);
24 visit(t);
25 Pop(S,t);
26 }
27 }
28 }
29 else
30 {
31 t=(t->left)?t->left:t->right;
32 Push(S,t);
33 }
34 }
35 }
写完之后,用C++实现了一下:
2 //
3
4 #include "stdafx.h"
5 #include <iostream>
6 #include <vector>
7 using namespace std;
8
9 struct node
10 {
11 char data;
12 node *left;
13 node *right;
14 node(char c=0,node *l=NULL,node *r=NULL):data(c),left(l),right(r){}
15 };
16
17 typedef node * BitTree;
18
19 char ch;
20
21 void CreateTree(BitTree &T)//构造二叉树(按先序次序输入)
22 {
23 ch=cin.get();
24 if(ch==' ')T=NULL;//空结点输入空格
25 else
26 {
27 T=new node(ch);
28 CreateTree(T->left);
29 CreateTree(T->right);
30 }
31 return;
32 }
33
34 void PreOrder_Nonrecursive(BitTree t)//非递归的先序遍历
35 {
36 if(!t)return;
37 vector<BitTree> S;
38 do
39 {
40 cout<<t->data<<" ";
41 if(!t->left&&!t->right)//->的优先级高于!高于&&
42 {
43 while(!S.empty())
44 {
45 if(S.back()->right&&S.back()->right!=t)
46 {
47 t=S.back()->right;
48 break;
49 }
50 t=S.back();
51 S.pop_back();
52 }
53 }
54 else
55 {
56 S.push_back(t);
57 t=(t->left)?t->left:t->right;
58 }
59 }while(!S.empty());
60 cout<<endl;
61 }
62
63 void postorder_traversal(BitTree t)//非递归的后序遍历
64 {
65 if(!t)return;
66 vector<BitTree> S;
67 S.push_back(t);
68 while(!S.empty())
69 {
70 if(!S.back()->left&&!S.back()->right)
71 {
72 t=S.back();
73 cout<<t->data<<" ";
74 S.pop_back();
75 while(!S.empty())
76 {
77 if(t==S.back()->left&&S.back()->right)
78 {
79 S.push_back(S.back()->right);
80 break;
81 }
82 else
83 {
84 t=S.back();
85 cout<<t->data<<" ";
86 S.pop_back();
87 }
88 }
89 }
90 else
91 {
92 t=(S.back()->left)?S.back()->left:S.back()->right;
93 S.push_back(t);
94 }
95 }
96 cout<<endl;
97 }
98
99
100
101 int _tmain(int argc, _TCHAR* argv[])
102 {
103 BitTree root=new node;
104 CreateTree(root);
105 PreOrder_Nonrecursive(root);
106 postorder_traversal(root);
107 system("PAUSE");
108 return 0;
109 }