二叉树层次遍历

我是研究僧i 提交于 2020-03-01 13:51:38

《编程之美》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);

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!