二叉树经典算法题整理

学而时习之。

二叉树遍历系列:
  1. 非递归实现二叉树前序遍历。
    思想: 弄一个栈,每次弹出的,就先保存好这个弹出的结果。然后先右后左子树的根节点压入堆栈。
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> r;
        
        if (root==nullptr) return r;

        stack<TreeNode*> q;


        q.push(root);

        while (!q.empty())
        {
            TreeNode* tmp = q.top();
            q.pop();

            r.push_back(tmp->val);

           
            if (tmp->right) q.push(tmp->right);
            if (tmp->left) q.push(tmp->left);
        }

        
        return r;

    }
    
};
  1. 二叉树中序遍历。
    思想:注意到,由于是中序遍历,所以根节点要弹出两次,第一次时,继续压入右左子树;第二次时,保存结点的值。核心是 弄个pair保存访问次数。
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> r;
        
        if (!root) return r;

        stack<pair<TreeNode*, int> > s;

        s.push(make_pair(root, 0));


        while (!s.empty())
        {
            pair<TreeNode*, int> tmp=s.top();
            s.pop();

            if (tmp.second==1 || ((tmp.first)->right==nullptr && (tmp.first)->left==nullptr)    )
                {r.push_back((tmp.first)->val);}

            else if(tmp.second==0)
            {        
                if ((tmp.first)->right) s.push(make_pair((tmp.first)->right,0));

                tmp.second +=1;
                s.push(tmp);
                
                if ((tmp.first)->left) s.push(make_pair((tmp.first)->left,0));
            }
        }

        return r;



    }

};
  1. 二叉树后序遍历。
    思想:与中序是一样的。只不过第一次弹出时,压入堆栈的顺序不一样而已,先自己,然后右边,再左边。
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> r;
        if (root==nullptr) return r;

        stack<pair<TreeNode*, int>> s;

        s.push(make_pair(root, 0));

        while (!s.empty())
        {
            pair<TreeNode*, int> tmp = s.top();
            s.pop();

            if (tmp.second==1 || ((tmp.first)->left==nullptr && (tmp.first)->right==nullptr ))
                r.push_back((tmp.first)->val);

            else if(tmp.second==0)
            {
                tmp.second++;
                s.push(tmp);
                
                if ((tmp.first)->right) s.push(make_pair((tmp.first)->right, 0));
                
                if ((tmp.first)->left) s.push(make_pair((tmp.first)->left, 0));

            }
        }
        return r;
    }
};
二叉树重建系列:
  1. 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
    思想:利用前序扫描,在中序中出现的点,左边是左子树而右边是右子树。利用递归法解决,
class Solution {
    public:
     TreeNode *reConstructBinaryTree(vector<int> pre,vector<int> in) {
        TreeNode* root=reConstructBinaryTree(pre,0,pre.size()-1,in,0,in.size()-1);
        return root;
    }
    //前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
    private:
     TreeNode *reConstructBinaryTree(vector<int> pre,int startPre,int endPre,vector<int> in,int startIn,int endIn) {
         
        if(startPre>endPre||startIn>endIn)
            return nullptr;
        TreeNode *root=new TreeNode(pre[startPre]);
         
        for(int i=startIn;i<=endIn;i++)
            if(in[i]==pre[startPre]){
                root->left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
                root->right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn);
                      break;
            }
                 
        return root;
    }
};
  1. 输入某二叉树的中序遍历和后序遍历的结果,请重建出该二叉树。假设输入的中序遍历和后序遍历的结果中都不含重复的数字。
    思想:后序遍历的最后一个结点是根节点,可在中序遍历中找到根节点,左边为左子树,右边为右子树。然后在后序遍历中逆向查找,从而可以得到子树的根节点,递归可得。
class Solution {
    public:
     TreeNode *reConstructBinaryTree(vector<int> pre,vector<int> in) {
        TreeNode* root=reConstructBinaryTree(pre,0,pre.size()-1,in,0,in.size()-1);
        return root;
    }
    
    private:
     TreeNode *reConstructBinaryTree(vector<int> aft,int startAft,int endAft,vector<int> in,int startIn,int endIn) {
         
        if(startAft>endAft||startIn>endIn)
            return nullptr;
        TreeNode *root=new TreeNode(aft[endAft]);
         //和前序的差别就在于从后获得根节点
        for(int i=startIn;i<=endIn;i++)
            if(in[i]==aft[startAft]){
                root->left=reConstructBinaryTree(aft,startAft,startAft+i-startIn,in,startIn,i-1);
                root->right=reConstructBinaryTree(aft,i-startIn+startAft+1,endAft,in,i+1,endIn);
                      break;
                      //递归 求取左右子树的序列
            }
                 
        return root;
    }
};
  1. 前序和后序不能保证唯一的树结构。

  2. 二叉树的层次遍历。
    思路:用两个队列,交替记录每层的结点,外层用while实现即可。注意for语句中第一句是初始化,后续不会再执行。

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> p, q;

        vector<vector<int>> r;

        if (root==nullptr) return r;

        p.push(root);
        while (!p.empty()||!q.empty())
        {
            vector<int> t1 ,t2;
            if (!p.empty())
            {
                for (TreeNode *tmp = p.front();!p.empty();p.pop())
                {
                    tmp = p.front();
                    if (tmp->left) q.push(tmp->left);
                    if (tmp->right) q.push(tmp->right);
                    t1.push_back(tmp->val);
                }
                    r.push_back(t1);
            }
            
            if (!q.empty()){
               for (TreeNode *tmp = q.front();!q.empty();q.pop())
                {
                    tmp = q.front();
                    if (tmp->left) p.push(tmp->left);
                    if (tmp->right) p.push(tmp->right);
                    t2.push_back(tmp->val);
                }

                r.push_back(t2);
            }
                }

        return r;
    }
};

