2021-11-14*二叉树* *深度遍历与宽度遍历* *栈* *队列*

目录

二叉树的深度遍历

 三种遍历方法(采用递归实现)

先序:头左右

中序:左头右

后序:左右头

非递归实现:(栈)

先序:

中序:(虽然也是用栈,但是要写一个“全压左”的子函数)

后序:(对前序进行了一点改变,变成先压左再右,并弹出到备用栈里面,打印备用栈)

二叉树的宽度(按层)遍历

宽度遍历用队列(先进先出)

 求一个二叉树的最大宽度

关于栈和队列的知识:

二叉树的深度遍历

深入学习二叉树(一) 二叉树基础 - 简书 (jianshu.com)icon-default.png?t=N7T8https://www.jianshu.com/p/bf73c8d50dc2

 三种遍历方法(采用递归实现)

先序:头左右

/**
 * 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) {}
 * };
 */
class Solution {
public:
void front(TreeNode* root,vector<int >&result){
    if(root==nullptr){return ;}
    result.push_back(root->val);
    front(root->left,result);
    front(root->right,result);
}
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>result;
        front(root,result);
        return result;    }
};

中序:左头右

/**
 * 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) {}
 * };
 */
class Solution {
public:
        void InOrderTraverse(TreeNode* T,vector<int>&a){
            if(T==nullptr){return;}
            InOrderTraverse(T->left,a);
            a.push_back(T->val);
            InOrderTraverse(T->right,a);
        }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>result;
        InOrderTraverse(root,result);
        return result;
    }
};

后序:左右头

/**
 * 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) {}
 * };
 */
class Solution {
public:
void back(TreeNode* root,vector<int>&result){
    if(root==nullptr){return;}
    back(root->left,result);
    back(root->right,result);
    result.push_back(root->val);
}
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int >result;
        back(root,result);
        return result;
    }
};

非递归实现:(栈)

先序:

先把根节点压进去( s.push() )

1:从栈中弹出一个节点( s.pop() )

2:打印(处理)该节点

3:先右后左压入栈(如果有)

4:循环往复。

/**
 * 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) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>result;
        stack<TreeNode*>p;
        p.push(root);
        if(root==nullptr){return result;}
        while(!p.empty()){
            result.push_back(p.top()->val);
            root=p.top();p.pop();
            if(root->right!=nullptr)p.push(root->right);
            if(root->left!=nullptr)p.push(root->left);          
        }
        return result;
    }
};

中序:(虽然也是用栈,但是要写一个“全压左”的子函数)

 树的左边界都压进去,然后弹出并打印(处理),弹出的过程中判断是否存在右节点,如果有将该右节点下属的的子树的左边界都压进去,循环往复。

/**
 * 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) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>result;
        if(root==nullptr){return result;}
        stack<TreeNode*>p;
        TreeNode *head=root;
        while(head!=nullptr){
            p.push(head);
            head=head->left;
        }//将左边界都压入栈内

        while(!p.empty()){
            result.push_back(p.top()->val);
            TreeNode *head2=p.top();
            //写入栈顶并且用head2表示栈顶,防止弹出后找不到
            p.pop();
            if(head2->right!=nullptr){//如果有右子节点的情况下,将右子树的左边界全部压入栈
                TreeNode *youhead=head2->right;
                while(youhead!=nullptr){
                    p.push(youhead);
                    youhead=youhead->left;
                }
            }
        }
        return result;
    }
};

后序:(对前序进行了一点改变,变成先压左再右,并弹出到备用栈里面,打印备用栈)

准备两个栈,先把头节点压到栈1中。

1:弹出该节点并压到栈2里面。

2:往栈1里面先压左再压右(如果有)

3:循环往复

依次打印(处理)弹出栈2里面的节点

/**
 * 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) {}
 * };
 */
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int >result;
        if(root==nullptr){return result;}

        stack<TreeNode*>p;
        stack<TreeNode*>q;
        p.push(root);
        while(!p.empty()){
            q.push(p.top());
            TreeNode *head;
            head=p.top();
            p.pop();
            if(head->left!=nullptr){p.push(head->left);}
            if(head->right!=nullptr){p.push(head->right);}
        }

        while(!q.empty()){
            result.push_back(q.top()->val);
            q.pop();
        }
        return result;
    }
};

