剑指offer(1/19)

二叉树的下一个结点

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

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        if(pNode == null){
            return null;
        }
        if(pNode.right != null){
            pNode = pNode.right;
            while(pNode.left != null){
                pNode = pNode.left;
            }
            return pNode;
        }
        while(pNode.next != null){
            if(pNode.next.left == pNode){
                return pNode.next;
            }
            pNode = pNode.next;
        }
        return null;
    }
}
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* node)
    {
        if(node==NULL) return NULL;
        if(node->right!=NULL){    //如果有右子树,则找右子树的最左节点
            node = node->right;
            while(node->left!=NULL) node = node->left;
            return node;
        }
        while(node->next!=NULL){ //没右子树,则找第一个当前节点是父节点左孩子的节点
            if(node->next->left==node) return node->next;
            node = node->next;
        }
        return NULL;   //退到了根节点仍没找到,则返回null
    }
};

对称的二叉树

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

public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        if(pRoot == null) return true;
        return isSame(pRoot.left,pRoot.right);
    }
    boolean isSame(TreeNode r1,TreeNode r2){
        if(r1 == null && r2 == null)
            return true;
        if(r1 == null || r2 == null)
            return false;
        if(r1.val != r2.val)
            return false;
        return isSame(r1.left,r2.right) && isSame(r1.right,r2.left);
    }
}
class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot)
    {
        if(pRoot == NULL)
            return true;
        return isSame(pRoot->left,pRoot->right);
    }
    bool isSame(TreeNode* r1,TreeNode* r2){
        if(r1 == NULL && r2 == NULL) return true;
        if(r1 == NULL || r2 == NULL) return false;
        if(r1->val != r2->val)
            return false;
        return isSame(r1->left,r2->right) && isSame(r1->right,r2->left);
    }
};

之字型打印二叉树

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

*/
/**
 * 大家的实现很多都是将每层的数据存进ArrayList中,偶数层时进行reverse操作,
 * 在海量数据时,这样效率太低了。
 * (我有一次面试,算法考的就是之字形打印二叉树,用了reverse,
 * 直接被鄙视了,面试官说海量数据时效率根本就不行。)
 *
 * 下面的实现:不必将每层的数据存进ArrayList中,偶数层时进行reverse操作,直接按打印顺序存入
 * 思路:利用Java中的LinkedList的底层实现是双向链表的特点。
 *     1)可用做队列,实现树的层次遍历
 *     2)可双向遍历,奇数层时从前向后遍历,偶数层时从后向前遍历
 */
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
    ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
    if (pRoot == null) {
        return ret;
    }
    ArrayList<Integer> list = new ArrayList<>();
    LinkedList<TreeNode> queue = new LinkedList<>();
    queue.addLast(null);//层分隔符
    queue.addLast(pRoot);
    boolean leftToRight = true;
     
    while (queue.size() != 1) {
        TreeNode node = queue.removeFirst();
        if (node == null) {//到达层分隔符
            Iterator<TreeNode> iter = null;
            if (leftToRight) {
                iter = queue.iterator();//从前往后遍历
            } else {
                iter = queue.descendingIterator();//从后往前遍历
            }
            leftToRight = !leftToRight;
            while (iter.hasNext()) {
                TreeNode temp = (TreeNode)iter.next();
                list.add(temp.val);
            }
            ret.add(new ArrayList<Integer>(list));
            list.clear();
            queue.addLast(null);//添加层分隔符
            continue;//一定要continue
        }
        if (node.left != null) {
            queue.addLast(node.left);
        }
        if (node.right != null) {
            queue.addLast(node.right);
        }
    }
     
    return ret;
    }
}
// public class Solution {
//     private ArrayList<ArrayList<Integer>> result = new  ArrayList<ArrayList<Integer>>();
//     public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
//         if(pRoot == null) return result;
//         ArrayList<TreeNode> parent = new ArrayList<>();
//         parent.add(pRoot);
//         printline(parent, 0);
//         return result;
//     }
     
