当前位置: 首页 > news >正文

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

二叉树遍历的递归写法:

#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; 
    }
};



题目链接

方法一:(思路) 在普通层次遍历的基础上,用 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);
    }
};



方法三: 上层完全出队后(此时下层完全入队),记录一下队列的大小。

/**
 * 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; 
        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; 
    }
};




  • 小进阶: 之字型打印二叉树
    题目连接

// 方法一: 使用 reverse()

/*
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; 
    }
    
};




转载于:https://www.cnblogs.com/acm1314/p/6758610.html

相关文章:

  • 申请Google API Key的方法(Debug版本)
  • 转:【C/C++】结构体和联合体的区别
  • shell--传入参数的处理
  • 日期格式化
  • 顺时针螺旋递减等差数列矩阵
  • MVC DataTable转ArrayList转JSON返回JSON到页面
  • 自定义控件自动出现在工具栏
  • 中庸之道别解,读《幸福超越完美》——leo鉴书(13)
  • mvc:argument-resolvers 自定义注解处理参数
  • Android下实现GPS定位服务
  • 数字转化为汉字,如5-五
  • 用Thread做点自动化的事
  • 201521123042 《Java程序设计》 第10周学习总结
  • Mysql全文索引
  • 如何不用组件实现Ajax效果
  • 【每日笔记】【Go学习笔记】2019-01-10 codis proxy处理流程
  • canvas 高仿 Apple Watch 表盘
  • CSS居中完全指南——构建CSS居中决策树
  • JAVA之继承和多态
  • JS笔记四:作用域、变量(函数)提升
  • Linux各目录及每个目录的详细介绍
  • python_bomb----数据类型总结
  • React Transition Group -- Transition 组件
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • SpiderData 2019年2月23日 DApp数据排行榜
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 如何学习JavaEE,项目又该如何做?
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • 在electron中实现跨域请求,无需更改服务器端设置
  • 正则学习笔记
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​卜东波研究员:高观点下的少儿计算思维
  • #define用法
  • #宝哥教你#查看jquery绑定的事件函数
  • (1)常见O(n^2)排序算法解析
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (算法)Travel Information Center
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET : 在VS2008中计算代码度量值
  • .NET DataGridView数据绑定说明
  • .Net Memory Profiler的使用举例
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • .net与java建立WebService再互相调用
  • []error LNK2001: unresolved external symbol _m
  • [20140403]查询是否产生日志
  • [2016.7 Day.4] T1 游戏 [正解:二分图 偏解:奇葩贪心+模拟?(不知如何称呼不过居然比std还快)]