二叉树的宽度(按层)遍历

宽度遍历用队列(先进先出)

1)先把头节点放入队列中

2)每次弹出一个,打印

3)对于弹出的节点,先把弹出节点的左节点放入队列、再把其右节点放入队列(没有左右节点就不放)

重复以上三个步骤:

/**
 * 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) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>result;
        if(root==nullptr){return result;}
        queue<TreeNode*>p;//宽度遍历用队列
        p.push(root);
        while(!p.empty()){
            result.push_back(p.front()->val);
            TreeNode *head=p.front();
            p.pop();
            if(head->left!=nullptr){p.push(head->left);}
            if(head->right!=nullptr){p.push(head->right);}
        }
        return result;
    }
};

 求一个二叉树的最大宽度

思路,在宽度遍历的基础上进行改进:

curLevel:记录当前Node所在层数
curWidth:记录当前层的宽度
maxWidth:记录全局最大层的宽度 

1、新增一个HashMap,用于记录当前Node属于哪一层
2、每次添加Node进队列时,记录当前Node所在层次
3、每次poll出一个Node时,在HashMap中获取它属于哪一层,如果属于当前层,curWidth++。反之 maxWidth = Math.max(maxWidth, curWidth) , curLevel++

以下列题目为例:

102. 二叉树的层序遍历 - 力扣(LeetCode) (leetcode-cn.com)icon-default.png?t=N7T8https://leetcode-cn.com/problems/binary-tree-level-order-traversal/

/**
 * 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) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>>result;
        if(root==nullptr){return result;}
        queue<TreeNode*>p;
        p.push(root);
        unordered_map<TreeNode*,int>hashable;
        int x=0;
        hashable[root]=0;//根位于第0层;
        result.push_back({});
        while(!p.empty()){
            if( hashable[p.front()] !=x ){result.push_back({});}
//判断当前待处理的头元素的层数是否和上一个被处理后踢出队列的头元素的层数相等。
//如果不相等,则意味着来到了新的一层,需要将结果向量增加一个维,以准备写入新的一层的元素。
            x=hashable[p.front()];//表示当前头元素的层数
            result[x].push_back(p.front()->val);
            TreeNode *head;
            head=p.front();;
            p.pop();
            if(head->left!=nullptr){p.push(head->left);hashable[head->left]=x+1;}
            if(head->right!=nullptr){p.push(head->right);hashable[head->right]=x+1;}
        }
        return result;
    }
};

判断当前待处理的头元素的层数是否和上一个被处理后踢出队列的头元素的层数相等。如果不相等,则意味着来到了新的一层,需要将结果向量增加一个维,以准备写入新的一层的元素。

关于栈和队列的知识:

定义栈:stack<数据类型:可以是int、TreeNode*等>名称;

压:p.push(被压元素);

弹:p.pop();                弹出栈顶的元素

p.empty()                如果栈中元素个数为0返回true,栈不为空返回false

p.top()                返回栈顶部的元素

p.size()                返回中元素的个数

定义队列:queue<数据类型:可以是int、TreeNode*等>名称;

压:q.push(被压元素);

弹:q.pop();                弹出队列头部的元素

q.empty()                如果栈中元素个数为0返回true,栈不为空返回false

q.front()                返回队列头部的元素

q.size()                      返回队列元素的个数

C++数据结构——栈_GeekZW的博客-CSDN博客_c++栈icon-default.png?t=N7T8https://blog.csdn.net/zichen_ziqi/article/details/80807989C++数据结构——队列_GeekZW的博客-CSDN博客_c++队列icon-default.png?t=N7T8https://blog.csdn.net/zichen_ziqi/article/details/80819939

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值