項目主頁: https://github.com/gozhuyinglong/blog-demos
本文源碼: https://github.com/gozhuyinglong/blog-demos/tree/main/java-data-structures
咱們前面講到了數組和鏈表兩種數據結構,其各自有本身的優缺點,咱們來回顧一下。java
優勢:經過下標訪問速度很是快。
缺點:須要檢索具體某個值時,或者插入值時(會總體移動)效率較低node
優勢:在插入某個值時,效率比數組高
缺點:檢索某個值時效率仍然較低git
咱們本篇講到的樹,便能提升數據的存儲和讀取效率。github
樹是一種非線性的數據結構,它包含n(n>=1)個節點,(n-1)條邊的有窮集合。把它叫作「樹」是由於它看起來像一個倒掛的樹,也就是說它是根朝上,葉子朝下的。算法
結合上圖瞭解樹的經常使用術語,加深對樹的理解。數組
樹結構中的每個元素稱爲一個節點,如上圖中的ABC......M數據結構
沒有父節點的節點叫作根節點,如上圖中的Aapp
一個節點的上級節點叫作它的父節點,一個節點最多隻能有一個父節點,如上圖中C是F的父節點ui
一個節點的下級節點叫作它的子節點,一個節點的子節點能夠有多個,如上圖中的IJK是E的子節點this
擁有相同父節點的節點叫作兄弟節點,如上圖中的L和M是兄弟節點
沒有子節點的節點叫作葉子節點,如圖中的BFGLMIJK
父子節點間的鏈接稱爲邊,一棵樹的邊數爲(n-1)
節點上的元素值
從root節點找到該節點的路線,如上圖中L的路徑爲A-D-H-L。路徑的長爲該路徑上邊的條數,L路徑的長爲3(n-1)。
距離根節點相等的路徑長度爲一層,如上圖中A爲第一層;BCDE爲第二層;FGHIJK爲第三層;LM爲第四層
以某一節點(非root)作爲根的樹稱爲子樹,如以E爲根的樹稱爲A的子樹
樹的最大層數,上圖中樹的高度爲4
多棵子樹構成樹林
咱們將第3章中的樹結構圖經過Java代碼進行實現。
TreeNode
類爲樹的一個節點,其中:
Tree
類實現了一棵樹的初始化和遍歷,listAll遍歷算法的核心是遞歸。具體內容見代碼
public class TreeDemo { public static void main(String[] args) { new Tree().initTree().listAll(); } private static class Tree { private TreeNode root; // 樹根 /** * 初始化一棵樹 */ private Tree initTree() { TreeNode a = new TreeNode("A"); TreeNode b = new TreeNode("B"); TreeNode c = new TreeNode("C"); TreeNode d = new TreeNode("D"); TreeNode e = new TreeNode("E"); TreeNode f = new TreeNode("F"); TreeNode g = new TreeNode("G"); TreeNode h = new TreeNode("H"); TreeNode i = new TreeNode("I"); TreeNode j = new TreeNode("J"); TreeNode k = new TreeNode("K"); TreeNode l = new TreeNode("L"); TreeNode m = new TreeNode("M"); root = a; a.firstChild = b; b.nextSibling = c; c.nextSibling = d; c.firstChild = f; d.nextSibling = e; d.firstChild = g; e.firstChild = i; g.nextSibling = h; h.firstChild = l; i.nextSibling = j; j.nextSibling = k; l.nextSibling = m; return this; } /** * 遍歷一棵樹,從root開始 */ public void listAll() { listAll(root, 0); } /** * 遍歷一棵樹 * * @param node 樹節點 * @param depth 層級(用於輔助輸出) */ public void listAll(TreeNode node, int depth) { StringBuilder t = new StringBuilder(); for (int i = 0; i < depth; i++) { t.append("\t"); } System.out.printf("%s%s\n", t.toString(), node.element); // 先遍歷子節點,子節點的層級須要+1 if (node.firstChild != null) { listAll(node.firstChild, depth + 1); } // 後遍歷兄弟節點,兄弟節點的層級不變 if (node.nextSibling != null) { listAll(node.nextSibling, depth); } } } private static class TreeNode { private final Object element; // 當前節點數據 private TreeNode firstChild; // 當前節點的第一個子節點 private TreeNode nextSibling; // 當前節點的下一個兄弟節點 public TreeNode(Object element) { this.element = element; } } }
輸出結果:
A B C F D G H L M E I J K