剑指Offer: 二叉树

二叉树的下一个结点


给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。


找出各种情况:
1、右孩子存在。寻找右子树的最左节点。
2、右孩子不存在,该节点为父节点的左子树,返回父节点。
3、右孩子不存在,该节点为父节点的右子树。若在右子树,则其父节点也是右孩子节点,跳出结束;若在左子树,则父节点为左孩子,追溯返回根节点。
4、右孩子不存在,该节点为根节点,返回nullptr。


class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(!pNode)  return pNode;
        if(pNode->right){
            pNode=pNode->right;
            while(pNode->left){
                pNode=pNode->left;
            }
            return pNode;
        }
        else{
            //root without next
            if(!pNode->next) return nullptr;
            if(pNode->next->left==pNode){//left
                return pNode->next;
            }
            else{//right
                TreeLinkNode *temp=pNode->next;//father node
                if(temp->next){//not root
                    pNode=temp->next;
                    if(pNode->left==temp){
                        while(pNode->next){
                            pNode=pNode->next;
                        }
                        return pNode;
                    }
                }
            }
        }
        return nullptr;
    }
};

对称的二叉树


请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。


非递归实现:
1、进入根节点左子树,先序遍历,从左到右;进入根节点右子树,先序遍历,从右到左。
2、中间及时判断对应节点是否相等,节点的孩子存在情况。


class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot)
    {
        if(!pRoot)  return true;
        stack<TreeNode*> st1,st2;
        if(pRoot->left&&pRoot->right){
            st1.push(pRoot->left);
            st2.push(pRoot->right);
            //左子树left father right
            //右子树right father left
            while((!st1.empty())&&(!st2.empty())){
                TreeNode *cur1=st1.top(),*cur2=st2.top();
                st1.pop();
                st2.pop();
                if(cur1->val!=cur2->val){
                    return false;
                }
                if(cur1->right&&cur2->left){
                    st1.push(cur1->right);
                    st2.push(cur2->left);
                }
                else if(cur1->right||cur2->left){
                    return false;
                }
                if(cur1->left&&cur2->right){
                    st1.push(cur1->left);
                    st2.push(cur2->right);
                }  
                else if(cur1->left||cur2->right){
                    return false;
                }
            }
        }
        else if(pRoot->left||pRoot->right){
            return false;
        }
        return true;
    }

};

按之字形顺序打印二叉树


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


1、从做开始的时候先保存左孩子,再保存右孩子。下一层将读取从右开始,此时先保存右孩子,再保存左孩子。
2、下一层将从做到右。
3、记得将v及时clear


class Solution {
public:
    //BFS
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int>> res{};
        if(!pRoot)  return res;
        stack<TreeNode*> st1,st2;
        st1.push(pRoot);
        while((!st1.empty())||(!st2.empty())){//exit only all empty
            vector<int> v;
            while(!st1.empty()){//st1 is not empty:left to right
                TreeNode *cur=st1.top();
                st1.pop();
                v.push_back(cur->val);
                if(cur->left){
                    st2.push(cur->left);
                }
                if(cur->right){
                    st2.push(cur->right);
                }
            }
            res.push_back(v);
            v.clear();
            while(!st2.empty()){//st2 is not empty:right to left
                TreeNode *cur=st2.top();
                st2.pop();
                v.push_back(cur->val);
                if(cur->right){
                    st1.push(cur->right);
                }
                if(cur->left){
                    st1.push(cur->left);
                }
            }
            if(!v.empty())  res.push_back(v);
        }
        return res;
    }
};

把二叉树打印成多行


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


1、队列:queue,front()取头,pop()删除头。
2、从左到右放入队列,队列FIFO,下一层将也是从左到右读取。
3、对于多行保存,设置三个变量即可。
4、学会的新的写法。之前我还几个栈换来换去,看来不一定要用栈解决问题的。next可以不要,直接q.size()。


