「漫步計算機系統」之資料結構與演算法(12):樹Ⅰ

問題一:重建二叉樹

給定某二叉樹的前序遍歷和中序遍歷,請重建出該二叉樹並返回它的頭結點。

例如

輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建出如下圖所示。

「漫步計算機系統」之資料結構與演算法(12):樹Ⅰ

程式碼如下:

// 快取中序遍歷陣列每個值對應的索引

private Map 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的子結構。

「漫步計算機系統」之資料結構與演算法(12):樹Ⅰ

程式碼如下:

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;

問題四:二叉樹的映象

操作給定的二叉樹,將其變換為源二叉樹的映象。

「漫步計算機系統」之資料結構與演算法(12):樹Ⅰ

程式碼如下:

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,程式完畢!

「漫步計算機系統」之資料結構與演算法(12):樹Ⅰ

注:凡屬於本公眾號內容,未經允許不得私自轉載,否則將依法追究侵權責任。