算法学习【8】二叉树相关算法

       二叉树相关算法是笔试面试常考内容,需重点掌握。

       二叉树节点定义:

<span style="font-size:14px;">public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}</span>

       常见二叉树笔试题如下

        1、二叉树序列化:将二叉树转换成String,空节点用特殊字符代替,一般用‘#’表示,而且String是按每层依次编号,即层次遍历。因为层次遍历的方法也有很多,所以序列化方法也很多,这里采用递归,非递归见4。

         二叉树 :3        ,序列化结果为{3,9,20,#,#,15,7}。

                        /    \

                      9    20

                           /    \

                         15    7

         上面的例子在程序中表示:

		TreeNode root = new TreeNode(3);
		root.left  = new TreeNode(9);
		root.right = new TreeNode(20);
		root.right.left  = new TreeNode(15);
		root.right.right = new TreeNode(7);
		System.out.println(Serialize(root));

         序列化程序:

	private static StringBuffer sbur = new StringBuffer("");
	public static String Serialize(TreeNode root){
		if(root==null)
			return "";
		int i=0;
		//nodeAtLevel(root, i)=0说明第i行是空行,所有节点都是空
		while(nodeAtLevel(root, i)!=0){
			i++;
		}
        //删除末尾的空格和逗号
		i = sbur.length()-1;
		while(sbur.charAt(i)==','||sbur.charAt(i)=='#'){
			sbur.deleteCharAt(i);
			i--;
		}
		return sbur.toString();
	}
	//根节点为root的二叉树第level行(从0开始)
	private static int nodeAtLevel(TreeNode root, int level){
		if(root==null||level <0){
			sbur.append("#,");
			return 0;
		}else if(level==0){
			sbur.append(root.val);
			sbur.append(",");
			return 1;
		}else{
			return nodeAtLevel(root.left, level-1)+nodeAtLevel(root.right,level-1);
		}
	}
          笔试时也可以采用前序、中序、后序遍历进行序列化,更加简单。
          博客http://blog.csdn.net/u012768242/article/details/50990426就是采用的先序遍历。


        2、二叉树反序列化:由String重构二叉树,这里String是按每层依次编号。

         二叉树第k行有2^(k-1)个节点(k从1开始),k行共有2^k-1个节点第k行的第一个元素索引为2^(k-1)

         索引为2^(k-1)2^(k-1)+2^(k-2)-1的节点在第k行左边,索引为2^(k-1)+2^(k-2)2^k-1的节点在第k行右边

        节点索引为n可推导出行号为k,它是该行第n-(2^(k-1)-1)个节点,与它同一行且位于它左边的节点共有n-2^(k-1),这些节点在下一层共有2*n-2^k个子节点,则节点n的左子树节点是k+1行第2*n-2^k+1个节点右子节点是k+1行第2*n-2^k+2个节点。

        因此,节点n的左子树节点索引为2*n右子树节点索引为2*n+1

         因此按层次遍历序列化的二叉树,可以按照索引规则进行反序列化。

	public static TreeNode Deserialize(String str){
		ArrayList<TreeNode> al = new ArrayList<TreeNode>();
		int begin = 0;
		int n=0;
		for(int i=0;i<str.length();i++){
			if(str.charAt(i)==','){
				String temp = str.substring(begin, i);
				if(temp.equals("#"))
					al.add(null);
				else
					al.add(new TreeNode(Integer.parseInt(temp)));
				begin = i+1;
				n++;
			}
		}
		String temp = str.substring(begin);
		al.add(new TreeNode(Integer.parseInt(temp)));
		n++;

		for(int i=1;i<=n;i++){
			if(al.get(i-1)!=null){
				if(2*i<=n)
					al.get(i-1).left = al.get(2*i-1);
				if(2*i+1<=n)
					al.get(i-1).right= al.get(2*i);
			}
		}
		return al.get(0);
	}

        3、数组转化为二叉树

         和上面的内容基本一致。以后使用该函数可以很方便的构造二叉树。

         博客http://blog.csdn.net/dahai_881222/article/details/7816127则是把一个有序数组转为二叉树存储。

         空节点用-1代替,以下图为例。


	public static TreeNode arr2Tree(int[] arr){
		int n = arr.length;
		TreeNode[] tn = new TreeNode[n];
		for(int i=0;i<n;i++){
			tn[i] = new TreeNode(arr[i]);
		}
		for(int i=1;i<=n;i++){
			if(tn[i-1].val!=-1){
				if(2*i<=n)
					tn[i-1].left = tn[2*i-1];
				if(2*i+1<=n)
					tn[i-1].right= tn[2*i];
			}
		}
		return tn[0];
	}

        4、层次遍历,即二叉树转化为数组

        参考:http://blog.csdn.net/zzran/article/details/8778021

                   http://www.cnblogs.com/miloyip/archive/2010/05/12/binary_tree_traversal.html

                    http://www.cnblogs.com/kaituorensheng/p/3558645.html


        5、前序、中序、后序遍历的递归算法

	public static void preOrder(TreeNode root){
		if(root==null)
			return;
		else{
			System.out.print(root.val+" ");
			preOrder(root.left);
			preOrder(root.right);
		}
	}
	public static void midOrder(TreeNode root){
			if(root==null)
				return;
			else{
				midOrder(root.left);
				System.out.print(root.val+" ");
				midOrder(root.right);
			}
	}
	public static void postOrder(TreeNode root){
			if(root==null)
				return;
			else{
				postOrder(root.left);
				postOrder(root.right);
				System.out.print(root.val+" ");
			}
	


        6、判断一个树是否为另一颗数的子树

         首先判断节点值是否相同,相同则比较各个子节点是否相同,不同则递归判断是否是左子树或右子树的子树。

	public static boolean isSubtree(TreeNode root1, TreeNode root2){
		if(root2 == null)
			return true;
		if(root1 == null)
			return false;
		if(checkNode(root1, root2))
			return true;
		return isSubtree(root1.left, root2)||isSubtree(root1.right, root2);
	}

	public static boolean checkNode(TreeNode root1, TreeNode root2){
		if(root2 == null)
			return true;
		if(root1 == null)
			return false;
		if(root1.val==root2.val)
			return checkNode(root1.left,root2.left)&&checkNode(root1.right,root2.right);
		else
			return false;
	}


        7、求二叉树的深度

         递归算法:二叉树的深度 = max(左子树的深度,右子树的深度)+1。

	public static int getDeep(TreeNode root){
		if(root==null)
			return 0;
		int leftdeep  = getDeep(root.left);
		int rightdeep = getDeep(root.right);
		return leftdeep>rightdeep?leftdeep+1:rightdeep+1;
	}


        8、前序遍历和中序遍历结果重构二叉树(不含重复数字)

         前序遍历数组的第一个元素必定是根节点root,在中序遍历数组中找到root,位于根节点左边的一定属于根节点左子树,位于根节点右边的一定属于根节点右子树,然后递归左子树、右子树,将递归结果赋值给root.left和root.right

    public static TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        int value = pre[0];
        TreeNode root = new TreeNode(value);
        int i=0;
        for(;i<in.length;i++){
            if(in[i]==value){
                break;
            }
        }

        if(i>0){
            int[] inleft = new int[i];
            int[] preleft = new int[i];
            for(int k=0;k<i;k++){
                inleft[k] = in[k];
                preleft[k]= pre[k+1];
            }
            root.left = reConstructBinaryTree(preleft, inleft);
        }else{
            root.left = null;
        }

        if(i<in.length-1){
            int[] inright= new int[in.length-i-1];
            int[] preright= new int[in.length-i-1];
            for(int k=0;k<in.length-i-1;k++){
                inright[k] = in[k+i+1];
                preright[k]= pre[k+i+1];
            }
            root.right= reConstructBinaryTree(preright,inright);
        }else{
            root.right = null;
        }

        return root;
    }

        9、求二叉树的镜像


    public static void Mirror(TreeNode root) {
        if(root == null)
        	return;
        TreeNode temp = root.left;
        root.left = root.right;
        root.right= temp;
        if(root.left!=null)
        	Mirror(root.left);
        if(root.right!=null)
        	Mirror(root.right);
    }




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值