AcWing 44. 分行从上往下打印二叉树(计数法+标记法)

首先,我们要知道一件事。那就是:在用辅助队列进行二叉树层次遍历时,辅助队列中的所有节点在层次上要么均来自同一层,要么来自相邻两层。而且对于后者的情况,辅助队列中从队头到队尾的所有节点,前半部分节点所在层数距离根节点较近,而后半部分则较远

因此,本题的解题关键就在于如何正确地区分这两部分。可以想到的方法有两种。第一种是设置两个计数器,分别记录辅助队列中不同层中节点的个数并且动态维护。另一种则是在出现分层时及时地向辅助队列中插入特殊的标记用来提醒程序换行打印。这两种方法各有难度,前者是如何进行动态维护,后者则是如何判断插入标记的时机。

另外,由于本题仍然是属于层次遍历的问题。因此以下两个方法的代码均是在层次遍历的模板上修改而来的。

1.计数器法

我们将辅助队列中的节点从前往后分为“当前层”和“下一层”,分别设置两个计数器记录节点数。出队时当前层计数器自减,入队时下一层计数器自增。当当前层计数器变为0时,说明当前层节点已经被完全遍历,需要换行。此时只需将下一层计数器的值赋值给当前计数器,然后再将下一层计数器清零即可。

具体代码如下:

/**
 * 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>> printFromTopToBottom(TreeNode* root) {
        vector<vector<int>> ans;
        if(!root) return ans;
        queue<TreeNode *> q;
        q.push(root);
        int cur_level = 1, next_level = 0; //记录当前层及下一层的节点个数
        vector<int> temp; //存放当前层的打印结果
        while(!q.empty()){
            TreeNode *p = q.front();
            q.pop();
            temp.push_back(p -> val);
            cur_level--;
            if(p -> left){
                q.push(p -> left);
                next_level++;
            }
            if(p -> right){
                q.push(p -> right);
                next_level++;
            }
            if(!cur_level){ //辅助队列中当前层计数器为0说明要换行
                ans.push_back(temp);
                temp.clear();
                cur_level = next_level;
                next_level = 0;
            }
        }
        return ans;
    }
};

2.标记法

我们可以使用空节点NULL来作为标记以分割在辅助队列中的不同层的节点。当队头节点为空时,说明当前层已经遍历完毕,需要换行。此时如果队列非空,则在队尾再插入一个NULL用来作为分割标记。注意:必须要先判断队列是否为空,否则在遍历结束时程序会陷入不断向辅助队列中插入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>> printFromTopToBottom(TreeNode* root) {
        vector<vector<int>> ans;
        if(!root) return ans;
        queue<TreeNode *> q;
        q.push(root);
        q.push(NULL); //第一层只有一个节点,故直接插入一个标记
        vector<int> temp;
        while(!q.empty()){
            TreeNode *p = q.front();
            q.pop();
            if(p){
                temp.push_back(p -> val);
                if(p -> left) q.push(p -> left);
                if(p -> right) q.push(p -> right);
            }
            else{ //当前节点是标记说明要换行
                ans.push_back(temp);
                temp.clear();
                if(!q.empty()) q.push(NULL); //这里必须添加if语句,否则的话队列会在最后不停地插入NULL
            }
        }
        return ans;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值