vlambda博客
学习文章列表

【漫步计算机系统】之数据结构与算法(11):树Ⅰ

问题一:重建二叉树

给定某二叉树的前序遍历和中序遍历,请重建出该二叉树并返回它的头结点。


例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。



代码如下:

// 缓存中序遍历数组每个值对应的索引private Map<Integer, Integer> indexForInOrders = new HashMap<>();
public TreeNode reConstructBinaryTree(int[] pre, int[] in) { for (int i = 0; i < in.length; i++) indexForInOrders.put(in[i], i); return reConstructBinaryTree(pre, 0, pre.length - 1, 0);}
private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int inL) { if (preL > preR) return null; TreeNode root = new TreeNode(pre[preL]); int inIndex = indexForInOrders.get(root.val); int leftTreeSize = inIndex - inL; root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, inL); root.right = reConstructBinaryTree(pre, preL + leftTreeSize + 1, preR, inL + leftTreeSize + 1); return root;}


算法描述:

  1. 创建一个中序遍历索引哈希表indexForInOrders,键为中序遍历数组的结点值,值为中序遍历数组的下标;

  2. 前序遍历序列从头至尾递归;

  3. 在一次递归中,根结点root为前序遍历的头结点,root在子树中的位置为哈希表indexForInOrders中键为根节点对应的值inIndex;

  4. 将inIndex前面序列的根节点作为root的左子结点,后面序列的根节点作为root的右子结点;

  5. 递归至叶子结点,返回null,重建完成!


问题二:二叉树的下一个结点

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


public class TreeLinkNode {
int val; TreeLinkNode left = null; TreeLinkNode right = null; TreeLinkNode next = null; // 指向父结点的指针
TreeLinkNode(int val) { this.val = val; }}


代码如下:

public TreeLinkNode GetNext(TreeLinkNode pNode) { if (pNode.right != null) { TreeLinkNode node = pNode.right; while (node.left != null) node = node.left; return node; } else { while (pNode.next != null) { TreeLinkNode parent = pNode.next; if (parent.left == pNode) return parent; pNode = pNode.next; } } return null;}


算法描述:

  1. 如果结点pNode的右子结点不为空,得到右子结点node;

  2. 如果node的左子结点不为空,一直迭代左子结点,返回最左的子结点;若为空,直接返回node;

  3. 若pNode的右子结点为空,迭代,得到pNode的父结点parent,pNode指向其父节点;

  4. 一直到parent的左子结点为pNode,返回parent结点,程序结束!


问题三:树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。


【漫步计算机系统】之数据结构与算法(11):树Ⅰ


代码如下:

public boolean HasSubtree(TreeNode root1, TreeNode root2) { if (root1 == null || root2 == null) return false; return isSubtreeWithRoot(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);}
private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) { if (root2 == null) return true; if (root1 == null) return false; if (root1.val != root2.val) return false; return isSubtreeWithRoot(root1.left, root2.left) && isSubtreeWithRoot(root1.right, root2.right);}


算法描述:

运用递归函数,若从两棵树的根结点开始有子结构,或一棵树的左子树和另一棵树有子结构,或一棵树的右子树和另一棵树有子结构,返回true;


问题四:二叉树的镜像

操作给定的二叉树,将其变换为源二叉树的镜像。



代码如下:

public TreeNode Mirror(TreeNode root) { if (root == null) return root; swap(root); Mirror(root.left); Mirror(root.right); return root;}
private void swap(TreeNode root) { TreeNode t = root.left; root.left = root.right; root.right = t;}


算法描述:

  1. 交换根结点root的左右子树;

  2. 将根结点的左子树交换;

  3. 将根结点的右子树交换,递归;

  4. 返回根结点root,程序完毕!