【leetcode】二叉树专题-遍历

二叉树的结构

 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };

二叉树的深度遍历的三种方式

在开始总结三种遍历方式之前,先将左程云老师提到递归序做一个总结,我理解的递归序就是递归过程中遍历到节点顺序。针对下面这个伪代码:

void recursive(TreeNode*node){
	if(node == NULL)
		return ;
	recursive(node->left);
	
	recursive(node->right);
}

递归过程,是先遍历自己,然后进而遍历左子树,再遍历右子树,调用函数的过程中,return会返回到上一次调用的位置,所以每个节点都会被遇到3次。对应的递归顺序如下:
12444255523666377731
在这里插入图片描述

前序遍历

所谓前序遍历是指第一次遇到这个节点的时候就做出相应的动作,比如打印,这样前序遍历的舒顺序是:1->2->4->5->3->6->7(在递归序中取出第一次出现的数字即可)

  • 递归实现
void recursive(TreeNOde*node){
	if(node == NULL)
		return ;
	cout<<node->val<<" ";
	//左子树
	recursive(node->left);
	//右子树
	recursive(node->right);
}
  • 非递归实现
  1. 非递归实现本质就是自己用代码实现栈这一数学结构,栈是满足【先入后出】的特性为了配合这一特性,我们应该先将右孩子压入栈,再将左孩子压入栈,这样就能实现左孩子先弹出,先处理左子树,右孩子再弹出,再处理右子树的过程,满足先序遍历。
  2. 同样,先序遍历是指第一次遇到该节点就处理(比如打印)所以每次从栈顶弹出节点我们都要打印,然后再压栈操作,直至栈空。
    具体实现
1.先将父节点入栈
2.从栈中弹出一个节点,记为cur
3.打印、处理cur
4.先右节点入栈再左节点入栈(如果存在左右节点的话)
5.重复以上操作,直至栈空

代码

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>res;
        if(root != nullptr){
        
            stack<TreeNode*>stk;
            stk.push(root);
            while(!stk.empty()){
                TreeNode*temp = stk.top();
                stk.pop();
                res.push_back(temp->val);
                if(temp->right != nullptr)
                    stk.push(temp->right);
                if(temp->left != nullptr)
                    stk.push(temp->left);
            }
        }
        return res;
    }
};

中序遍历

  • 非递归实现
  1. 中序遍历顺序是 左-头-右
  2. 循环内部将整棵树的左节点入栈,当没有左节点时弹出栈顶元素
  3. 并对弹出的栈顶元素做处理,之后将栈顶元素的右子树左同样的处理:将右子树的左节点一直入栈,循环往复
  4. 相当于整个树按照左边界分解到了
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>res;
        if(root != nullptr){
        
            stack<TreeNode*>stk;
            TreeNode*tmp = root;
            while(!stk.empty() || tmp != nullptr ){
                if(tmp != nullptr){
                	stk.push(temp);
                	temp = temp -> left;
                }
                else{
                	temp = stk.top();
                	stk.pop();
                	res.push_back(temp->val);
                	temp = temp -> right;
                }
            }
        }
        return res;
    }
};

后序遍历

  • 非递归实现
  1. 后序遍历的处理方式应该是左-右-头,在遍历的过程中,头节点总是最先遇到,我们遇到时不做任何处理,借助收集栈,放入收集栈中,之后利用栈“先入后出”的特性,最后处理头节点
  2. 先遍历 头节点,之后遍历左节点、右节点,采用循环完成,循环过程中,先将栈顶元素出栈,出栈元素放入收集栈中,之后取出栈顶元素的左节点处理栈,取出栈顶元素的右节点入处理栈,循环往复。
  3. 对收集栈进行出栈操作。
1.根节点入栈
2.循环内部先将栈顶元素出栈,记为cur了, 直至栈空
3.左节点入栈
4.右节点入栈
5.cur节点放入收集栈
6.处理完成后,收集栈内元素依次出栈
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>res;
        if(root != nullptr){
        
            stack<TreeNode*>stk;
            stack<TreeNode*>stk1; // collecting
            stk.push(root);
            while(!stk.empty()){
                TreeNode*temp = stk.top();
                stk.pop();
                stk1.push(temp);
                if(temp->left != nullptr)
                    stk.push(temp->left);
                if(temp->right != nullptr)
                    stk.push(temp->right);             
            }
            while(!stk1.empty()){
            	TreeNode*cur = stk1.top();
            	stk1.pop();
            	res.push_back(cur->Val);
            }
        }
        return res;
    }
};

二叉树的宽度优先遍历

BFS

宽度优先遍历表示按层处理二叉树中的每一个结点,下图遍历顺序应为1-2-3-4-5-6-7
在这里插入图片描述
实现思路

- 采用队列的方式实现,先入先出,
- 首先将头节点进入队列,之后进入循环,将队列头部元素出队列,出队列时处理该节点
- 左右孩子入队列
- 循环往复,直至队列为空

代码

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>res;
        if(root != nullptr){
        
            queue<TreeNode*>que ;
            que.push(root);
            while(!que.empty()){
                TreeNode*temp = que.front();
                que.pop();
                res.push_back(temp->val);
                if(temp->left != nullptr)
                    que.push(temp->left);
                if(temp->right != nullptr)
                    que.push(temp->right);             
            }
        }
        return res;
    }
};

BFS获得二叉树最大宽度

二叉树宽度为每一层的结点个数,下面的二叉树中最大宽度为4,可以采用BFS的方式得到二叉树的最大宽度
在这里插入图片描述
实现思路:


 1. 要想得到每一层的宽度,就需要标记每一个节点所在的层,这样才能统计每一层结点的个数,从而得到一棵二叉树的最大宽度,
 2. 可以采用哈希表实现,哈希表中记录当前结点与所在层数的对应关系,规定头节点所在的层为第13. 如果所在的层数与当前统计宽度的层数相同,宽度就加14. 如果不相同,则要更新当前最大宽度、并将统计宽度的层数加1,表示接下来要统计下面一层的宽度

代码

class Solution {
public:
    int getMaxWdith(TreeNode* root) {
        if(root == nullptr)
        	return 0;
        queue<TreeNode*>que ;
        que.push(root);
		unordered_map<TreeNode*, int>hash;
        hash[root] = 1; //表示root结点对应的层为1
        int curlevel = 1; //要统计宽度的层数
        int curCounts = 0; // curlevel 统计得到的数量
        int maxWidth = -1; //初始化maxwidth = -1
        while(!que.empty()){
        	TreeNode*temp = que.front();
            que.pop();
            if(hash[temp] == curlevel){
            	curCounts++;
            }
            else{
            	maxWidth = max(maxWidth, curCounts);
            	curCounts = 0;
            	curlevel++;
            }
            if(temp->left != nullptr){
            	que.push(temp->left);
            	hash[temp->left] = curlevel+1;
            }
                
             if(temp->right != nullptr){
             	hash[temp->right] = curlevel+1;
                que.push(temp->right); 
                }
        }
            
         return maxWidth;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值