树的子节点链表示法及其Java实现

来源:互联网 发布:淘宝上专柜撤柜剪标的 编辑:程序博客网 时间:2024/05/04 23:47

父节点表示法的思想是让每个节点持有它的父节点的索引,这种方式是从子节点出发;反过来可以让父节点持有它的所有子节点。这种方式下,由于每个父节点需要记住多个子节点,因此必须采用“子节点链”表示法。如下图:

 

image_thumb1image


Java实现代码

package com.liuhao.DataStructures;import java.util.ArrayList;import java.util.List;public class TreeChild<E> {private static class ChildNode {private int pos;// 记录当前节点位置private ChildNode next;public ChildNode(int pos, ChildNode next) {this.pos = pos;this.next = next;}}public static class Node<T> {T data;ChildNode first;// 记录第一个子节点public Node() {}public Node(T data) {this.data = data;this.first = null;}public String toString() {if (first != null) {return "TreeChild$Node[data=" + data + ", first=" + first.pos+ "]";}return "TreeChild$Node[data=" + data + ", first=-1]";}}private final int DEFAULT_TREE_SIZE = 100;private int treeSize = 0;// 使用一个Node[]数组来记录该树的所有节点private Node<E>[] nodes;// 记录节点数private int nodeNums;// 以指定根节点创建树@SuppressWarnings("unchecked")public TreeChild(E data) {treeSize = DEFAULT_TREE_SIZE;nodes = new Node[treeSize];nodes[0] = new Node<E>(data);nodeNums++;}// 以指定根节点、指定treeSize创建树@SuppressWarnings("unchecked")public TreeChild(E data, int treeSize) {this.treeSize = treeSize;this.nodes = new Node[treeSize];nodes[0] = new Node<E>(data);nodeNums++;}// 为指定节点添加子节点public void addNode(E data, Node<E> node) {for (int i = 0; i < treeSize; i++) {if (nodes[i] == null) {nodes[i] = new Node<E>(data);// 若该节点没有第一个子节点,那么就新建子节点链if (node.first == null) {node.first = new ChildNode(i, null);} else {// 若有,则依次取该节点的子节点,直到叶子节点ChildNode next = node.first;while (next.next != null) {next = next.next;}// 在叶子节点处添加该子节点next.next = new ChildNode(i, null);}nodeNums++;return;}}throw new RuntimeException("该树已满,无法添加新节点");}// 判断是否为空public boolean isEmpty() {// 跟节点是否为空return nodes[0] == null;}// 获取根节点public Node<E> getRoot() {return nodes[0];}// 获取指定节点的所有子节点public List<Node<E>> getChildren(Node<E> node) {List<Node<E>> list = new ArrayList<Node<E>>();// 获取给定节点的第一子节点ChildNode next = node.first;// 沿着孩子链不断搜索下一个孩子节点while (next != null) {// 添加孩子链中的节点list.add(nodes[next.pos]);next = next.next;}return list;}// 返回指定节点的第index个子节点public Node<E> getChildByIndex(Node<E> node, int index) {// 获取该节点的第一个子节点ChildNode next = node.first;// 沿着孩子链一直搜寻for (int i = 0; next != null; i++) {if (index == i) {return nodes[next.pos];}next = next.next;}return null;}// 递归的方式返回某个节点的深度private int getDeep(Node<E> node) {if (node.first == null) {return 1;} else {int max = 0;ChildNode next = node.first;while (next != null) {// 获取以其子节点为根的子树的深度int tmp = this.getDeep(nodes[next.pos]);if (tmp > max) {max = tmp;}next = next.next;}return max + 1;}}public int getDeep() {return this.getDeep(getRoot());}// 返回包含指定节点的索引public int pos(Node<E> node) {for (int i = 0; i < treeSize; i++) {if (nodes[i] == node) {return i;}}return -1;}}

从以上程序可以看出,定义树节点时增加了一个first域。该first域用于保存对该节点的子节点链的引用,通过这种方式即可记录数中节点之间的父子关系。

添加节点时只需找到指定节点的子节点链的最后节点,并让他指向新增的节点。


测试代码:

package com.liuhao.test;import java.util.List;import org.junit.Test;import com.liuhao.DataStructures.TreeChild;import com.liuhao.DataStructures.TreeChild.Node;public class TreeChildTest {@Testpublic void test() {TreeChild<String> tree = new TreeChild<String>("root");Node<String> root = tree.getRoot();System.out.println("根节点:" + root);tree.addNode("节点1", root);tree.addNode("节点2", root);tree.addNode("节点3", root);System.out.println("添加子节点后的根节点:" + root);System.out.println("树的深度:" + tree.getDeep());List<Node<String>> nodes = tree.getChildren(root);System.out.println("根节点的第一个子节点:" + nodes.get(0));tree.addNode("节点4", nodes.get(0));System.out.println("根节点的第一个子节点:" + nodes.get(0));System.out.println("树的深度:" + tree.getDeep());}}


显然,子节点链表示法中的每个节点都可以快速找到它的所有子节点,但相应的找父节点则比较麻烦。





0 0
原创粉丝点击