二叉树的遍历:先序,中序,后序,递归,非递归,层次遍历

二叉树遍历的递归写法:

#include <iostream>
#include <vector>
#include <algorithm>
#include <stack>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x):val(x), left(NULL), right(NULL) {}
};

// 先序遍历
void preOrder(TreeNode* root)
{
    if(root == NULL)
        return;
    cout << root->val << " ";
    preOrder(root->left);
    preOrder(root->right);
}

// 中序遍历
void inOrder(TreeNode* root)
{
    if(root == NULL)
        return;
    inOrder(root->left);
    cout << root->val << " ";
    inOrder(root->right);
}

// 后序遍历
void lastOrder(TreeNode* root)
{
    if(root == NULL)
        return;
    lastOrder(root->left);
    lastOrder(root->right);
    cout << root->val << " ";
}


---
## 非递归写法:
- 先序遍历

题目链接

vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> temp;
        if(root == NULL)
            return res;
        temp.push(root);
        while(!temp.empty())
        {
            TreeNode* pos = temp.top();
            temp.pop();
            res.push_back(pos->val);
            if(pos->right != NULL)
                temp.push(pos->right);
            if(pos->left != NULL)
                temp.push(pos->left);
        }
        return res;
}



- 中序遍历

题目链接

// 只有当左子树已经访问完后,才能访问根节点
/*
    对于任一节点 P
    1)  若其左孩子不为空,则将 P 入栈并将 P 的左孩子置为当前 P ,
        然后对当前 P 再进行相同的处理;
    2)  若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶节点,
        然后将当前 P 置为栈顶节点的右孩子;
    3)  直到 P 为 NULL 并且栈为空则遍历结束;
*/
vector<int> inOrderTraversal(TreeNode* root){
    vector<int> res;
    stack<TreeNode*> temp;
    if(root == NULL)
        return res;
    TreeNode* pos = root;
    while(!temp.empty() || pos != NULL)
    {
        if(pos != NULL){
            // push 左子树入栈
            temp.push(pos);
            pos = pos->left;
        }
        else
        {
            pos = temp.top();
            temp.pop();
            res.push_back(pos->val);
            pos = pos->right;
        }
    }
    return res;
}



- 后序遍历

题目链接

// 先入栈根,然后是右子树,最后左子树
// 要求最后访问根节点, 即访问该根节点时必须访问完左子树和右子树,
// 我们只需要保证访问某一节点时,该节点的右子树已经被访问, 否则需要
// 将该节点重新压入栈。
/*
对于任一结点 P, 将其入栈, 然后沿其左子树一直往下搜索, 直到搜索到没有左孩子的结点,
此时该结点出现在栈顶,但是此时不能将其出栈并访问,因为其右孩子还没有被访问。
所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在
栈顶,此时可以将其出栈并访问。 这样就保证了正确的访问顺序。 可以看出,在这个过程中,
每个结点都两次出现在栈顶,并且只有第二次出现在栈顶时,才能访问它。
*/
 vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> tmp;
        if(root == NULL)
            return res;
        TreeNode* pos = root;   // 记录正在访问的结点
        TreeNode* pre = NULL;   // 记录前一个访问的结点
        do
        {
            while(pos != NULL)      // 把左子树结点都压进栈
            {
                tmp.push(pos);
                pos = pos->left;
            }
            pre = NULL;             // 左结点压完后,初始化前一个访问结点为 NULL
            while(!tmp.empty())
            {
                pos = tmp.top();
                tmp.pop();
                if(pos->right == pre)       // 右孩子已经被访问
                {
                    res.push_back(pos->val);    // 右孩子已经被访问,可以访问该结点
                    pre = pos;      // 记录刚刚访问的结点
                }
                else
                {
                    tmp.push(pos);  // 第一次访问该结点,再次放入栈中
                    pos = pos->right;
                    break;
                }
            }
        } while(!tmp.empty());

        return res;
    }

---
- 层次遍历

题目链接

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
		vector<int> res; 
        queue<TreeNode*> tmp; 
        if(root == NULL)
            return res; 
        TreeNode* pos = root; 
        tmp.push(pos); 
        while(!tmp.empty())
       	{
            pos = tmp.front(); 
            tmp.pop();
            res.push_back(pos->val); 
            if(pos->left != NULL)
                tmp.push(pos->left); 
            if(pos->right != NULL)
                tmp.push(pos->right); 
        }
        return res; 
    }
};

