目录

每日算法(二)——二叉树

先序中序后序两两结合组成树

给定一个二叉树正确的先序,中序,后序数组 重构出原来的二叉树 并返回头节点

思路: 根据 3种遍历方式的特点 先序遍历的第一个元素为树的根节点 后序遍历的最后一个元素为树的根节点 利用递归方式重构树

 public Node buildTree(int[] preorder, int[] inorder) {
        return buildTrees(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
    }

    private Node buildTrees(int[] preorder, int pleft, int pright, int[] inorder, int inleft, int inright) {
        if(pleft > pright || inleft > inright) return null;
      // 头节点
        Node root = new Node(preorder[pleft]);
        int rootIn = inleft;
        while(preorder[pleft] != inorder[rootIn]){
            rootIn++;
        }
      // 左子树的长度
        int left = rootIn - inleft;
      // 先序/中序遍历的左子树范围
        root.left = buildTrees(preorder,pleft +1,pleft + left,inorder,inleft,rootIn - 1);
      // 先序/中序遍历的右子树范围
        root.right = buildTrees(preorder,pleft + left + 1,pright,inorder,rootIn + 1,inright);
        return root;
    }
 public Node buildTree(int[] inorder, int[] postorder) {
        return buildTrees(inorder, 0, inorder.length - 1, postorder, 0, postorder.length - 1);
    }

    private Node buildTrees(int[] inorder, int inLeft, int inRight, int[] postorder, int posLeft, int posRight) {
        if (inLeft > inRight || posLeft > posRight) return null;
      // 头节点
        Node root = new Node(postorder[posRight]);
        int rootIn = inLeft;
        while(inorder[rootIn] != postorder[posRight]){
            rootIn++;
        }
        int leftLen = rootIn - inLeft;
        root.left = buildTrees(inorder,inLeft,rootIn - 1,postorder,posLeft,posLeft + leftLen - 1);
        root.right= buildTrees(inorder,rootIn + 1,inRight,postorder,posLeft + leftLen,posRight - 1);
        return root;
    }

特别注意: 先序和后序的组合并不一定能重构出正确的树

​ A A 二者的先序和后序 都是 AB BA

​ /

B B

即 只有每个结点的孩子树为 0 或 2 的二叉树才能被先序和后序正确还原

public static Node prePosToTree(int[] pre, int[] pos) {
		if (pre == null || pos == null) {
			return null;
		}
		HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
		for (int i = 0; i < pos.length; i++) {
			map.put(pos[i], i);
		}
		return prePos(pre, 0, pre.length - 1, pos, 0, pos.length - 1, map);
	}

	public static Node prePos(int[] p, int pi, int pj, int[] s, int si, int sj,
			HashMap<Integer, Integer> map) {
		Node head = new Node(s[sj--]);
		if (pi == pj) {
			return head;
		}
		int index = map.get(p[++pi]);
		head.left = prePos(p, pi, pi + index - si, s, si, index, map);
		head.right = prePos(p, pi + index - si + 1, pj, s, index + 1, sj, map);
		return head;
	}

通过先序和中序生成后序数组

public static int[] getPosArray(int[] pre, int[] in) {
		if (pre == null || in == null) {
			return null;
		}
		int len = pre.length;
		int[] pos = new int[len];
  // 预先保存中序遍历时每个结点的位置 不必像上一题中遍历求解位置
		HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
		for (int i = 0; i < len; i++) {
			map.put(in[i], i);
		}
		setPos(pre, 0, len - 1, in, 0, len - 1, pos, len - 1, map);
		return pos;
	}

	public static int setPos(int[] p, int pi, int pj, int[] n, int ni, int nj,
			int[] s, int si, HashMap<Integer, Integer> map) {
		if (pi > pj) {
			return si;
		}
      // 填充数组
		s[si--] = p[pi];
		int i = map.get(p[pi]);
		si = setPos(p, pj - nj + i + 1, pj, n, i + 1, nj, s, si, map);
		return setPos(p, pi + 1, pi + i - ni, n, ni, i - 1, s, si, map);
	}

统计完全二叉树的节点数

满二叉树引出: 满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点

完全二叉树: 有左无右 至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上

思路: 如果右子树没有到达最后一层 则说明右子树为满二叉树 否则左子树为满二叉树

一颗树深度为h,最大层数为k,深度与最大层数相同,k=h;

  它的叶子数是: 2^h

  第k层的结点数是: 2^(k-1)

  总结点数是: 2^k-1 (2的k次方减一)

public static int nodeNum(Node head) {
		if (head == null) {
			return 0;
		}
		return bs(head, 1, mostLeftLevel(head, 1));
	}
// bs(node,l,h) 以node为头的完全二叉树的节点数是多少
	public static int bs(Node node, int l, int h) {
		if (l == h) {
			return 1;
		}
		if (mostLeftLevel(node.right, l + 1) == h) {
			return (1 << (h - l)) + bs(node.right, l + 1, h);
		} else {
			return (1 << (h - l - 1)) + bs(node.left, l + 1, h);
		}
	}

	public static int mostLeftLevel(Node node, int level) {
		while (node != null) {
			level++;
			node = node.left;
		}
		return level - 1;
	}