樹:
定義:
樹是n個節點的有限集。n=0時稱為空樹。在任意一顆非空樹中:(1)有且僅有一個特定的稱為根(Root)的結點,(2)當n>1時,其余結點可分為m(m>0)個互不相交的有限集T1、T2、T3、……Tm,其中每一個集合本身又是一顆樹,並稱為根的子樹,如下圖
概念:
- 樹的結點包含一個數據元素及若干指向其子樹的分支。結點擁有的子樹數稱為結點的度(Degree)。度為0的結點稱為葉結點(Leaf) 或終端結點;度不為0的結點稱為非終端結點或分支結點。除根結點之外,分支結點也稱為內部結點。樹的度是樹內各結點的度的最大值。因為這棵樹結點的度的最大值是結點D的度為3,所以樹的度也為3,如下圖:
結點的子樹的根稱為該結點的孩子,相應的,該結點稱為孩子的雙親。同一個雙親的孩子之間互稱兄弟,如下圖:
- 結點的層次從根開始,根為第一層,根的孩子為第二層。雙親在同一層的結點互為堂兄弟,樹中結點的最大層次稱為樹的深度或者高度,如下圖:
樹的父節點表示法:
1 import java.util.ArrayList; 2 import java.util.List; 3 4 5 /** 6 * 樹的父節點表示法 7 * @author wydream 8 * 9 */ 10 11 public class TreeParent<E> { 12 13 //定義一個樹類 14 public static class Node<T>{ 15 T data;//保存數據 16 int parent;//保存父節點的位置 17 public Node(){ 18 19 } 20 21 public Node(T data) { 22 this.data=data; 23 } 24 25 //指定根節點 26 public Node(T data,int parent) { 27 this.data=data; 28 this.parent=parent; 29 } 30 31 public String toString() { 32 return "TreeParent$Node[data=" + data + ", parent=" + parent + "]"; 33 } 34 } 35 36 private final int DEFAULT_TREE_SIZE=100;//樹的默認大小 37 private int treeSize=0;//樹的實際大小 38 //使用一個node數組來記錄該樹里的所有節點 39 private Node<E>[] nodes; 40 //記錄樹的節點數 41 private int nodeNums; 42 43 //以指定節點創建樹 44 public TreeParent(E data) { 45 treeSize=DEFAULT_TREE_SIZE; 46 nodes=new Node[treeSize]; 47 nodes[0]=new Node<E>(data,-1); 48 nodeNums++; 49 } 50 51 //以指定根節點、指定treeSize創建樹 52 public TreeParent(E data,int treeSize){ 53 this.treeSize=treeSize; 54 nodes=new Node[treeSize]; 55 nodes[0]=new Node<E>(data,-1); 56 nodeNums++; 57 } 58 59 //為指定節點添加子節點 60 public void addNode(E data,Node<E> parent) { 61 for(int i=0;i<treeSize;i++) { 62 // 找到數組中第一個為null的元素,該元素保存新節點 63 if(nodes[i]==null) { 64 nodes[i]=new Node<E>(data,pos(parent)); 65 nodeNums++; 66 return; 67 } 68 // 創建新節點,並用指定的數組元素保存它 69 } 70 throw new RuntimeException("該樹已滿"); 71 } 72 73 // 判斷樹是否為空 74 public boolean isEmpty() { 75 return nodes[0]==null; 76 } 77 78 // 返回根節點 79 public Node<E> root() { 80 return nodes[0]; 81 } 82 83 // 返回指定節點(非根結點)的父節點 84 public Node<E> parent(Node<E> node) { 85 return nodes[node.parent]; 86 } 87 88 // 返回指定節點(非葉子節點)的所有子節點 89 public List<Node<E>> children(Node<E> parent){ 90 List<Node<E>> list=new ArrayList<Node<E>>(); 91 for(int i=0;i<treeSize;i++) { 92 // 如果當前節點的父節點的位置等於parent節點的位置 93 if(nodes[i]!=null&&nodes[i].parent==pos(parent)) { 94 list.add(nodes[i]); 95 } 96 } 97 return list; 98 } 99 100 // 返回該樹的深度 101 public int deep() { 102 //用於記錄節點的最大深度 103 int max=0; 104 for(int i=0;i<treeSize&&nodes[i]!=null;i++) { 105 //初始化本節點的深度 106 int def=1; 107 //m 記錄當前節點的父節點的位置 108 int m=nodes[i].parent; 109 //如果其父節點存在 110 while(m!=-1&&nodes[m]!=null) { 111 //向上繼續搜索父節點 112 m=nodes[m].parent; 113 def++; 114 } 115 if(max<def) { 116 max=def; 117 } 118 } 119 return max; 120 } 121 122 //返回包含指定值的節點 123 public int pos(Node<E> node) { 124 for(int i=0;i<treeSize;i++) { 125 //找到指定節點 126 if(nodes[i]==node) { 127 return i; 128 } 129 } 130 return -1; 131 } 132 133 134 //測試 135 public static void main(String[] args) { 136 TreeParent<String> tp=new TreeParent<String>("root"); 137 TreeParent.Node root=tp.root(); 138 System.out.println(root); 139 tp.addNode("節點1", root); 140 System.out.println("此樹的深度"+tp.deep()); 141 tp.addNode("節點2",root); 142 //獲取根節點的所有子節點 143 List<TreeParent.Node<String>> nodes=tp.children(root); 144 System.out.println("根節點的第一個子節點為:"+nodes.get(0)); 145 // 為根節點的第一個子節點新增一個子節點 146 tp.addNode("節點3", nodes.get(0)); 147 System.out.println("此樹的深度:" + tp.deep()); 148 149 } 150 }
程序運行結果:
TreeParent$Node[data=root, parent=-1] 此樹的深度2 根節點的第一個子節點為:TreeParent$Node[data=節點1, parent=0] 此樹的深度:3
樹的子節點表示法:
1 import java.util.ArrayList; 2 import java.util.List; 3 4 /** 5 * 樹的子節點表示法 6 * @author wydream 7 * 8 */ 9 10 11 public class TreeChild<E> { 12 13 private static class SonNode{ 14 //記錄當前節點的位置 15 private int pos; 16 private SonNode next; 17 18 public SonNode(int pos,SonNode next) { 19 this.pos=pos; 20 this.next=next; 21 } 22 23 } 24 25 public static class Node<T>{ 26 T data; 27 SonNode first;//記錄第一個子節點 28 29 public Node(T data) { 30 this.data=data; 31 this.first=null; 32 } 33 34 public String toString() { 35 if (first != null) { 36 return "TreeChild$Node[data=" + data + ", first=" + first.pos + "]"; 37 } else { 38 return "TreeChild$Node[data=" + data + ", first=-1]"; 39 } 40 } 41 } 42 43 private final int DEFAULT_TREE_SIZE = 100; 44 private int treeSize=0; 45 46 // 使用一個Node[]數組來記錄該樹里的所有節點 47 private Node<E>[] nodes; 48 49 //記錄節點數 50 private int nodeNums; 51 52 // 以指定根節點創建樹 53 public TreeChild(E data) { 54 treeSize=DEFAULT_TREE_SIZE; 55 nodes=new Node[treeSize]; 56 nodes[0]=new Node<E>(data); 57 nodeNums++; 58 } 59 60 // 以指定根節點、指定treeSize創建樹 61 public TreeChild(E data,int treeSize) { 62 this.treeSize=treeSize; 63 nodes=new Node[treeSize]; 64 nodes[0]=new Node<E>(data); 65 nodeNums++; 66 } 67 68 // 為指定節點添加子節點 69 public void addNode(E data,Node parent) { 70 for(int i=0;i<treeSize;i++) { 71 // 找到數組中第一個為null的元素,該元素保存新節點 72 if(nodes[i]==null) { 73 // 創建新節點,並用指定數組元素保存它 74 nodes[i]=new Node(data); 75 if(parent.first==null) { 76 parent.first=new SonNode(i, null); 77 }else { 78 SonNode next=parent.first; 79 while(next.next!=null) { 80 next=next.next; 81 } 82 next.next = new SonNode(i, null); 83 } 84 nodeNums++; 85 return; 86 } 87 } 88 throw new RuntimeException("該樹已滿,無法添加節點"); 89 } 90 91 //判斷樹是否為空 92 public boolean isEmpty() { 93 return nodes[0]==null; 94 } 95 96 //返回根節點 97 public Node<E> root(){ 98 return nodes[0]; 99 } 100 101 //返回指定節點的所有子節點 102 public List<Node<E>> children(Node<E> parent){ 103 List<Node<E>> list=new ArrayList<Node<E>>(); 104 // 獲取parent節點的第一個子節點 105 SonNode next=parent.first; 106 // 沿着孩子鏈不斷搜索下一個孩子節點 107 while(next!=null) { 108 list.add(nodes[next.pos]); 109 next=next.next; 110 } 111 return list; 112 } 113 114 // 返回指定節點(非葉子節點)的第index個子節點 115 public Node<E> child(Node parent,int index){ 116 // 獲取parent節點的第一個子節點 117 SonNode next=parent.first; 118 // 沿着孩子鏈不斷搜索下一個孩子節點 119 for(int i=0;next!=null;i++) { 120 if(index==i) { 121 return nodes[next.pos]; 122 } 123 next=next.next; 124 } 125 return null; 126 } 127 128 // 返回該樹的深度 129 public int deep() { 130 // 獲取該樹的深度 131 return deep(root()); 132 } 133 134 // 這是一個遞歸方法:每棵子樹的深度為其所有子樹的最大深度 + 1 135 public int deep(Node node) { 136 if(node.first==null) { 137 return 1; 138 }else { 139 // 記錄其所有子樹的最大深度 140 int max=0; 141 SonNode next=node.first; 142 // 沿着孩子鏈不斷搜索下一個孩子節點 143 while(next!=null) { 144 // 獲取以其子節點為根的子樹的深度 145 int tmp=deep(nodes[next.pos]); 146 if(tmp>max) { 147 max=tmp; 148 } 149 next=next.next; 150 } 151 // 最后,返回其所有子樹的最大深度 + 1 152 return max + 1; 153 } 154 } 155 156 157 // 返回包含指定值得節點 158 public int pos(Node node) { 159 for (int i = 0; i < treeSize; i++) { 160 // 找到指定節點 161 if (nodes[i] == node) { 162 return i; 163 } 164 } 165 return -1; 166 } 167 168 //測試 169 public static void main(String[] args) { 170 171 TreeChild<String> tp = new TreeChild<String>("root"); 172 TreeChild.Node root = tp.root(); 173 System.out.println(root); 174 tp.addNode("節點1", root); 175 tp.addNode("節點2", root); 176 tp.addNode("節點3", root); 177 System.out.println("添加子節點后的根結點:" + root); 178 System.out.println("此樹的深度:" + tp.deep()); 179 // 獲取根節點的所有子節點 180 List<TreeChild.Node<String>> nodes = tp.children(root); 181 System.out.println("根節點的第一個子節點:" + nodes.get(0)); 182 // 為根節點的第一個子節點新增一個子節點 183 tp.addNode("節點4", nodes.get(0)); 184 System.out.println("此樹第一個子節點:" + nodes.get(0)); 185 System.out.println("此樹的深度:" + tp.deep()); 186 187 } 188 189 190 191 192 }
程序運行結果:
TreeChild$Node[data=root, first=-1] 添加子節點后的根結點:TreeChild$Node[data=root, first=1] 此樹的深度:2 根節點的第一個子節點:TreeChild$Node[data=節點1, first=-1] 此樹第一個子節點:TreeChild$Node[data=節點1, first=4] 此樹的深度:3