1. 程式人生 > >樹的父節點表示法及其Java實現

樹的父節點表示法及其Java實現

樹中除了根節點之外,每個節點都有且僅有一個父節點,為了記錄樹中節點與節點之間的父子關係,可以為每個節點增加一個parent域,用以記錄該節點的父節點。

對於下圖中的樹:

image

可以用下表來儲存:

image

由此可見,只要用一個節點陣列來儲存樹中的每個節點,並讓每個節點記錄其父節點在陣列中的索引即可。

Java實現程式碼

package com.liuhao.DataStructures;

import java.util.ArrayList;
import java.util.List;

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;
		}

		public String toString() {
			return "TreeParent$Node[data=" + data + ", parent=" + parent + "]";
		}
	}

	private final int DEFAULT_TREE_SIZE = 100;
	private int treeSize = 0;

	// 使用一個Node[]陣列來記錄該樹的所有節點
	private Node<E>[] nodes;

	// 記錄節點數
	private int nodeNums;

	// 以指定節點建立樹
	public TreeParent(E data) {
		this.treeSize = DEFAULT_TREE_SIZE;
		this.nodes = new Node[treeSize];
		nodes[0] = new Node<E>(data, -1);
		nodeNums++;
	}

	// 以指定根節點、指定treeSize建立樹
	public TreeParent(E data, int treeSize) {
		this.treeSize = treeSize;
		this.nodes = new Node[treeSize];
		nodes[0] = new Node<E>(data, -1);
		nodeNums++;
	}

	// 判斷是否為空
	public boolean isEmpty() {
		// 跟節點是否為空
		return nodes[0] == null;
	}

	// 返回包含指定節點的索引位置
	public int pos(Node<E> node) {
		for (int i = 0; i < treeSize; i++) {
			if (nodes[i] == node) {
				return i;
			}
		}
		return -1;
	}

	// 為指定節點新增子節點
	public void addNode(E data, Node<E> parent) {
		for (int i = 0; i < treeSize; i++) {
			// 找到陣列中第一個為null的節點,用該節點儲存新節點
			if (nodes[i] == null) {
				nodes[i] = new Node<E>(data, this.pos(parent));
				nodeNums++;
				return;
			}
		}
		throw new RuntimeException("該樹已滿,無法新增新節點");
	}

	// 獲取根節點
	public Node<E> getRoot() {
		return nodes[0];
	}

	// 獲取指定節點的父節點
	public Node<E> getParent(Node<E> node) {
		// 每個節點記錄了其父節點的位置
		return nodes[node.parent];
	}

	// 獲取指定節點的子節點
	public List<Node<E>> getChildren(Node<E> node) {
		List<Node<E>> list = new ArrayList<Node<E>>();
		for (int i = 0; i < treeSize; i++) {
			if (nodes[i] != null && nodes[i].parent == this.pos(node)) {
				list.add(nodes[i]);
			}
		}
		return list;
	}

	// 獲取樹的深度
	public int getDeep() {
		int max = 0;
		for (int i = 0; i < treeSize && nodes[i] != null; i++) {
			//初始化當前節點的深度
			int def = 1;
			//m記錄當前節點的父節點的位置
			int m = nodes[i].parent;
			while(m != -1 && nodes[m] != null){
				//繼續向上搜尋父節點
				m = nodes[m].parent;
				def++;
			}
			if(def > max){
				max = def;
			}
		}
		return max;
	}
	
	//刪除指定節點的子樹
	public void removeChildren(Node<E> node){
		for (int i = 0; i < treeSize; i++) {
			if (nodes[i] != null && nodes[i].parent == this.pos(node)) {
				nodes[i] = null;
				nodeNums--;
			}
		}
	}
}

測試程式碼:

package com.liuhao.test;

import java.util.List;

import org.junit.Test;

import com.liuhao.DataStructures.TreeParent;
import com.liuhao.DataStructures.TreeParent.Node;

public class TreeParentTest {

	@Test
	public void test() {
		TreeParent<String> tree = new TreeParent<String>("root");
		Node<String> root = tree.getRoot();
		System.out.println("根節點:" + root);
		
		tree.addNode("節點1", root);
		tree.addNode("節點2", root);
		System.out.println("樹的深度:" + tree.getDeep());
		
		List<Node<String>> nodes = tree.getChildren(root);
		System.out.println("根節點的第一個子節點:" + nodes.get(0));
		
		tree.addNode("節點3", nodes.get(0));
		System.out.println("樹的深度:" + tree.getDeep());
		
		tree.removeChildren(root);
		System.out.println("根節點的第一個子節點:" + nodes.get(0));
		System.out.println("樹的深度:" + tree.getDeep());
	}

}

通過上面的程式可以看出,父節點表示法可以方便的找出每個節點 的父節點,但是子節點的查詢很麻煩,需要遍歷整個樹。

您的關注是我堅持寫作的動力,如果覺得有用,歡迎關注我的微信,海量學習資源免費送!

你的關注是對我最大的鼓勵!