树:
定义:
树是n个节点的有限集。n=0时称为空树。在任意一颗非空树中:
(1)有且仅有一个特定的称为根(Root)的结点,
(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、T3、……Tm,其中每一个集合本身又是一颗树,并称为根的子树,如下图
概念:
- 树的结点包含一个数据元素及若干指向其子树的分支。结点拥有的子树数称为结点的度(Degree)。度为0的结点称为叶结点(Leaf) 或终端结点;度不为0的结点称为非终端结点或分支结点。除根结点之外,分支结点也称为内部结点。树的度是树内各结点的度的最大值。因为这棵树结点的度的最大值是结点D的度为3,所以树的度也为3,如下图:
- 结点的子树的根称为该结点的孩子,相应的,该结点称为孩子的双亲。同一个双亲的孩子之间互称兄弟,如下图:
- 结点的层次从根开始,根为第一层,根的孩子为第二层。双亲在同一层的结点互为堂兄弟,树中结点的最大层次称为树的深度或者高度,如下图:
树的父节点表示法:
代码语言:javascript复制 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 }
程序运行结果:
代码语言:javascript复制TreeParent$Node[data=root, parent=-1]
此树的深度2
根节点的第一个子节点为:TreeParent$Node[data=节点1, parent=0]
此树的深度:3
树的子节点表示法:
代码语言:javascript复制 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 }
程序运行结果:
代码语言:javascript复制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