4、树的概述
4.1 与树相关的概念
- 节点:树的最基本组成元素,常常包含一个数据元素以及若干个指针用于指向其他节点;
- 节点的度(degree):节点拥有的子树的个数
- 树的度:树中所有节点的最大度即该树的度
- 叶子节点:度为0的节点被称为叶子节点或者终端节点
- 分支节点:度不为0的节点称为分支节点或者非终端节点
- 子节点、父节点、兄弟节点:节点的子树的根被称为该节点的子节点,该节点被称为子节点的父节点,具有相同父节点的子节点被称为兄弟节点
- 节点的层次(level):节点的层次从根开始算起,根节点的层次为1,其他节点的层次为父节点的层次加1
- 树的深度:树中节点的最大层次值称为树的深度或高度
- 有序树与无序树:如果将树中节点的各个子树看成从左到右是有序的,则该树被称为有序树,否则是无序树
- 祖先节点(ancestor):从根到该节点所经路径的所有节点
- 后代节点:以某节点为跟的子树中任意节点都被称为该节点的子节点
- 森林:2棵或者2棵以上互不相交的树的集合,删去一棵树的根,就得到一片森林
4.2 树的实现
为实现树这种数据结构,必须记录节点与节点之间的父子关系,所以又以下两种表示方法:
- 父节点表示法:每个节点都记录他的父节点
- 孩子链表示法:每个非叶子节点通过一个链表来记录它的所有的子节点
下面分别用两种方法实现树的表示:
4.2.1 树的父节点表示
import java.util.ArrayList;
import java.util.List;
/**
* 树的父节点表示法
* @author retreatweb
*
* @param <E> 树中保存的元素类型
*/
public class TreeParent<E> {
/**
* 树中保存的元素
* @author retreatweb
* @param <T> 节点的数据类型
*/
public static class Node<T>{
T data;
//记录父节点的位置
int parent;
public Node(){
}
public Node(T data){
this.data = data;
}
public Node(T data, int parent) {
this.data = data;
this.parent = parent;
}
public String toString(){
return "TreeParent$Node[data="+data+",parent="+parent+"]";
}
}
private final int DEFAULT_TREE_SIZE = 10;
private int treeSize = 0;
//使用一个NOde[]数组来记录树中所有的节点
private Node<E>[] nodes;
//记录节点数
private int nodeNums;
//以指定根节点创建树
public TreeParent(E data){
treeSize = DEFAULT_TREE_SIZE;
nodes = new Node[treeSize];
nodes[0] = new Node<E>(data, -1);
nodeNums++;
}
//以指定根节点指treesize创建树
public TreeParent(E data,int treeSize){
this.treeSize = treeSize;
nodes = new Node[treeSize];
nodes[0] = new Node<E>(data, -1);
nodeNums++;
}
/**
* 为指定节点添加子节点
* @param data 子节点的数据
* @param parent 需要添加子节点的节点
*/
public void addNode(E data,Node parent){
for (int i = 0; i < treeSize; i++) {
//找到数组中第一个为null的元素,用该元素保存该子节点
if(nodes[i] == null){
//创建新节点,并用数组元素保存
nodes[i] = new Node<E>(data, pos(parent));
nodeNums++;
return;
}
}
throw new RuntimeException("该树已满,无法添加元素");
}
/**
* 获得包含指定值的位置
* @param parent 指定值
* @return 指定值的位置
*/
public int pos(Node<E> parent) {
for (int i = 0; i < treeSize; i++) {
if(nodes[i] == parent){
return i;
}
}
return -1;
}
/**
* 判断树是否为空
* @return 返回根元素是否为null
*/
public boolean isEmpty(){
return nodes[0] == null;
}
/**
* 求根节点
* @return 返回根节点
*/
public Node<E> root(){
return nodes[0];
}
/**
* 获得指定父节点的所有的子节点
* @param parent 指定的父节点
* @return 返回子节点的集合
*/
public List<Node<E>> children(Node<E> parent){
List<Node<E>> list = new ArrayList();
for (int i = 0; i < treeSize; i++) {
//如果当前节点的父节点的位置等于父节点的位置
if(nodes[i] != null && nodes[i].parent == pos(parent)){
list.add(nodes[i]);
}
}
return list;
}
/**
* 获取该树的深度
* @return 返回该树的节点的最大深度
*/
public int deep(){
//用于记录节点的最大深度
int max = 0;
for (int i = 0; i < treeSize && nodes[i] != null; i++) {
//初始化本节点的深度
int def = 1;
//用m记录当前节点的父节点的位置
int m = nodes[i].parent;
//如果当前节点的父节点存在
if(m != -1 && nodes[m] != null){
//向上继续搜索父节点
m = nodes[m].parent;
def++;
}
if(max < def){
max = def;
}
}
return max;
}
}
4.2.2 树的孩子链表示
import java.util.ArrayList;
import java.util.List;
/**
* 树的子节点链表示法
*
* @author Administrator
*
*/
public class TreeChild<E> {
/**
* 子节点
*/
private static class SonNode {
// 记录当前节点位置
private int pos;
private SonNode next;
public SonNode(int pos, SonNode next) {
this.pos = pos;
this.next = next;
}
}
/**
* 节点
*
* @author Administrator
*
* @param <T>
*/
public static class Node<T> {
T data;
// 记录第一个子节点
SonNode first;
public Node(T data) {
this.data = data;
this.first = null;
}
public String toString() {
if (first != null) {
return "TreeChild$Node[data=" + data + ",first" + first.pos + "]";
} else {
return "TreeChild$Node[data=" + data + ",first=-1]";
}
}
}
private final int DEFAULT_TREE_SIZE = 10;
private int treeSize = 0;
// 使用一个NOde[]数组来记录树中所有的节点
private Node<E>[] nodes;
// 记录节点数
private int nodeNums;
// 以指定根节点创建树
public TreeChild(E data) {
treeSize = DEFAULT_TREE_SIZE;
nodes = new Node[treeSize];
nodes[0] = new Node<E>(data);
nodeNums++;
}
// 以指定根节点指treesize创建树
public TreeChild(E data, int treeSize) {
this.treeSize = treeSize;
nodes = new Node[treeSize];
nodes[0] = new Node<E>(data);
nodeNums++;
}
// 为指定节点添加子节点
public void addNode(E data, Node parent) {
for (int i = 0; i < treeSize; i++) {
// 找到数组中第一个为null的元素,用该元素保存该子节点
if (nodes[i] == null) {
// 创建新节点,并用指定数组元素保存
nodes[i] = new Node(data);
if (parent.first == null) {
parent.first = new SonNode(i, null);
} else {
SonNode snext = parent.first;
while (snext.next != null) {
snext = snext.next;
}
snext.next = new SonNode(i, null);
}
nodeNums++;
return;
}
}
throw new RuntimeException("该树已满,无法添加元素");
}
/**
* 判断树是否为空
* @return 返回根元素是否为null
*/
public boolean isEmpty(){
return nodes[0] == null;
}
/**
* 求根节点
* @return 返回根节点
*/
public Node<E> root(){
return nodes[0];
}
/**
* 获得指定父节点的所有的子节点
* @param parent 指定的父节点
* @return 返回子节点的集合
*/
public List<Node<E>> children(Node<E> parent){
List<Node<E>> list = new ArrayList();
//获取parent节点的第一个子节点
SonNode first = parent.first;
//沿着孩子链不断搜素下一个孩子节点
while(first != null){
list.add(nodes[first.pos]);
first = first.next;
}
return list;
}
/**
* 获取指定父节点的第index个子节点
* @param parent 指定父节点
* @param index 第index个子节点
* @return 返回子节点
*/
public Node<E> child(Node parent,int index){
//获取指定父节点的第一个子节点
SonNode first = parent.first;
for (int i = 0;first != null; i++) {
if(i == index){
return nodes[first.pos];
}
first = first.next;
}
return null;
}
/**
* 获取树的最大深度
* @return 返回树的深度
*/
public int deep(){
return deep(root());
}
/**
* 获得某节点的最大深度
* 该方法为递归方法,每一棵子树的最大深度为其子树的深度+1
* @param node 要求深度的节点
* @return
*/
private int deep(Node<E> node) {
//叶子节点
if(node.first == null){
return 1;
}else{
//记录所有子树的最大深度
int max = 0;
SonNode next = node.first;
while(next != null){
//获取以其子节点为跟的树的深度
int tem = deep(nodes[next.pos]);
if(tem > max){
max = tem;
}
next = next.next;
}
return max + 1;
}
}
public int index(Node node){
for (int i = 0; i < treeSize; i++) {
if(nodes[i] == node){
return i;
}
}
return -1;
}
}