【二叉树】二叉树遍历总结

  节点定义如下

1 // Definition for a binary tree node.
2 struct TreeNode {
3     int val;
4     TreeNode *left;
5     TreeNode *right;
6     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
7 }

  前序遍历:

  若二叉树为空,则空操作返回,否则:

  1. 访问根节点
  2. 前序遍历根节点的左子树
  3. 前序遍历根节点的右子树  

  中序遍历:

  若二叉树为空,则空操作返回,否则:

  1. 中序遍历根节点的左子树
  2. 访问根节点
  3. 中序遍历根节点的右子树

  后序遍历:

  若二叉树为空,则空操作返回,否则:

  1. 后序遍历根节点的左子树
  2. 后序遍历根节点的右子树
  3. 访问根节点  

   层序遍历:

  其中后序遍历可以看作是和前序遍历是对称的,所以从根节点开始先遍历右子树,再遍历左子树,不过要把最后的遍历输出翻转过来。所以后序遍历的代码和前序遍历的代码基本一致,只是左右子树的访问顺序不同。

 

1. 递归方法

  前序遍历:

1 void preorderTraversal(TreeNode* root, vector<int>& nums) {
2     if(!root) return;
3     nums.push_back(root->val); // 访问根节点
4     preorderTraversal(root->left); // 前序遍历左子树
5     preorderTraversal(root->right); // 前序遍历右子树
6 }

  中序遍历:

1 void inorderTraversal(TreeNode* root, vector<int>& nums) {
2     if(!root) return;   
3     inorderTraversal(root->left, nums); // 中序遍历左子树
4     nums.push_back(root->val);          // 访问根节点
5     inorderTraversal(root->right, nums); // 中序遍历右子树
6 } 

  后序遍历:

1 void postorderTraversal(TreeNode* root, vector<int>& nums) {
2     if(!root) return;   
3     postorderTraversal(root->left, nums); // 后序遍历左子树
4     postorderTraversal(root->right, nums); // 后序遍历右子树
5     nums.push_back(root->val);            // 访问根节点
6 }

    层序遍历:

 1 vector<vector<int>> levelOrder(TreeNode* root) {
 2     vector<vector<int> > res;
 3     levelorder(root, 0, res);
 4     return res;
 5 }
 6 void levelorder(TreeNode *root, int level, vector<vector<int> > &res) {
 7     if (!root) 
 8         return;
 9     if (res.size() == level) 
10         res.push_back({});
11     
12     res[level].push_back(root->val);
13     
14     if (root->left) 
15         levelorder(root->left, level + 1, res);
16     if (root->right) 
17         levelorder(root->right, level + 1, res);
18 }

 

 

2.迭代方法(使用栈)

  

  前序遍历 1):

 1 void preorderTraversal(TreeNode* root, vector<int>& nums) {
 2     TreeNode* cur = root;
 3   stack<TreeNode* > st; 
 4 
 5     while (cur || !st.empty()) {
 6         if (cur) {
 7             st.push(cur);
 8             nums.push_back(cur->val);
 9             cur = cur->left;
10         } else {
11             cur = st.top();
12             st.pop();
13             cur = cur->right;
14         }
15      }
16 }

  前序遍历 2):

 1 void preorderTraversal(TreeNode* root, vector<int>& nums) {
 2     TreeNode* cur = root;
 3   stack<TreeNode* > st; 
 4 
 5     while (cur || !st.empty()) {
 6         if (!cur) {                           // 根节点为空,则需要返回上一级
 7             cur = st.top();               // 访问右子树,而右子树已被保存在栈中
 8             st.pop();
 9         }            
10         nums.push_back(cur->val);  // 访问根节点
11         if (cur->right) st.push(cur->right); // 保存待遍历节点
12         cur = cur->left; // 继续访问左子树
13     }             
14 } 

  前序遍历 3):

