构造二叉树,并求解树的高度

时间:2021-10-14 19:29:53

一,问题描述

在控制台上输入一组数据,请按照输入的数据的格式来构造一棵二叉树,并打印出二叉树的高度。

输入的数据格式如下:

第一行为一个整数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)。有点大。

 

参考资料:二叉树的构造