树简介
树结构,一种非线性结构,指的是N个有父子关系节点的有限集合。
树中任一节点可以有0或多个子节点,但只能有一个父节点。根节点是一个特例,根节点没有父节点,叶子节点没有子节点。树中每个节点既可以是其上一级节点的子节点,也可以是下一级节点的父节点,因此同一个节点可以既是父节点,也是子节点。
如果按节点是否包含子节点来分,节点分成以下两种:
- 普通节点:包含子节点的节点。
- 叶子节点:没有子节点的节点,因此叶子节点不可作为父节点。
如果按节点是否具有唯一的父节点来分,节点又可分为如下两种:
- 根节点:没有父节点的节点,根节点不可作为子节点。
- 普通节点:具有唯一父节点的节点。
相关术语:
- 节点:树的最基本组成单元,常包括一个数据元素及若干指针用于指向其他节点。
- 节点的度:节点拥有的子树的个数被称为节点的度(degree)。
- 树的度:树中所有节点的度的最大值就是该树的度。
- 叶子节点:度为0的节点被称叶子节点或终端节点。
- 分支节点:度不为0的节点被称分支节点或非终端节点。
- 子节点、父节点、兄弟节点:节点的子树的根被称为该节点的子节点,而该节点称做子节点的父节点(parent)。具有相同父节点的子节点之间互称为兄弟节点(sibling)。
- 节点的层次(level):节点的层次从根开始算起,根的层次值为1,其余节点的层次值为父节点层次值加1。
- 树的深度(depth):树中节点的最大层次值称为树的深度或高度。
- 有序树与无序树:如果将树中节点的各个子树看成从左到右是有序的(即不能互换),则称该树为有序树,否则称为无序树。
- 祖先节点(ancestor):从根到该节点所经分支上的所有节点。
- 后代节点(descendant):以某节点为根的子树中任一节点都称为该节点的后代节点。
- 森林(forest):森林是2 棵或 2 棵以上互不相交的树的集合,删去一棵树的根,就得到一个森林。
父节点表示法
树中除根节点之外的每个节点都有一个父节点。为了记录树中节点与节点之间的父子关系,可以为每个节点增加一个parent域,用以记录该节点的父节点。
public class TreeParent<E> {
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;
}
@Override
public String toString() {
return "TreeParent$Node[data=" + data + ",parent=" + parent + "]";
}
}
private final int DEFAULT_SIZE = 100;
private int treeSize = 0;
private Node<E>[] nodes;
private int nodeNums;
// 以指定根节点创建树
public TreeParent(E data) {
treeSize = DEFAULT_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);
nodeNums++;
}
// 为指定节点添加子节点
public void addNode(E data, Node parent) {
for (int i = 0; i < treeSize; i++) {
if (nodes[i] != null) {
nodes[i] = new Node(data, pos(parent));
nodeNums++;
return;
}
}
throw new RuntimeException();
}
public boolean empty() {
return nodeNums == 0;
}
// 返回根节点
public Node<E> root() {
return nodes[0];
}
// 返回指定节点的父节点
public Node<E> parent(Node node) {
return nodes[node.parent];
}
// 返回指定节点(非叶子节点)的所有子节点
public List<Node<E>> children(Node 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;
}
// 返回该树的深度
public int deep() {
int max = 0;
for (int i = 0; i < treeSize && nodes[i] != null; i++) {
int def = 1;
int m = nodes[i].parent;
while (m != -1 && nodes[m] != null) {
m = nodes[m].parent;
def++;
}
if (max < def) {
max = def;
}
}
return max;
}
// 返回包含指定值的节点
private int pos(Node parent) {
for (int i = 0; i < treeSize; i++) {
if (nodes[i] == parent) {
return i;
}
}
return -1;
}
}
子节点链表示法
由每个节点记住它的所有子节点。
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;
}
}
public static class Node<T> {
T data;
//记录第一个节点
SonNode first;
public Node(T data) {
this.data = data;
this.first = null;
}
}
private final int DEFAULT_SIZE = 100;
private int treeSize = 0;
//使用一个Node[]数组来记录该树里所有节点
private Node<E>[] nodes;
//记录节点数
private int nodeNums;
//以指定根节点创建树
public TreeChild(E data) {
this.treeSize = DEFAULT_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++) {
if (nodes[i] == null) {
nodes[i] = new Node(data);
if (parent.first == null) {
parent.first = new SonNode(i, null);
} else {
SonNode next = parent.first;
while (next.next != null) {
next = next.next;
}
next.next = new SonNode(i, null);
}
nodeNums++;
return;
}
}
throw new RuntimeException();
}
//判断是否为空
public boolean empty() {
return nodeNums == 0;
}
//返回根节点
public Node<E> root() {
return nodes[0];
}
//返回指定节点(非叶子结点)的所有子节点
public List<Node<E>> children(Node parent) {
List<Node<E>> list = new ArrayList<>();
SonNode next = parent.first;
while (next != null) {
list.add(nodes[next.pos]);
next = next.next;
}
return list;
}
//返回指定节点(非叶子节点)的第index个子节点
public Node<E> child(Node parent, int index) {
SonNode next = parent.first;
for (int i = 0; next != null; i++) {
if (i == index) {
return nodes[next.pos];
}
next = next.next;
}
return null;
}
//返回该树的深度
public int deep() {
return deep(root());
}
private int deep(Node node) {
if (node.first == null) {
return 1;
} else {
int max = 0;
SonNode next = node.first;
while (next != null) {
int tmp = deep(nodes[next.pos]);
if (tmp > max) {
max = tmp;
}
next = next.next;
}
return max + 1;
}
}
//返回包含指定值的节点
public int pos(Node node) {
for (int i = 0; i < treeSize; i++) {
if (nodes[i] == node) {
return i;
}
}
return -1;
}
}