//     // 树的的结构一般使用的都是递归算来实现的
//     public void printline(ArrayList<TreeNode> nodes, int tim){
//         if(nodes.size() == 0 || nodes == null) return;
//         ArrayList<TreeNode> res = new ArrayList<>();
//         ArrayList<Integer> list = new ArrayList<>();
//         TreeNode temp;
//         for(int i=nodes.size()-1; i>=0; i--){
//             temp = nodes.get(i);
//             list.add(temp.val);
//             if(tim % 2 == 0){
//               if(temp.left != null) res.add(temp.left);
//               if(temp.right != null) res.add(temp.right);    
//             }else{
//                 if(temp.right != null) res.add(temp.right);
//                 if(temp.left != null) res.add(temp.left);
//             }
//         }
//         result.add(list);
//         printline(res, tim+1);
//     }
 
// }
class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int>> res;
        if(!pRoot)return res;
        queue<TreeNode*> que;    //建立个单向队列,用于存放节点
        bool flag=false;     //判断是否为偶数行,flag=false代表奇数行,flag=true代表偶数行
        que.push(pRoot);
        while(que.size()>0){
            vector<int> vec;    //行容器,用于存入当前行输出的结果
            int len=que.size();
            for(int i=0;i<len;i++){
                TreeNode* tmp=que.front();
                vec.push_back(tmp->val);
                que.pop();
                if(tmp->left)que.push(tmp->left);
                if(tmp->right)que.push(tmp->right);
            }
            if(flag) reverse(vec.begin(),vec.end());  //是偶数行就反转顺序
            flag=!flag;     //改变flag的值
            res.push_back(vec);
        }
        return res;
    }
};

层次遍历

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

public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        ArrayList<Integer> list = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        TreeNode temp;
        if(pRoot == null){
            return result;
        }
        queue.offer(pRoot);
        int start = 0, end = 1;
        while(!queue.isEmpty()){
            temp = queue.poll();
            list.add(temp.val);
            start++;
            if(temp.left != null){
                queue.offer(temp.left);
            }
            if(temp.right != null){
                queue.offer(temp.right);
            }
            if(start ==end){
                start = 0;
                end = queue.size();
                result.add(list);
                list = new ArrayList<>();
            }
        }
        return result;
    }
    
}
class Solution {
public:
        vector<vector<int> > Print(TreeNode* pRoot) {
            vector<vector<int> > vec;
            if(pRoot == NULL) return vec;
            queue<TreeNode*> q;
            q.push(pRoot);
            while(!q.empty())
            {
                int lo = 0, hi = q.size();
                vector<int> c;
                while(lo++ < hi)
                {
                    TreeNode *t = q.front();
                    q.pop();
                    c.push_back(t->val);
                    if(t->left) q.push(t->left);
                    if(t->right) q.push(t->right);
                }
                vec.push_back(c);
            }
            return vec;
        }
};

序列化二叉树

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

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。

二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

例如,我们可以把一个只有根节点为1的二叉树序列化为"1,",然后通过自己的函数来解析回这个二叉树

