一,問題描述
在控制台上輸入一組數據,請按照輸入的數據的格式來構造一棵二叉樹,並打印出二叉樹的高度。
輸入的數據格式如下:
第一行為一個整數N(其實是二叉樹中邊的數目),表示接下來一共有N行輸入,每行輸入有兩個數,左邊的數表示父結點,右邊的數表示父結點的孩子結點。示例如下:
6
0 1
0 2
1 3
2 4
2 5
4 6
從上面的輸入可以看出:①根結點0 的左孩子為1,右孩子為2 。②結點1 只有一個孩子,即左孩子3
二,問題分析
問題的關鍵是根據上面的輸入數據 構造一棵二叉樹。
首先用一個Map<Integer, List<Integer>>保存上面的輸入的數據。其中Key為父結點,Value為父結點的孩子結點。對於二叉樹而言,父結點的孩子結點最多只有2個,故List長度最大為2.
然后,根據Map來構造二叉樹即可。
對於Map中的每一個Entry,Entry的Key為父結點,找到父結點在樹中的位置(findNode方法)。
Entry的Value為父結點的左右孩子,遍歷Value,構造孩子結點。已知了父結點在樹中的位置,又構造了孩子結點,只需要將父結點的左右指針指向左右孩子即可。
三,代碼實現
import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Scanner; import java.util.Set; //按要求構造二叉樹,假設頭結點為0 public class BuildTree { public static void main(String[] args) { Scanner sc = new Scanner(System.in); //<parent, childList> Map<Integer, List<Integer>> datas = new LinkedHashMap<Integer, List<Integer>>(); while(sc.hasNextInt()) { int edges = sc.nextInt(); //將樹的信息保存到hashmap<parent, childList>中 for(int i = 0; i < edges; i++) { int parent = sc.nextInt(); int child = sc.nextInt(); if(!datas.containsKey(parent)){ List<Integer> childs = new ArrayList<Integer>(); childs.add(child); datas.put(parent, childs); }else{ List<Integer> childs = datas.get(parent); childs.add(child); } }//end for BinaryNode root = buildTree(datas); int height = height(root); System.out.println(height); } sc.close(); } //求二叉樹的高度 private static int height(BinaryNode root){ if(root == null) return 0; int leftHeight = height(root.left); int rightHeight = height(root.right); return 1 + (leftHeight > rightHeight ? leftHeight : rightHeight); } //構造二叉樹 private static BinaryNode buildTree(Map<Integer, List<Integer>> datas){ BinaryNode root = null; BinaryNode current = null; List<Integer> childs = null; Set<Entry<Integer, List<Integer>>> entrySet = datas.entrySet(); for (Entry<Integer, List<Integer>> entry : entrySet) { int parent = entry.getKey(); current = findNode(parent, root); childs = datas.get(parent); if(current == null){//說明parent是根結點 root = new BinaryNode(parent); createNode(root, childs); }else{ createNode(current, childs); } } return root; } //創建parent結點的左右孩子結點 private static void createNode(BinaryNode parent, List<Integer> childs){ if(childs.size() == 2){//說明有左右孩子 BinaryNode leftChild = new BinaryNode(childs.get(0)); BinaryNode rightChild = new BinaryNode(childs.get(1)); parent.left = leftChild; parent.right = rightChild; } if(childs.size() == 1){//說明只有左孩子 BinaryNode leftChild = new BinaryNode(childs.get(0)); parent.left = leftChild; } } //查找樹根為root的二叉樹中 值為 nodeVal 的結點 private static BinaryNode findNode(int nodeVal, BinaryNode root){ //先序遞歸遍歷查找 值為 nodeVal的結點 BinaryNode target = null; if(root == null) return null; if(root.val == nodeVal) return root; target = findNode(nodeVal, root.left);//先在左子樹中查找 if(target == null) target = findNode(nodeVal, root.right);//左子樹中未找到,則在右子樹中查找 return target; } private static class BinaryNode{ int val; BinaryNode left; BinaryNode right; public BinaryNode(int val){ this.val = val; left = right = null; } } }
復雜度分析:由於 當構造父結點的左右孩子時,需要先查找父結點在二叉樹中的位置,這個查找是用“先序遍歷的思路”實現的。
故構造樹的時間復雜度為O(1+2+3+……+N)=O(N^2)。有點大。
參考資料:二叉樹的構造