void preorderTraversal(TreeNode* root, vector<int>& nums) {
  stack<TreeNode* > st; 
    if (!root)
        return;
    st.push(root);

    while (!st.empty()) {
        TreeNode* cur = st.top();
        st.pop();
        nums.push_back(cur->val);
        if (cur->right)
            st.push(cur->right);
        if (cur->left)
            st.push(cur->left); 
    }             
}

 

  中序遍历:

 1 void inorderTraversal(TreeNode* root, vector<int>& nums) {
 2     TreeNode* cur = root;
 3     stack<TreeNode* > st; 
 4 
 5     while (cur || !st.empty()) {
 6         if (cur) {                                 // 找到最左节点并保存根节点
 7             st.push(cur);                     // 即访问左子树
 8             cur = cur->left;
 9         } else {                                  
10             cur = st.top();
11             st.pop();
12             nums.push_back(cur->val);    // 访问根节点
13             cur = cur->right;                      // 访问右子树
14         }
15     }
16 } 

  后序遍历 1) 遍历结果需要翻转:

 1 void postorderTraversal(TreeNode* root, vector<int>& nums) {
 2     stack<TreeNode* > st;
 3     TreeNode* cur = root;
 4 
 5     while (cur || !st.empty()) {
 6         if (cur) {
 7             nums.push_back(cur->val);
 8             st.push(cur);
 9             cur = cur->right;
10         } else {
11             cur = st.top();
12             st.pop();
13             cur = cur->left;
14         }
15     }
16     reverse(nums.begin(), nums.end());
17 }

  后序遍历 2) 遍历结果需要翻转:

 1 void postorderTraversal(TreeNode* root, vector<int>& nums) {
 2     stack<TreeNode* > st;
 3     TreeNode* cur = root;
 4 
 5     while (cur|| !st.empty()) {
 6         if (!cur) {
 7             cur= st.top();
 8             st.pop();
 9         }
10         nums.push_back(cur->val);
11         if (cur->left) st.push(cur->left);
12         cur= cur->right;
13     }
14     reverse(nums.begin(), nums.end());
15 }

  后序遍历 3) 遍历结果无需翻转:

 1 void postorderTraversal(TreeNode* root, vector<int>& nums) {
 2     stack<TreeNode* > st;
 3     TreeNode* cur = root, *pre = nullptr;
 4 
 5     while (cur || !st.empty()) {
 6         while (cur) {          // 找到最左节点,并存储沿路节点
 7             st.push(cur);
 8             cur = cur->left;
 9         }
10         cur = st.top();        // 
11         if (!cur->right || cur->right == pre) {  // 右子树已遍历或为空,则访问根节点
12             nums.push_back(cur->val);           // 并将根节点从栈中推出
13             pre = cur;
14             st.pop();
15             cur = nullptr;        // cur置为null,从而再从栈中取节点,即返回父节点
16         } else {                                 
17             cur = cur->right;     // 当前节点的右子树尚未遍历,则该节点保留在栈中
18         }                         // 遍历右子树
19     }
20 }

 

 3.Morris遍历

  Morris算法基于线段树,利用叶子结点的空指针建立索引,此索引按照中序遍历的顺序建立。

  前序遍历:

 

  

 1 void preorderTraversal(TreeNode* root, vector<int>& nums) {
 2     TreeNode* cur = root, *pre = nullptr;
 3 
 4     while (cur) {
 5         if (cur->left) {   // 左孩子不为空,则找中序遍历下的前驱结点
 6             pre= cur->left;  // 前驱结点为左子树的最右节点
 7             while (pre->right && pre->right != cur) { // 找到最优节点,且该节点未建立线索
 8                 pre = pre->right; // cur的中序遍历下的前驱结点
 9             }
10 
11             if (pre->right == cur) {  // cur与pre已建立线索,则去掉该线索
12                 pre->right = nullptr;  // 剪掉线索
13                 cur= cur->right;       // 左子树已遍历完毕,遍历右子树
14             } else {                    // cur与pre并未建立线索,则建立线索
15                 nums.push_back(cur->val);
16                 pre->right = cur;   
17                 cur= cur->left;    // 遍历左子树,继续建立线索
18             }
19         } else {
20             nums.push_back(cur->val);   
21             cur = cur->right;  // 左子树为空,则返回父节点,且父节点已与此节点已建立线索,即parent = cur->right
22         }
23     }
24 }

 

 

  中序遍历:

 

 1 void inorderTraversal(TreeNode* root, vector<int>& nums) {
 2     TreeNode* cur = root, *pre = nullptr;
 3 
 4     while (cur) {
 5         if (cur->left) {
 6             pre = cur->left;
 7             while (pre->right && pre->right != cur) {
 8                 pre = pre->right;
 9             }
10 
11             if (pre->right == cur) {
12                 nums.push_back(cur->val); // 建立的线索是根据中序遍历
13                 pre->right = nullptr;
14                 cur = cur->right;
15             } else {
16                 pre->right = cur;
17                 cur = cur->left;
18             }               
19         } else {
20             nums.push_back(cur->val);
21             cur = cur->right;
22         }
23     }
24 } 

 

  后序遍历:

 

 1 void postorderTraversal(TreeNode* root, vector<int>& nums) {
 2     TreeNode* cur = root, *pre = nullptr;
 3 
 4     while (cur) {
 5         if (cur->right) {
 6             pre = cur->right;
 7             while (pre->left && pre->left != cur) {
 8                 pre = pre->left;
 9             }
10 
11             if (pre->left == cur) {
12                 pre->left = nullptr;
13                 cur = cur->left;
14             } else {
15                 nums.push_back(cur->val);
16                 pre->left = cur;
17                 cur = cur->right;
18             }
19 
20         } else {
21             nums.push_back(cur->val);
22             cur = cur->left;
23         }
24     }
25     reverse(nums.begin(), nums.end());
26 } 

 

4.分治

  前序遍历:

 1 vector<int> preorderTraversal(TreeNode* root) {
 2     vector<int> res;
 3     if (!root)
 4         return res;
 5         
 6     vector<int> leftSubTree = preorderTraversal(root->left);
 7     vector<int> rightSubTree = preorderTraversal(root->right);
 8 
 9     res.push_back(root->val);
10     res.insert(res.end(), leftSubTree.begin(), leftSubTree.end());
11     res.insert(res.end(), rightSubTree.begin(), rightSubTree.end());
12 
13     return res;       
14 }

 

posted @ 2018-03-17 09:13  Vincent丶丶  阅读(421)  评论(0编辑  收藏  举报