4.2 二叉树的自底向上层次遍历。
可以也用队列,这里用bfs,核心是采用level计量层数,然后反向插入。

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> r;
        helper(r, root,0);
        return r;

    }

    void helper(vector<vector<int>> &r, TreeNode *p1, int level)
    {
            if (p1==nullptr) return;

            if (level>=r.size()) {vector<int> tmp;r.insert(r.begin(), tmp);}
     
            r[r.size()-1-level].push_back(p1->val);
            helper(r, p1->left, level+1);
            helper(r, p1->right, level+1);

            
    }
};
  1. 二叉树的锯齿形遍历。
    思路:和层次遍历差不多,只不过换成栈,然后在第二个栈先推入右子树,再推入左子树。
class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        stack<TreeNode*> p, q;

        vector<vector<int>> r;

        if (root==nullptr) return r;

        p.push(root);
        while (!p.empty()||!q.empty())
        {
            vector<int> t1 ,t2;
            if (!p.empty())
            {
                for (TreeNode *tmp = p.top();!p.empty();p.pop())
                {
                    tmp = p.top();
                    
                    
                    if (tmp->left) q.push(tmp->left);
                    if (tmp->right) q.push(tmp->right);
                    t1.push_back(tmp->val);
                }
                    r.push_back(t1);
            }
            
            if (!q.empty()){
               for (TreeNode *tmp = q.top();!q.empty();q.pop())
                {
                    tmp = q.top();
                   
                    if (tmp->right) p.push(tmp->right);
                     if (tmp->left) p.push(tmp->left);
                    t2.push_back(tmp->val);
                }

                r.push_back(t2);
            }
                }

        return r;
    }
};
  1. 二叉搜索树与双向链表
    思路:中序遍历的思想。对于当前结点root,如果空,返回nullptr;否则对左右子树求双向链表头结点。对于左子树求得的点,向右走到末尾,然后指向root,root->left = 此点;对于右子树,直接指向即可。递归,最后返回最左结点作为双向链表的头结点。
class Solution {
public:
TreeNode* find(TreeNode* root)
{
    if (root==NULL) return NULL;
     TreeNode*l = root;
    while (l->right!=NULL)
        l=l->right;
   
    return l;
}
    
TreeNode* find2(TreeNode* root)
{
    if (root==NULL) return NULL;
    TreeNode*l = root;
    while (l->left!=NULL)
        l=l->left;
   
    return l;
}

TreeNode* Convert(TreeNode* pRootOfTree)
{
    TreeNode* t1, *t2=pRootOfTree;
    if (pRootOfTree==NULL) return NULL;
    while (t2->left!=NULL) t2=t2->left;
    
    if (pRootOfTree->left!=NULL)
    {
        
        TreeNode *tmp=pRootOfTree->left;
        TreeNode*s1=Convert(tmp);
        t1=find(s1);
        
        pRootOfTree->left=t1;
        t1->right=pRootOfTree;
        
        
    }
    if (pRootOfTree->right!=NULL)
    {
        TreeNode* tmp=pRootOfTree->right;
        TreeNode* s1=Convert(tmp);
       
        
        pRootOfTree->right=s1;
        s1->left=pRootOfTree;
    }
        
    
        return t2;
}

};
二叉树判别系列:
  1. 给定一个二叉树,判断它是否是高度平衡的二叉树。(左右两个子树的高度差绝对值不超过1)。
    思路: 判断高度平衡,自然需要得到高度的函数。除了得到高度之外,要考虑到如果子树不是平衡树,那么本身也不是平衡树了,用一个状态*-1*来表示。
class Solution {
public:
    bool isBalanced(TreeNode* root) {
        return getDepth(root)!=-1;
    }

    int getDepth(TreeNode *root)
    {
        if (root==nullptr) return 0;
        int lh = getDepth(root->left), rh = getDepth(root->right);
        if (lh == -1 || rh == -1 || abs(lh-rh)>1)
            return -1;
        return max(lh,rh)+1;
    }
};
  1. 给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。
    思路: 先要设计一个判断是否相同的函数。随后用这个函数判别当前是否相同,否则递归到左子树和右子树。注意边界条件,nullptr。
class Solution {
public:
 bool isSametree(TreeNode *a1, TreeNode *a2)
    {
        if (a1==nullptr&&a2!=nullptr) return false;
        if (a2==nullptr&&a1!=nullptr) return false;
        if (a1==nullptr&& a2==nullptr) return true;
        return (a1->val==a2->val) && isSametree(a1->left, a2->left) && isSametree(a1->right, a2->right);

    }
    bool isSubtree(TreeNode* s, TreeNode* t) {
         if(s==NULL && t!=NULL) return 0;
    if(s!=NULL && t==NULL) return 0;


        return (isSametree(s,t) || isSubtree(s->left,t) || isSubtree(s->right, t));//为啥这不能都用isSame?因为isSame不能再往下递归。
    }
};

你可能感兴趣的:(数据结构)