[题目链接](https://leetcode.com/problems/binary-tree-level-order-traversal/#/description)
方法一:(思路) 在普通层次遍历的基础上,用 NULL 分隔各层。 
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int> > res;
        vector<int> level; 
        queue<TreeNode*> tmp; 
        if(root == NULL)
            return res; 
        TreeNode* pos = root;
        tmp.push(pos); 
        tmp.push(NULL);         // 以 NULL 作为每层之间的分隔板 
        while(!tmp.empty())
        {
            pos = tmp.front(); 
            tmp.pop(); 
            if(pos == NULL)
            {
                res.push_back(level);  
                level.resize(0); 
                if(tmp.size() > 0)      // 注意当队列为空时不能再插入 NULL, 不然会无限循环。
                    tmp.push(NULL);     // 当前层的所有子节点(下一层)都已加入队列,插入 NULL 进行分隔       
            }
            else
            {
                level.push_back(pos->val); 
                if(pos->left != NULL)
                    tmp.push(pos->left); 
                if(pos->right != NULL)
                    tmp.push(pos->right); 
            }
        }
        return res; 
    }
};

方法二:(思路) 先序遍历, 全局数组记录各层结点的值。 
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(root == NULL)
            return res; 
        buildLevels(root, 0); 
        return res; 
    }
    
private:
vector<vector<int> > res;     
    void buildLevels(TreeNode* pos, int depth)    // 先序遍历
    {
        if(pos == NULL)
            return; 
        if(res.size() == depth)
            res.push_back(vector<int>());   // 每到一个新层,初始化这一层
        res[depth].push_back(pos->val);     
        buildLevels(pos->left, depth+1); 
        buildLevels(pos->right, depth+1);
    }
};

方法三: 上层完全出队后(此时下层完全入队),记录一下队列的大小。 ```cpp /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: vector> levelOrder(TreeNode* root) { vector > res; if(root == NULL) return res;
    TreeNode* pos = root; 
    queue<TreeNode*> que;
    que.push(pos); 
    
    while(!que.empty())
    {
        int sz = que.size();
        vector<int> temp; 
        while(sz--)
        {
            pos = que.front();
            que.pop();
            temp.push_back(pos->val);
            if(pos->left != NULL)
                que.push(pos->left);
            if(pos->right != NULL)
                que.push(pos->right);
        }
        
        res.push_back(temp);
    }
    
    return res; 
}

};

<br/>
<br/>

- 小进阶: 之字型打印二叉树
[题目连接](https://www.nowcoder.com/practice/91b69814117f4e8097390d107d2efbe0?tpId=13&tqId=11212&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)

// 方法一: 使用 reverse()
```cpp
/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
        vector<vector<int> > Print(TreeNode* pRoot) {
        	vector<vector<int> > res; 
            if(pRoot == NULL)
                return res; 
            
            vector<int> level; 
            TreeNode* pos = pRoot; 
            queue<TreeNode*> tmp;
            
            tmp.push(pos);
            tmp.push(NULL);		// 以 NULL 作为隔板
            
            bool flag = true; 
            while (!tmp.empty())
            {
                pos = tmp.front(); 
                tmp.pop();
                
                if(pos == NULL)
                {
                    if(flag)
                    	res.push_back(level);
                    else
                    {
                        reverse(level.begin(), level.end());
                        res.push_back(level); 
                    }
                        
                    
                    level.resize(0);
                    if(tmp.size() > 0)	// 注意: 当 tmp为空时,不要再插入 NULL. 不然无限循环
                        tmp.push(NULL);
                    flag = !flag;
                }
                else
                {
                    level.push_back(pos->val);
                    if(pos->left != NULL)
                        tmp.push(pos->left);
                    if(pos->right != NULL)
                        tmp.push(pos->right);
                }
            }
            
            return res; 
        }
    
};

// 方法二: 祭出利器 deque

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int> > res; 
        if(pRoot == NULL)
            return res; 
        
        deque<TreeNode*> deq;
        TreeNode* pos = pRoot; 
        deq.push_back(pos);
        bool flag = true; 
        while(!deq.empty())
        {
            flag = !flag; 
            int sz = deq.size();
            vector<int> temp; 
            while(sz--)
            {
                if(flag)	// pop_front, push_back, right then left
                {
                    pos = deq.front();
                    deq.pop_front();
                    temp.push_back(pos->val);
                    if(pos->right != NULL)
                        deq.push_back(pos->right);
                    if(pos->left != NULL)
                        deq.push_back(pos->left); 
                }
                else	// pop_back, push_front, left then right
                {
                    pos = deq.back();
                    deq.pop_back();
                    temp.push_back(pos->val);
                    if(pos->left != NULL)
                        deq.push_front(pos->left);
                    if(pos->right != NULL)
                        deq.push_front(pos->right);
                }
            }
            res.push_back(temp);
        }
        
        return res; 
    }
    
};


posted @ 2017-04-24 19:48  草滩小恪  阅读(381)  评论(0编辑  收藏  举报