class Solution {
public:
        vector<vector<int> > Print(TreeNode* pRoot) {
            //BFS
            vector<vector<int>> res{};
            if(!pRoot)  return res;
            queue<TreeNode*> q;
            q.push(pRoot);
            int has{1},i{0},next{0};//本层节点数,迭代,下层节点数
            while(!q.empty()){
                vector<int> v;
                for(next=0,i=0;i<has;++i){
                    TreeNode *cur=q.front();
                    q.pop();//删除头元素
                    v.push_back(cur->val);
                    if(cur->left){
                        q.push(cur->left);
                        ++next;
                    }  
                    if(cur->right){
                        q.push(cur->right);
                        ++next;
                    }  
                }
                has=next;
                res.push_back(v);              
            }
            return res;
        }
};

序列化二叉树


请实现两个函数,分别用来序列化和反序列化二叉树


BFS:
1、层序遍历,将每个节点的孩子表示出来。
2、对于编码,val的表示,字符串表示在字符流中,在解码的时候我们要根据需求编写解码函数,string to int函数编写或调用。
3、对于内存,传输确定即可。在下面第二个改变程序体现。
4、反序列化,我们的一层节点数必定是2的幂。
注:
1、c_str()函数,将string转换为char ,要注意如果该string是某个函数局部变量,而我们要获取其char,这样我们要strcpy!
2、append()函数使用。


class Solution {
public:
    char* Serialize(TreeNode *root) {   
        if(!root)   return nullptr;
        queue<TreeNode*> qNode;
        qNode.push(root);
        int has{1},i{0};
        string res{""};
        while(!qNode.empty()){
            for(i=0;i<has;++i){
                TreeNode *cur=qNode.front();
                qNode.pop();
                if(cur){
                    res+=to_string(cur->val)+',';
                    qNode.push(cur->left);
                    qNode.push(cur->right);
                }  
                else    res.append("#");
            }
            has=qNode.size();
        }
        int len=res.length();
        char *cres=new char[len+1];//'\0'
        strcpy(cres,res.c_str());//能够保存
        return cres;
    }
    TreeNode* Deserialize(char *str) {
        if(!str)    return nullptr;
        queue<TreeNode*> qNode;
        char *cp=str;
        TreeNode *root=new TreeNode(decode(cp));
        ++cp;
        qNode.push(root);
        int has{1};
        while(*cp!='\0'&&(!qNode.empty())){
            for( int i=0;i<has;++i){
                TreeNode *cur=qNode.front();
                qNode.pop();
                if(*cp!='#'){
                    cur->left=new TreeNode(decode(cp));
                    qNode.push(cur->left);
                }
                ++cp;
                if(*cp!='#'){
                    cur->right=new TreeNode(decode(cp));
                    qNode.push(cur->right);
                }
                ++cp;
            }
            has=qNode.size();
        }
        delete [] str;
        return root;
    } 
private:

    int decode(char* &cp){
        int num{0};
        while(*cp!=','){
            num=10*num+*cp-48;
            ++cp;
        }
        return num;
    }
};

既然是要传输数据,我们肯定确定了每次包的大小,还有,既然是字符流,我们尽量用char*,以除去结果转换的耗时,及缓存的使用。反序列化与解码函数相同。
此处使用strcpy()函数不易出错,因为本来就有字符串转换函数。


#define N 1024
class Solution {
public:
    char* Serialize(TreeNode *root) {   
        if(!root)   return nullptr;
        queue<TreeNode*> qNode;
        qNode.push(root);
        int has{1},i{0};
        char *cres=new char[N],*cp=cres;
        while(!qNode.empty()){
            for(i=0;i<has;++i){
                TreeNode *cur=qNode.front();
                qNode.pop();
                if(cur){
                    string temp=to_string(cur->val)+",";
                    strcpy(cp,temp.c_str());
                    cp+=temp.length();
                    qNode.push(cur->left);
                    qNode.push(cur->right);
                }  
                else{
                    *cp='#';
                    ++cp;
                }   
            }
            has=qNode.size();
        }
        *cp='#';
        return cres;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值