子节点链表示法:
从上面的程序来看,程序定义树节点时添加了一个first域。该first域用于保存该节点的子节点链的引用。通过这种方法即可保存树中的节点之间的父子关系。使用这种子节点链表示法来存储树时,添加节点时只需找到指定父节点的子节点链的最后节点,并让他指向新增的节点即可。
测试结果如下:
通过上面介绍可知,子节点链表示法的特点是:每个节点都可以快速的找到它的所有的子节点。但如果找找到某个节点的父节点则比较麻烦,程序要遍历整个节点数组。
父节点表示法的思想是让每个节点“记住”它的父节点的索引,父节点表示法是从子节点入手的;反过来,还有另外一种方式:让父节点“记住”它的所有子节点。在这种方式下,由于每个父节点需要记住多个子节点,因此必须采用”子节点链“表示法。在这种表示法下,对于下面的树的采用的保存结构如下图所示:
从上面的图可以看出,采用子节点链表示法来记录树时,需要为每个节点维护一个子节点链,通过该子节点链来记录该节点的所有子节点。下面程序实现了树的子节点链表示法:
import java.util.ArrayList;
import java.util.List;
/**
* 子节点链表示法
* @author WB
*
* @param <E>
*/
public class TreeChild <E>{
//用于保存子节点链
private class SonNode{
//记录自己的索引位置
private int pos;
private SonNode next;
public SonNode(int pos, SonNode next){
this.pos = pos;
this.next = next;
}
}
//用于保存节点
public class Node <T>{
T data;
//每个节点都有可能有子节点,指向第一个可能的子节点
SonNode first;
public Node(){
}
public Node(T data, SonNode first){
this.data = data;
this.first = first;
}
public String toString(){
return first != null ? "TreeChild$Node[data = " + data + ", first = " + first.pos + "]" :
"TreeChild$Node[data = " + data + ", first = -1]";
}
}
private final int DEFAULT_TREE_SIZE = 100;
//容量
private int treeSize = 0;
//底层数组
private Node<E>[] nodes;
private int nodeNums;
@SuppressWarnings("unchecked")
public TreeChild(){
treeSize = DEFAULT_TREE_SIZE;
nodes = new Node[treeSize];
}
public TreeChild(E data){
this();
nodes[0] = new Node<E>(data, null);
nodeNums ++;
}
@SuppressWarnings("unchecked")
public TreeChild(E data, int initSize){
treeSize = initSize;
nodes = new Node[treeSize];
nodes[0] = new Node<E>(data, null);
nodeNums ++;
}
//判断是否为空
public boolean isEmpty(){
return nodes[0] == null;
}
//返回根节点
public Node<E> root(){
return nodes[0];
}
//为指定节点添加子节点
public void add(E data, Node<?> parent){
if(pos(parent) == -1){
throw new RuntimeException("无法找到该节点。");
}
else{
for(int i = 0;i < treeSize; i ++){
//找到第一个为空的位置存放新添加的子节点
if(nodes[i] == null){
Node<E> newNode = new Node<E>(data, null);
nodes[i] = newNode;
if(parent.first == null){
SonNode sonNode = new SonNode(i, null);
parent.first = sonNode;
}
else{//有子节点链
SonNode next = parent.first;
while(next.next != null){
next = next.next;
}
next.next = new SonNode(i, null);
}
nodeNums ++;
return;
}
}
throw new RuntimeException("该树已满,无法添加新节点!");
}
}
//获得指定节点(非叶子节点)的所有子节点
public List<Node<E>> children(Node<?> parent){
List<Node<E>> list = new ArrayList<Node<E>>();
SonNode next = parent.first;
while(next != null){
list.add(nodes[next.pos]);
next = next.next;
}
return list;
}
//获取指定节点(非叶子节点)的第 i 个子节点
public Node<E> child(int index, Node<?> parent){
SonNode next = parent.first;
for(int i = 1; next != null; i ++){
if(i == index){
return nodes[next.pos];
}
next = next.next;
}
return null;
}
//返回树的深度
public int deep(){
return deepHelp( root() );
}
//这是一个递归方法:每柯子树的深度是其所有子树的最大深度 +1
private int deepHelp(Node<?> parent){
if(parent.first == null){
return 1;
}
else{
int max = 0;
SonNode next = parent.first;
while(next != null){
int tmp = deepHelp(nodes[next.pos]);
if(tmp > max){
max = tmp;
}
next = next.next;
}
return max + 1;
}
}
private int pos(Node<?> parent){
for(int i = 0; i < treeSize; i ++){
if(nodes[i] == parent){
return i;
}
}
return -1;
}
}
从上面的程序来看,程序定义树节点时添加了一个first域。该first域用于保存该节点的子节点链的引用。通过这种方法即可保存树中的节点之间的父子关系。使用这种子节点链表示法来存储树时,添加节点时只需找到指定父节点的子节点链的最后节点,并让他指向新增的节点即可。
下面是测试代码:
import java.util.List;
import com.yc.tree.TreeChild;
public class TreeChildTest {
public static void main(String[] args) {
TreeChild<String> tree = new TreeChild<String>("root");
System.out.println("根节点:" + tree.root());
tree.add("节点1", tree.root());
tree.add("节点2", tree.root());
tree.add("节点3", tree.root());
System.out.println( "添加子节点后的根节点为:" + tree.root());
System.out.println( "此时树的深度为:" + tree.deep());
//获取根节点下的所有子节点
List<TreeChild<String>.Node<String>> list = tree.children(tree.root());
System.out.println( "根节点的第一个子节点为:" + list.get(0));
System.out.println( "或者用child()方法得到根节点的第一个子节点为:" + tree.child(1, tree.root()));
//为根节点的第一个子节点添加新的子节点
tree.add("节点4", list.get(0));
System.out.println( " 此时树的深度为:" + tree.deep());
System.out.println( " 根节点的第一个子节点的第一个字节点为:" + tree.child(1, tree.child(1, tree.root())));
}
}测试结果如下:
通过上面介绍可知,子节点链表示法的特点是:每个节点都可以快速的找到它的所有的子节点。但如果找找到某个节点的父节点则比较麻烦,程序要遍历整个节点数组。
本文介绍了子节点链表示法的基本概念及实现方法,详细解释了如何通过子节点链表示法来存储树形结构的数据,并提供了具体的代码示例。
177万+

被折叠的 条评论
为什么被折叠?



