【漫步计算机系统】之数据结构与算法(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;
}
算法描述:
创建一个中序遍历索引哈希表indexForInOrders,键为中序遍历数组的结点值,值为中序遍历数组的下标;
前序遍历序列从头至尾递归;
在一次递归中,根结点root为前序遍历的头结点,root在子树中的位置为哈希表indexForInOrders中键为根节点对应的值inIndex;
将inIndex前面序列的根节点作为root的左子结点,后面序列的根节点作为root的右子结点;
递归至叶子结点,返回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;
}
算法描述:
如果结点pNode的右子结点不为空,得到右子结点node;
如果node的左子结点不为空,一直迭代左子结点,返回最左的子结点;若为空,直接返回node;
若pNode的右子结点为空,迭代,得到pNode的父结点parent,pNode指向其父节点;
一直到parent的左子结点为pNode,返回parent结点,程序结束!
问题三:树的子结构
输入两棵二叉树A,B,判断B是不是A的子结构。
代码如下:
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;
}
算法描述:
交换根结点root的左右子树;
将根结点的左子树交换;
将根结点的右子树交换,递归;
返回根结点root,程序完毕!