构造二叉树,并求解树的高度
一,问题描述
在控制台上输入一组数据,请按照输入的数据的格式来构造一棵二叉树,并打印出二叉树的高度。
输入的数据格式如下:
第一行为一个整数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)。有点大。
参考资料:二叉树的构造