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

  

  

  

  

原文地址:https://www.cnblogs.com/GuoXinxin/p/10449582.html