1 #include <iostream>
2
3 #define MAXN 100
4 using namespace std; 5
6
7 struct BTNode 8 { 9 char tag; 10 BTNode *left; 11 BTNode *right; 12 }; 13
14 class BTree 15 { 16 private: 17 BTNode **root; 18 void BuildBTree(BTNode **root); 19
20 public: 21 /*递归版本*/
22 void PreVisit(BTNode *root); 23 void InVisit(BTNode *root); 24 void PostVisit(BTNode *root); 25
26 /*非递归版本*/
27 void NR_PreVisit(BTNode *root); 28 void NR_InVisit(BTNode *root); 29 void NR_PostVisit(BTNode *root); 30
31 BTree(BTNode **r); 32 BTree(); 33 }; 34
35 BTree::BTree() 36 { 37
38 } 39
40 BTree::BTree(BTNode **r) 41 { 42 root = r; 43 /*
44 *root = new BTNode; 45 (*root)->left = NULL; 46 (*root)->right = NULL; 47 */
48 BuildBTree(root); 49 } 50
51 /*先序方式插入结点*/
52 void BTree::BuildBTree(BTNode **root) 53 { 54 char c; 55
56 c = getchar(); 57 if(c == '#') 58 *root=NULL; 59 else{ 60 *root = new BTNode; 61 (*root)->tag = c; 62 BuildBTree(&(*root)->left); 63 BuildBTree(&(*root)->right); 64 } 65 } 66
67 void BTree::PreVisit(BTNode *root) 68 { 69 if(root!=NULL) 70 { 71 printf("%c ", root->tag ); 72 PreVisit(root->left); 73 PreVisit(root->right); 74 } 75 } 76
77 void BTree::InVisit(BTNode *root) 78 { 79 if(root!=NULL) 80 { 81 InVisit(root->left); 82 printf("%c ", root->tag ); 83 InVisit(root->right); 84 } 85 } 86
87 void BTree::PostVisit(BTNode *root) 88 { 89 if(root!=NULL) 90 { 91 PostVisit(root->left); 92 PostVisit(root->right); 93 printf("%c ", root->tag ); 94 } 95 } 96
97 void BTree::NR_PreVisit(BTNode *root) 98 { 99 BTNode *s[MAXN]; 100 int top=0; 101
102 while(top!=0 || root!=NULL) 103 { 104 while(root!=NULL) 105 { 106 s[top] = root; 107 printf("%c ", s[top++]->tag); 108 root = root->left; 109 } 110 if(top>0) 111 { 112 root = s[--top]; 113 root = root->right; 114 } 115 } 116 } 117
118 void BTree::NR_InVisit(BTNode *root) 119 { 120 BTNode *s[MAXN]; 121 int top=0; 122
123 while(top!=0 || root!=NULL) 124 { 125 while(root!=NULL) 126 { 127 s[top++]=root; 128 root = root->left; 129 } 130 if(top>0) 131 { 132 root = s[--top]; 133 printf("%c ", root->tag); 134 root = root->right; 135 } 136 } 137 } 138
139 void BTree::NR_PostVisit(BTNode *root) 140 { 141 BTNode *s[MAXN], *tmp=NULL; 142 int top=0; 143
144 while(top!=0 || root!=NULL) 145 { 146 while(root!=NULL) 147 { 148 s[top++]=root; 149 root=root->left; 150 } 151 if(top>0) 152 { 153 root = s[--top]; 154
155 /*右孩子不存在或者已经访问过,root出栈并访问*/
156 if( (root->right == NULL) || (root->right == tmp) ) 157 { 158 printf("%c ", root->tag); 159 tmp = root; //保存root指针
160 root=NULL; //当前指针置空,防止再次入栈
161 } 162
163 /*不出栈,继续访问右孩子*/
164 else
165 { 166 top++; //与root=s[--top]保持平衡
167 root = root->right; 168 } 169 } 170 } 171 } 172
173 int main() 174 { 175 BTNode *root=NULL; 176 BTree bt(&root); //头指针的地址
177
178 bt.NR_PreVisit(root); 179 printf("\n"); 180 bt.NR_InVisit(root); 181 printf("\n"); 182 bt.NR_PostVisit(root); 183 printf("\n"); 184 return 0; 185 }
先上代码,带NR(Non-recursive)的表示非递归遍历。
测试数据:
124#8##5##369###7##
表示的二叉树:
用windows自带的画图画的,的确是粗糙了点。。。
测试结果:
1 2 4 8 5 3 6 9 7
4 8 2 5 1 9 6 3 7
8 4 5 2 9 6 7 3 1
一、关于二叉树的建立
首先要注意二叉树的创建过程,这里用的是先序方式递归插入结点,所以输入数据的时候,必须按照先序方式输入,
左结点或右结点为空的,用#表示。否则,输入不会有响应,因为递归过程还未结束,按CTRL+Z也没用。当然可以用其
他方式插入(如中序递归插入,后序递归插入等)。
二、三种非递归遍历的区别
前序、中序和后序的递归遍历方式比较简单,这里就不讲了。而非递归的遍历方式,只需要用数组存储结点指针,模拟系统栈的工作机制就可以了。
先说先序非递归遍历,按照根-左-右的方式访问的话,需要将当前结点压栈(同时打印当前结点信息),直到左子树为空(内层while);然后出栈,访问
右结点;后面的操作就跟前面的一样了(外层while)。
对于中序非递归遍历,可以看到代码结构几乎一模一样,只是打印结点信息的位置不同而已。这是因为中序遍历是左-根-右,这样前序和中序非
递归遍历(根-左和左-根都是压栈动作,且出栈动作的对象都是父节点)是一致的。
对于后序非递归遍历,因为后序遍历是左-右-根,根的访问是在右孩子之后,而这意味着两种情况:
1、右孩子不为空(继续访问右孩子);
2、右孩子为空,从左孩子返回,则需要访问根结点。
为了区分这两种情况(物理形式上从左孩子返回,还是从右孩子返回来访问根节点),对于右孩子的访问又需要判断根结点的右孩子是否为空或者已
访问过(右子树已遍历过)。除这两种情况外,都不应该访问根节点,而是要继续进入右子树。
三、补充说明
在后序非递归遍历的else语句中top++纯粹是为了使栈保持平衡,因为对于2)继续访问右孩子这种情况,不需要出栈,而前面的root[--top]包含
了出栈操作,以此保证栈的正确性(当然可以有其他的处理,这里也是考虑到三种非递归遍历方式的统一性)。
两个while不会提高程序的时间复杂度,因为二叉树的结点个数是固定的,内层while是为了提高算法的逻辑性。
四、递归->非递归
另外,今天实习看到一个老师写的非递归代码,非常棒,赞一个!他仅仅是将程序的返回地址和函数的形参、局部变量都保存起来,然后在退出时
还原现场;同样是非递归,但是这种方式更接近编译器的处理方式,同操作系统的任务切换也比较一致;所以这种处理方法为递归自动转换为非递归奠
定了基础。
分享一下他当场编写的非递归的汉诺塔:
1 #include <stdio.h> 2 #include <iostream> 3 4 using namespace std ; 5 6 #define MAXSIZE 1000 7 8 struct SNode 9 { 10 int n; 11 char from ; 12 char to; 13 char aux ; 14 int label ; 15 } ; 16 17 struct STK 18 { 19 20 SNode stack[MAXSIZE] ; 21 int sp ; 22 STK() 23 { 24 sp = 0 ; 25 }; 26 void push (int n,char from,char to,char aux, int label ) 27 { 28 if ( sp>= MAXSIZE ) 29 { 30 printf ( "STK is full!\n" ) ; 31 } 32 stack[sp].n = n ; 33 stack[sp].from = from ; 34 stack[sp].to = to ; 35 stack[sp].aux = aux ; 36 stack[sp++].label = label ; 37 }; 38 SNode POP() 39 { 40 if ( sp <=0 ) 41 { 42 printf ( "STK is empty!\n" ) ; 43 } 44 return stack[--sp] ; 45 }; 46 } ; 47 48 void move(int n,char from,char to,char aux) 49 { 50 if(n==1) 51 { 52 cout<<"将#1盘从"<<from<<"移到"<<to<<endl; 53 } 54 else 55 { 56 move(n-1,from,aux,to); 57 cout<<"将#"<<n<<"盘从"<<from<<"移到"<<to<<endl; 58 move(n-1,aux,to,from); 59 } 60 } 61 62 63 void move_stk(int n,char from,char to,char aux) 64 { 65 STK stk ; 66 char tmp; 67 S1: 68 if(n==1) 69 { 70 cout<<"将#1盘从"<<from<<"移到"<<to<<endl; 71 } 72 else 73 { 74 stk.push (n,from,to,aux,2 ) ; 75 n = n-1 ; 76 tmp = to ; 77 to = aux ; 78 aux = tmp ; 79 goto S1; 80 // move(n-1,from,aux,to); 81 S2: 82 cout<<"将#"<<n<<"盘从"<<from<<"移到"<<to<<endl; 83 84 stk.push (n,from,to,aux,3 ) ; 85 n = n-1 ; 86 tmp = from ; 87 from = aux ; 88 aux = tmp ; 89 goto S1; 90 // move(n-1,aux,to,from); 91 } 92 S3: 93 if ( stk.sp > 0 ) 94 { 95 SNode sn = stk.POP() ; 96 n = sn.n ; 97 from = sn.from; 98 to = sn.to ; 99 aux = sn.aux ; 100 if ( 1 == sn.label ) 101 goto S1; 102 else if ( 2 == sn.label ) 103 goto S2; 104 else 105 goto S3; 106 } 107 } 108 109 110 111 int main(int argc, char * argv[]) 112 { 113 move ( 3,'A','B', 'C' ); 114 printf ( "================================\n" ) ; 115 move_stk ( 3,'A','B', 'C' ); 116 117 return 0; 118 }