《编程之美》3.10介绍了二叉树层次遍历及从左到右输出每一层,并给出了两个扩展题目。下面是完整的代码实现:
View Code
1 #include <iostream> 2 #include <cassert> 3 #include <string> 4 #include <fstream> 5 #include <vector> 6 #include <queue> 7 using namespace std; 8 9 struct Node 10 { 11 int m_data; 12 Node* m_lChild; 13 Node* m_rChild; 14 Node(int data=0,Node* lChild=NULL,Node* rChild=NULL) 15 :m_data(data),m_lChild(lChild),m_rChild(rChild){} 16 }; 17 18 //方法一通过返回值来改变和构造整棵树 19 //Node* CreateTree(Node* pNode,vector<int>::iterator &begin,vector<int>::iterator end) 20 //{ 21 // if (*begin!=-1) 22 // { 23 // pNode=new Node(*begin); 24 // if (pNode) 25 // { 26 // if (++begin!=end) 27 // { 28 // pNode->m_lChild=CreateTree(pNode->m_lChild,begin,end); 29 // } 30 // if (++begin!=end) 31 // { 32 // pNode->m_rChild=CreateTree(pNode->m_rChild,begin,end); 33 // } 34 // } 35 // } 36 // return pNode; 37 //} 38 39 //方法二不需要返回值来构造一棵树,传递指针的地址来改变指针的指向 40 //这种方法可以修改为:传递指针的引用来改变指针的指向: 41 //void CreateTree(Node* &pNode,vector<int>::iterator &begin,vector<int>::iterator end) 42 void CreateTree(Node** pNode,vector<int>::iterator &begin,vector<int>::iterator end) 43 { 44 if (*begin!=-1) 45 { 46 *pNode=new Node(*begin); 47 if (*pNode) 48 { 49 if (++begin!=end) 50 { 51 CreateTree(&((*pNode)->m_lChild),begin,end); 52 } 53 if (++begin!=end) 54 { 55 CreateTree(&((*pNode)->m_rChild),begin,end); 56 } 57 } 58 } 59 } 60 61 Node* CreateTree(const char* fileName) 62 { 63 ifstream inFile; 64 inFile.open(fileName); 65 int value; 66 vector<int> vec; 67 while (inFile>>value) 68 { 69 vec.push_back(value); 70 } 71 if (vec.empty()) 72 { 73 return NULL; 74 } 75 Node* pRoot=NULL; 76 //pRoot=CreateTree(pRoot,vec.begin(),vec.end()); 77 CreateTree(&pRoot,vec.begin(),vec.end()); 78 return pRoot; 79 } 80 81 82 void InOrderTra(Node* pRoot) 83 { 84 if (pRoot) 85 { 86 InOrderTra(pRoot->m_lChild); 87 cout<<pRoot->m_data<<" "; 88 InOrderTra(pRoot->m_rChild); 89 } 90 } 91 92 //打印二叉树中某层次的节点,从左到右 93 //根节点为第0层 94 //成功返回1,失败返回0 95 int PrintNodeAtLevel(Node* root,int level) 96 { 97 if (!root || level<0) 98 { 99 return 0; 100 } 101 if (level==0) 102 { 103 cout<<root->m_data<<" "; 104 return 1; 105 } 106 return PrintNodeAtLevel(root->m_lChild,level-1) | PrintNodeAtLevel(root->m_rChild,level-1); 107 } 108 109 //求二叉树的深度 110 int Depth(Node* root) 111 { 112 if (!root) 113 { 114 return 0; 115 } 116 return 1+(max(Depth(root->m_lChild),Depth(root->m_rChild))); 117 } 118 119 //利用二叉树的深度及打印二叉树的某层次的节点来 120 //层次遍历二叉树 121 void LevelTra1(Node* root) 122 { 123 if (!root) 124 { 125 return; 126 } 127 int depth=Depth(root); 128 for (int i=0;i<depth;i++) 129 { 130 PrintNodeAtLevel(root,i); 131 cout<<endl; 132 } 133 } 134 135 //当不知道二叉树的深度时,利用PrintNodeAtLevel的返回值 136 //来结束循环 137 void LevelTra2(Node* root) 138 { 139 if (!root) 140 { 141 return; 142 } 143 int depth=Depth(root); 144 for (int i=0;;i++) 145 { 146 if (!PrintNodeAtLevel(root,i)) 147 { 148 break; 149 } 150 cout<<endl; 151 } 152 } 153 154 //非递归,利用queue记录节点信息来层次 155 //遍历二叉树。但是这种做法,怎样才能做 156 //到访问每层之后打印一个换行呢? 157 void LevelTra3(Node* root) 158 { 159 if (!root) 160 { 161 return; 162 } 163 queue<Node*> m_queue; 164 m_queue.push(root); 165 while (!m_queue.empty()) 166 { 167 Node* cur=m_queue.front(); 168 cout<<cur->m_data<<" "; 169 m_queue.pop(); 170 if (cur->m_lChild) 171 { 172 m_queue.push(cur->m_lChild); 173 } 174 if (cur->m_rChild) 175 { 176 m_queue.push(cur->m_rChild); 177 } 178 } 179 cout<<endl; 180 } 181 182 //编程之美上的方法:cur和last 183 //两个下标太巧妙了!!! 184 void LevelTra4(Node* root) 185 { 186 if (!root) 187 { 188 return; 189 } 190 vector<Node*> vec; 191 vec.push_back(root); 192 int cur=0; 193 int last=1; 194 while (cur<vec.size()) 195 { 196 last=vec.size(); 197 while (cur<last) 198 { 199 cout<<vec[cur]->m_data<<" "; 200 if (vec[cur]->m_lChild) 201 { 202 vec.push_back(vec[cur]->m_lChild); 203 } 204 if (vec[cur]->m_rChild) 205 { 206 vec.push_back(vec[cur]->m_rChild); 207 } 208 cur++; 209 } 210 cout<<endl; 211 } 212 } 213 214 //编程之美上的扩展问题2: 215 //从下往上层次遍历,并且每一层从右向左输出 216 void ReverseLevelTra1(Node* root) 217 { 218 if (!root) 219 { 220 return; 221 } 222 vector<Node*> vec; 223 vec.push_back(root); 224 vec.push_back(NULL); 225 int cur=0; 226 int last=2; 227 while (cur<vec.size()-1) 228 { 229 last=vec.size(); 230 while (cur<last) 231 { 232 if (vec[cur] && vec[cur]->m_lChild) 233 { 234 vec.push_back(vec[cur]->m_lChild); 235 } 236 if (vec[cur] && vec[cur]->m_rChild) 237 { 238 vec.push_back(vec[cur]->m_rChild); 239 } 240 cur++; 241 } 242 vec.push_back(NULL); 243 } 244 vec.pop_back(); 245 vec.pop_back(); 246 for (int i=vec.size()-1;i>=0;i--) 247 { 248 if (vec[i]) 249 { 250 cout<<vec[i]->m_data<<" "; 251 } 252 else 253 { 254 cout<<endl; 255 } 256 } 257 cout<<endl; 258 } 259 260 261 //编程之美上的扩展问题1: 262 //从下往上层次遍历,并且每一层从左向右输出 263 void ReverseLevelTra2(Node* root) 264 { 265 if (!root) 266 { 267 return; 268 } 269 vector<Node*> vec; 270 vec.push_back(root); 271 vec.push_back(NULL); 272 int cur=0; 273 int last=2; 274 while (cur<vec.size()-1) 275 { 276 last=vec.size(); 277 while (cur<last) 278 { 279 if (vec[cur] && vec[cur]->m_rChild) 280 { 281 vec.push_back(vec[cur]->m_rChild); 282 } 283 if (vec[cur] && vec[cur]->m_lChild) 284 { 285 vec.push_back(vec[cur]->m_lChild); 286 } 287 cur++; 288 } 289 vec.push_back(NULL); 290 } 291 //这里需要注意最后vec中最后连个均为NULL,需要全pop出来 292 vec.pop_back(); 293 vec.pop_back(); 294 for (int i=vec.size()-1;i>=0;i--) 295 { 296 if (vec[i]) 297 { 298 cout<<vec[i]->m_data<<" "; 299 } 300 else 301 { 302 cout<<endl; 303 } 304 } 305 cout<<endl; 306 } 307 308 //利用二叉树的深度及打印二叉树的某层次的节点来 309 //从低向上层次遍历二叉树 310 void ReverseLevelTra3(Node* root) 311 { 312 if (!root) 313 { 314 return; 315 } 316 int depth=Depth(root); 317 for (int i=depth-1;i>=0;i--) 318 { 319 PrintNodeAtLevel(root,i); 320 cout<<endl; 321 } 322 } 323 324 int main() 325 { 326 char* fileName="tree.txt"; 327 Node* pTree=CreateTree(fileName); 328 InOrderTra(pTree); 329 cout<<endl; 330 PrintNodeAtLevel(pTree,2); 331 cout<<endl; 332 cout<<Depth(pTree)<<endl; 333 LevelTra1(pTree); 334 LevelTra2(pTree); 335 LevelTra3(pTree); 336 LevelTra4(pTree); 337 ReverseLevelTra1(pTree); 338 ReverseLevelTra2(pTree); 339 ReverseLevelTra3(pTree); 340 } 341 342 //tree.txt文件内容为: 343 //1 2 4 -1 -1 5 7 -1 -1 8 -1 -1 3 -1 6 -1 -1 344 //构造出的树为编程之美P252图3-18的树
需要注意的问题如下:
1. 在构建二叉树的时候,二叉树在文件中按前序遍历存储,左右子树为空时,用-1表示。
2. 解决两个扩展题目并没有使用什么新方法,只是修改了书上的算法,首先将节点按层次存储在vector中,每一层之后存储一个NULL指针。
然后从后向前遍历vector,输出节点。至于每一层节点输出是从左到右还是从右到左与代码中将左右子树压入vector的顺序有关。
3. 书中的处理方法,设置cur和last两个下标太巧妙了,在以后的学习中记得使用。
4. 二叉树相关算法首先想到递归,毕竟二叉树的定义都是递归形式。
5. 非递归方法一般要借助队列、栈来存储路径上的节点。
6. ReverseLevelTra3,利用树的深度,从低向上从左到右层次输出每一层的节点。如果要从右到左输出,需要修改PrintNodeAtLevel代码如下:
return PrintNodeAtLevel(root->m_rChild,level-1) | PrintNodeAtLevel(root->m_lChild,level-1);
来源:https://www.cnblogs.com/ZJUKasuosuo/archive/2012/06/12/BinaryTree.html