import java.lang.Integer;
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    //使用前序遍历来序列化,遇到null就添加#!,遇到数值就添加!
    String Serialize(TreeNode root) {
        if(root==null)
            return "";
        return helpSerialize(root,new StringBuilder()).toString();
  }
    private StringBuilder helpSerialize(TreeNode node,StringBuilder sb){
        if(node==null) 
            return sb;
        sb.append(node.val).append("!");
        if(node.left!=null){
            helpSerialize(node.left,sb);
        }
        else{
            sb.append("#!");
        }
        if(node.right!=null){
            helpSerialize(node.right,sb);
        }
        else{
            sb.append("#!");
        }
        return sb;
    }
     //1!2!4!#!#!5!#!#!3!6!#!#!7!#!#!

    TreeNode Deserialize(String str) {
       if(str==null || str.length()==0){
           return  null;
       }     
        String[] strs=str.split("!");
        return helpDeserialize(strs);
  }
    private int  index=0;  
    //如果遇到了#表示,知道左边结束了,要开始建立右边了,如果再次遇到了#,表示当前整个左边要结束了要开始右子树
    //124##5##36##7##
    //先将1建立为根节点
    //然后建立左子树,2是这个1的左子节点,4是2的左子节点,1左——》2左-》4
    //然后建立4的左子节点的时候,遇到了#退出建立左子节点的递归,然后来到了建立4的右子树节点,又遇到了#号,退出了4的右子树节点递归
    //这样的话,建立4节点的左右子树都退出了,也退出4的递归,到2的右子树建立,然后字符串到5,建立5节点,2的右-》5(左右退出,和4上面的退出是相同得)
    //然后2的右子树递归退出,到1的右子树建立,建立3为1的右子树节点,然后建立3的左子树节点6,然后遇到##,同上面一样,退出6的左子树节点建立,退出6的右子树节点建立
    //到3的右子树节点7,然后7建立左右子树遇到##,也同样退出
    private TreeNode helpDeserialize(String[] str){
        if(str[index].equals("#")){
            index++;
            return null;
        }
        TreeNode root = new TreeNode(Integer.valueOf(str[index]));
        index++;
        root.left=helpDeserialize(str);
        root.right=helpDeserialize(str);
        return root;
    }
}
class Solution {
public:
    //1.将二叉树转化为字符串序列
    //例如:树:10,6,4,14,12,16 
    //序列化后:00!60!40!#!#!#!14!12!#!#!16!#!#!
    vector<int>s;
    void  Serializevector(TreeNode *root)
    {
        if(root==nullptr)//如果根节点为空,直接存入#和!
        {
            s.push_back('#');//#表示空节点
            s.push_back('!');//!表示一个节点存放完毕
            return;
        }
         vector<int>temp;
        //首先将根节点存入容器temp中,value组成的序列为除以10的模,
        int value=root->val;
        while(value!=0)
        {
            temp.push_back(value%10);
       // temp.push_back(value);
            value=value/10;
        }
        for (int i = temp.size() - 1; i >= 0 ; i--)
        {
            s.push_back( temp[i]);
        }
        s.push_back('!');//根节点存完之后输入!表示该节点存放完毕
        Serialize(root->left) ;
        Serialize(root->right);
    }
    char* Serialize(TreeNode *root) {
        Serializevector(root);//分别递归左右节点,
        char*result=new char[s.size()];//构建数的节点大小的空间
        for (int i=0;i<s.size();i++)
        {
            result[i]= (char) s[i];//依次存入到最终结果中
        }
        return result;
    }
    
   //2.反序列化二叉树,将字符串转化成树
    //序列化为://序列化后:00!60!40!#!#!#!14!12!#!#!16!#!#!
    //反序列化:**str指向'00!'*str从0到‘\0’
    TreeNode* Deserialize(char **str)  
    {
      if(**str=='#')  //如果字符串序列为#!,树某一节点为空
      {
        (*str) += 2;
         return NULL;
      }
       int value=0;
       while (**str!= '!')//若字符串未遍历到字符串末尾,
      {
         value *= 10;
         value += (int)**str;
         (*str)++;
      }
      TreeNode*root =new TreeNode(value);
       //序列化后:'00!60!40!#!#!#!14!12!#!#!16!#!#!\0'
       //当遍历到'\0'时,树的所有节点都遍历完了,返回根节点
      if (**str=='\0')//   
          return root;
      else
        (*str)++;
        root->left=Deserialize(str);//遍历左子树和右子树
        root->right=Deserialize(str);
        return root;
  }
     TreeNode* Deserialize(char *str) {
       return   Deserialize(&str);    
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值