二叉樹分層遍歷


首先定義二叉樹的存儲結構:

  

1 struct TreeNode {
2     int val;
3     TreeNode *left;
4     TreeNode *right;
5 
6     TreeNode(int v, TreeNode* l = NULL, TreeNode *r = NULL)
7         :val(v), left(l), right(r) {}
8 };

 

1.遞歸的方法(《編程之美》3.10)

  二叉樹本身就帶有遞歸屬性,通常我們可以用遞歸方法解決。假設要訪問第k層節點,那么其實可以轉皇城分別訪問“以該二叉樹根節點的左右子節點為根節點的兩棵子樹”中層次為k-1的節點。此方法需要求出二叉樹的深度,其實可以直接訪問到二叉樹某一層次失敗的時候返回就可以了。

  這個方法的問題是遞歸調用,效率較低。而且對每一層的訪問都需要從根節點開始,效率極差。

  最壞的情況下(不平衡樹)時間復雜度為O(n^2),空間復雜度O(1)

 1 //輸出以root為根節點中的第level層中的所有節點(從左至右),成功返回1
 2 //失敗返回0
 3 //root為二叉樹根節點
 4 //level為層次數,其中根節點為第0層
 5 int PrintNodeAtLevel(TreeNode *root, int level) {
 6     if (!root || level < 0) return 0;
 7     if (level == 0){
 8         cout<<root->val;
 9         return 1;
10     }
11 
12     return PrintNodeAtLevel(root->left, level - 1) + PrintNodeAtLevel(root->right, level - 1);
13 }
14 
15 //層次遍歷二叉樹
16 //root,二叉樹的根節點
17 void LevelOrder(TreeNode *root) {
18     for (int level = 0; ; level++) {
19         if (!PrintNodeAtLevel(root, level)) 
20             break;
21         cout<<endl;
22     }
23 }

 

2. 使用數組和兩個游標的方法(《編程之美》 3.10)

  在訪問k層的時候,我們只需要知道k-1層的信息就足夠了,所以在訪問第k層的時候,要是能夠知道k-1層的節點信息,就不再需要從根節點開始遍歷了。

  根據上述分析,可以從根節點出發,依次將每一層的根節點從左往右壓入一個數組,並並用一個游標cur記錄當前訪問的節點,另一個游標last指示當前層次的最后一個節點的下一個位置,以cur===last作為當前層次訪問結束的條件,在訪問某一層的同時將該層的所有節點的子節點壓入數組,在訪問完某一層之后,檢查是否還有新的層次可以訪問,直到檢查完所有的層次(不再有新的節點可以訪問)

  這種方法需要一個vector一直存儲所有節點,空間效率較差。

  時間復雜度為O(n),空間復雜度為O(n)

 1 void LevelOrder(TreeNode *root) {
 2     if (root == NULL) return;
 3     vector<TreeNode *> vec; //這里使用stl中的vector代替數組,可利用到
 4                             //其動態擴展的屬性
 5     vec.push_back(root);
 6     int cur = 0, last = vec.size();
 7     while (cur < vec.size()) {
 8         last = vec.size();
 9 
10         while (cur < last) {
11             cout<<vec[cur]->val;
12             if (vec[cur]->left) 
13                 vec.push_back(vec[cur]->left);
14             if(vec[cur]->right)
15                 vec.push_back(vec[cur]->right);
16             ++cur;
17         }
18         cout<<endl;
19     }
20 }

 

3. 兩個隊列的方法

  廣度優先搜索的思想。使用兩個隊列,一個記錄當前層的節點,另一個記錄下一層的節點。輸出當前層節點后交換,使下一層的節點稱為當前層的節點。

  時間復雜度O(n),空間復雜度O(1)

 1 void LevelOrder(TreeNode *root) {
 2     if (root == NULL) return ;
 3 
 4     queue<TreeNode *> current, next;
 5     
 6     current.push(root);
 7     while (!current.empty()) {
 8         while (!current.empty()) {
 9             TreeNode * p = current.front();
10             cout<<p->val<<" ";
11             current.pop();
12             if (p->left)
13                 next.push(p->left);
14             if (p->right)
15                 next.push(p->right);
16         }
17         cout<<endl;
18         swap(next, current);
19     }
20 }

 

4.使用一個隊列和兩個標記的方法

  使用current記錄當前節點的數量,nextlevel記錄下一層節點的數量。當current==0時就將下一層置為當前層。

  

 1 void LevelOrder(TreeNode *root) {
 2     if (root == NULL) return;
 3 
 4     queue<TreeNode *> q;
 5     q.push(root);
 6     int nextlevel = 0; //記錄下一層節點的數量
 7     int current = 1; //記錄當前層節點的數量
 8 
 9     while (!q.empty()) {
10         TreeNode *p = q.front();
11         q.pop();
12         --current;
13         cout<<p->val<<" ";
14 
15         if (p->left) {
16             q.push(p->left);
17             ++nextlevel;
18         }
19         if (p->right) {
20             q.push(p->right);
21             ++nextlevel;
22         }
23 
24         if(current == 0) {
25             cout<<endl;
26             swap(current, nextlevel);
27         }
28     }
29 }

 

  

5. 使用一個隊列加一個標記的方法

  用隊列暫存儲節點,每當一層節點進入隊列,就在最后加入一個空指針表示當前層結束。

 1 void LevelOrder(TreeNode *root) {
 2     if (root == NULL) return;
 3 
 4     queue<TreeNode *> q;
 5     q.push(root);
 6     q.push(0);
 7     while (!q.empty()) {
 8         TreeNode *p =q.front();
 9         q.pop();
10         if (p) {
11             cout<<p->val<<" ";
12             if (p->left)
13                 q.push(p->left);
14             if (p->right)
15                 q.push(p->right);
16             //當發現空指針(結束信號時),要檢查隊列是夠還有節點
17             //如果沒有的話還插入新的結束信號,則會造成死循環
18         } else if (!q.empty()) {
19             q.push(0);
20             cout<<endl;
21         }
22     }
23 }

 

 參考資料:

     1.《編程之美》

     2. 《劍指offer》

     2. http://www.cnblogs.com/miloyip/archive/2010/05/12/binary_tree_traversal.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM