zoukankan      html  css  js  c++  java
  • 32 从上到下打印二叉树(举例让抽象问题具体化)

    题目一描述:不分行从上到下打印二叉树,即树的广度优先遍历

    从上往下打印出二叉树的每个节点,同层节点从左至右打印。(不分行)

    测试用例:

    功能测试(完全二叉树;所有节点只有左/右子树的二叉树)

    特殊输入测试(二叉树的根节点为nullptr;只有一个节点的二叉树

    解题思路:

     1)使用队列:

    每次打印一个节点时,如果该节点有子节点,则把该节点的子节点放到一个队列的末尾。接下来到队列的头部取出最早进入队列的节点,重复前面的打印操作,直至队列中所有的节点都被打印出来。

    //使用双向队列,用单向的队列就可以
    /* 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> result; if(root==nullptr) return result; deque<TreeNode*> saveNodes; saveNodes.push_back(root); //error: while(saveNodes) saveNodes没有对应的bool值 while(!saveNodes.empty()){ //队列非空的时候 TreeNode* currNode = saveNodes.front(); saveNodes.pop_front(); result.push_back(currNode->val); if(currNode->left) //右子树非空,追加在队列的后面 saveNodes.push_back(currNode->left); if(currNode->right) //左子树非空,追加在队列的后面 saveNodes.push_back(currNode->right); } return result; } };
    //单向队列
    class Solution { public: vector<int> PrintFromTopToBottom(TreeNode* root) { vector<int> result; if(root==nullptr) return result; queue<TreeNode*> saveNodes; saveNodes.push(root); //error: while(saveNodes) saveNodes没有对应的bool值 while(!saveNodes.empty()){ //队列非空的时候 TreeNode* currNode = saveNodes.front(); saveNodes.pop(); result.push_back(currNode->val); if(currNode->left) //右子树非空,追加在队列的后面 saveNodes.push(currNode->left); if(currNode->right) //左子树非空,追加在队列的后面 saveNodes.push(currNode->right); } return result; } };  


    题目二描述: 分行从上到下打印二叉树(把二叉树打印成多行)

    从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

    解题思路:

    1)为了分行打印,增加两个变量:一个变量表示在当前层中还没有打印的节点数;另一个变量表示下一层节点的数目。

    class Solution {
    public:
            vector<vector<int> > Print(TreeNode* pRoot) {
                vector<vector<int> > result;
                if(pRoot==nullptr)
                    return result;
                vector<int> row;
                queue<TreeNode*> treeNodes;
                treeNodes.push(pRoot);
                int toBePrint = 1; //初始化为1,根节点
                int nextLevel = 0;
                
                while(!treeNodes.empty()){
                    TreeNode* pNode = treeNodes.front();
                    treeNodes.pop();
                    row.push_back(pNode->val); 
                    toBePrint--;
                    
                    if(pNode->left){
                        treeNodes.push(pNode->left);
                        nextLevel++;
                    }
                    
                    if(pNode->right){
                        treeNodes.push(pNode->right);
                        nextLevel++;
                    }
                    
                    if(toBePrint==0){
                        result.push_back(row);
                        //删除行!!
                        vector<int>().swap(row);
                        toBePrint = nextLevel;
                        nextLevel = 0;
                    }
                }
                return result;
            }
    }; 

    错误的写法:

    class Solution {
    public:
            vector<vector<int> > Print(TreeNode* pRoot) {
                vector<vector<int> > result;
                if(pRoot==nullptr)
                    return result;
                
                int row = 0;
                queue<TreeNode*> treeNodes;
                treeNodes.push(pRoot);
                int toBePrint = 1; //初始化为1,根节点
                int nextLevel = 0;
                
                while(!treeNodes.empty()){
                    TreeNode* pNode = treeNodes.front();
                    treeNodes.pop();
                    (result[row]).push_back(pNode->val); //error: 不能这样使用 result[row].push_back
                    toBePrint--;
                    
                    if(pNode->left){
                        treeNodes.push(pNode->left);
                        nextLevel++;
                    }
                    
                    if(pNode->right){
                        treeNodes.push(pNode->right);
                        nextLevel++;
                    }
                    
                    if(toBePrint==0){
                        row++;
                        toBePrint = nextLevel;
                        nextLevel = 0;
                    }
                }
                return result;
            }
    };

    错误原因:

    vector<vector<int> > result(10); (result[row]).push_back(pNode->val);   //可以使用 result[row]

    但是若初始化时,没有指定vector的大小,则不能使用result[row],属于数组越界,非法访问。这种情况只能用push_back在尾部追加。

    2)用队列的长度来记录每层的节点数

    class Solution {
    public:
            vector<vector<int> > Print(TreeNode* pRoot) {
                vector<vector<int> > result;
                if(pRoot == NULL) return result;
     
                queue<TreeNode*> q;
                q.push(pRoot);
     
                while(!q.empty())
                { //每一个while循环打印一行
                    int index = 0;  //用于遍历每行元素
                    int numNodes = q.size();  //当前行的元素数==队列里的元素数
                    
                    vector<int> row; //用于存储每行的元素。
                    
                    while(index++ < numNodes)
                    {
                        TreeNode *currNode = q.front();
                        q.pop();
                        row.push_back(currNode->val);
                        if(currNode->left) q.push(currNode->left);
                        if(currNode->right) q.push(currNode->right);
                    }
                    result.push_back(row);
                }
                return result;
            }
    };
    


    题目二描述: 按之字形打印二叉树

    请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

    解题思路:

    1)与分行打印树思路相同,只不过在偶数行时,将每行vector<int>倒序存入

    class Solution {
    public:
        vector<vector<int> > Print(TreeNode* pRoot) {
            vector<vector<int> > result;
            if(pRoot==nullptr)
                return result;
            
            queue<TreeNode*> treeNodes;
            treeNodes.push(pRoot);
            int count=1; //记录单行还是双行
            while(!treeNodes.empty()){
                vector<int> row; //用于存每行的元素 //每次循环都会被清零
                int numNodesInRow = treeNodes.size();  //每行元素的个数
                while(numNodesInRow--){
                    TreeNode* curr = treeNodes.front(); //访问
                    treeNodes.pop(); //删除
                    row.push_back(curr->val);  //读取当前节点的元素
                    
                    if(curr->left)
                        treeNodes.push(curr->left);
                    if(curr->right)
                        treeNodes.push(curr->right);
                }
    
                if((count & 0x1)==1){//第几行
                    result.push_back(row);
                }else{
                    vector<int> inverseRow(row.rbegin(),row.rend());
                    result.push_back(inverseRow);
                }
                count++;
            }
            
            return result;
        }
        
    };
    
     * 大家的实现很多都是将每层的数据存进ArrayList中,偶数层时进行reverse操作,
     * 在海量数据时,这样效率太低了。
     * (我有一次面试,算法考的就是之字形打印二叉树,用了reverse,
     * 直接被鄙视了,面试官说海量数据时效率根本就不行。

    2)使用两个栈:(不必将每层的数据存进queue中,偶数层时进行reverse操作,直接按打印顺序存入

    在打印某一层节点时,把下一层子节点保存到相应的栈中。如果当前打印的时奇数层,从左到右打印,并先保存左子节点再保存右子节点到第一个栈中(奇数栈);如果当前打印的是偶数层,从右向左打印,并先保存右子节点再保存左子节点到第二个栈中(偶数栈)。  

    //实现1
    class Solution { public: vector<vector<int> > Print(TreeNode* pRoot) { vector<vector<int> > result; if(pRoot==nullptr) return result; //使用两个栈存储 stack<TreeNode*> oddRow,evenRow; vector<int> row; //存储每行的遍历元素 int numRow = 1; evenRow.push(pRoot); while(oddRow.size() || evenRow.size()){//两个栈有一个非空时,进入循环 if((numRow & 0x1)==1){ //奇数行 从左到右 且先遍历左子树 while(evenRow.size()){ TreeNode* pNode = evenRow.top(); evenRow.pop(); row.push_back(pNode->val); if(pNode->left) oddRow.push(pNode->left); if(pNode->right) oddRow.push(pNode->right); } }else{ //偶数行 从右到左 且先遍历右子树 while(oddRow.size()){ TreeNode* pNode = oddRow.top(); oddRow.pop(); row.push_back(pNode->val); if(pNode->right) evenRow.push(pNode->right); if(pNode->left) evenRow.push(pNode->left); } } //遍历完一行 result.push_back(row); vector<int>().swap(row); //将row清空,便于下一行的存储 numRow++; } return result; } };
    //实现2
    class Solution {
    public:
        vector<vector<int> > Print(TreeNode* pRoot) {
            vector<vector<int> > result;
            if(pRoot==nullptr)
                return result;
            //使用两个栈存储
            stack<TreeNode*> levels[2];
            vector<int> row; //存储每行的遍历元素
            int current = 0;
            int next = 1;
            
            levels[current].push(pRoot);  //
            while(levels[0].size() || levels[1].size() ){
                TreeNode* pNode = levels[current].top(); //读取当前节点
                levels[current].pop();  //删除读取过的节点
                
                row.push_back(pNode->val);
                
                if(current==0){ //奇数行,先存左子树
                    if(pNode->left)
                        levels[next].push(pNode->left);
                    if(pNode->right)
                        levels[next].push(pNode->right);
                }else{ //偶数行,先存右子树
                    if(pNode->right)
                        levels[next].push(pNode->right);
                    if(pNode->left)
                        levels[next].push(pNode->left);
                }
                
                if(levels[current].empty()){ //当前栈为空时,换栈
                    result.push_back(row);
                    vector<int> ().swap(row); //清空row
                    current = 1 - current;  //交换栈
                    next = 1 - next;
                }
            }
            return result;
        }
        
    };
    

      

      

      

      

  • 相关阅读:
    vue-router 实践
    修改vue中<router-link>的默认样式
    JSON.parse() 与 JSON.stringify() 的区别
    JS 中的异步操作
    CSS3 box-sizing:border-box的好处
    element ui 栅格布局
    css overflow用法
    koa中间件机制
    canvas 入门
    前端面试题:淘宝首页用了多少种标签
  • 原文地址:https://www.cnblogs.com/GuoXinxin/p/10449582.html
Copyright © 2011-2022 走看看