最近有点背...

数据结构之二叉树

二叉树概念

二叉树是指每个父节点最多有两个子节点的树。二叉树的定义是一个递归的定义,它很明确地区分了一个根节点的两个子树,分别是左子树和右子树。

这里写图片描述

相关术语

  • 节点
    树中每个元素叫作节点。
  • 根节点或树根
    树顶端的一个节点叫作树根。
  • 子树
    除根节点外,其他节点可以分为多个树的集合,叫作子树。
  • 节点的度
    一个节点直接含有的子树的个数叫做节点的度。如上图的6节点的度为2,分别是树根5、7.
  • 叶子节点
    度数为0的节点叫作叶子节点
  • 父节点、子节点
    父亲节点就是一个节点头上的那个节点。子节点就是一个节点下面的节点,可以是左节点或右节点。
  • 树的度
    一棵树中最大节点的度叫作树的度。
  • 树的深度、高度
    树的深度是从根节点开始(其深度为1)自顶向下逐层累加的。
    树的高度是从叶节点开始(其高度为1)自底向上逐层累加的。

    二叉树相关操作

    构建二叉树、遍历二叉树以及二叉树的常见算法
    注释已经很写的详细了,遇到不容易理解的地方,建议调试作图帮助理解。

  • 二叉树递归节点的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package Tree;

public class BinaryTreeNode {

private Integer data;//数据值
private BinaryTreeNode leftChild;//左孩子
private BinaryTreeNode rightChild;//右孩子

public BinaryTreeNode() {
}

public BinaryTreeNode(Integer data, BinaryTreeNode leftChild, BinaryTreeNode rightChild) {
this.data = data;
this.leftChild = leftChild;
this.rightChild = rightChild;
}

public Integer getData() {
return data;
}

public void setData(Integer data) {
this.data = data;
}

public BinaryTreeNode getLeftChild() {
return leftChild;
}

public void setLeftChild(BinaryTreeNode leftChild) {
this.leftChild = leftChild;
}

public BinaryTreeNode getRightChild() {
return rightChild;
}

public void setRightChild(BinaryTreeNode rightChild) {
this.rightChild = rightChild;
}
}
  • 操作二叉树
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package Tree;

import java.util.LinkedList;

public class BinaryTree {
public BinaryTreeNode root;

/**
* 构建一个二叉树 插入
* @param data
*/
public void add(Integer data) {
BinaryTreeNode binaryTreeNode = new BinaryTreeNode(data,null,null);
//引用当前节点
BinaryTreeNode current = root;
//引用父节点
BinaryTreeNode parent;
//判断根节点是否有值,如果root为null,也就是第一插入的时候
if(root == null) {
root = binaryTreeNode;
return;
} else {
while(true) {
//父节点指向当前节点
parent = current;
//如果插入的值比当前指向节点数据值要小,则向左走
if(data < current.getData()) {
current = current.getLeftChild();
if(current == null) {
parent.setLeftChild(binaryTreeNode);
return;
}
} else {
current = current.getRightChild();
if (current == null) {
parent.setRightChild(binaryTreeNode);
return;
}
}
}
}
}

/**
* 前序遍历
* 根左右
* @param root
*/
public void search_DLR(BinaryTreeNode root) {
if(root != null) {
System.out.print(root.getData()+" ");
search_DLR(root.getLeftChild());
search_DLR(root.getRightChild());
}
}

/**
* 中序遍历
* 左根右
* @param root
*/
public void search_LDR(BinaryTreeNode root) {
if(root !=null) {
search_LDR(root.getLeftChild());
System.out.print(root.getData()+" ");
search_LDR(root.getRightChild());
}
}

/**
* 后序遍历
* 左右根
* @param root
*/
public void search_LRD(BinaryTreeNode root) {
if(root !=null) {
search_LRD(root.getLeftChild());
search_LRD(root.getRightChild());
System.out.print(root.getData()+" ");
}
}

/*
* 按层进行遍历
* 总体思路就是把树种节点存入到linkedlist模拟的队列中去
* 把头元素移出的同时把它的左右孩子插入到队列当中去 如果有的话
* 这样不断进行这个操作 弹出头结点的同时输出头结点知道队列为空 按层遍历
* @param root
*/
public void search_level(BinaryTreeNode root) {
//把数据存到一个队列里面 这里面用链表来模拟队列
LinkedList<BinaryTreeNode> list = new LinkedList<BinaryTreeNode>();
BinaryTreeNode binaryTreeNode = root;
BinaryTreeNode result = null;
//先把根节点插入进去 判断根节点是否有值
if(binaryTreeNode != null) {
list.addLast(binaryTreeNode);
//弹出根节点值
result = list.poll();
//不断判断弹出节点的返回值 如果没有节点了则弹出null 做终止判断
while(result!=null) {
System.out.print(result.getData()+" ");
//判断当前队列中第一个元素是否含有左右孩子如果含有则插入到队列中
if(binaryTreeNode.getLeftChild()!=null) {
list.addLast(binaryTreeNode.getLeftChild());
}
if(binaryTreeNode.getRightChild()!=null) {
list.addLast(binaryTreeNode.getRightChild());
}
//当前队列不为空时 BinaryTreeNode变量始终指向队列头元素
if(list.size() != 0) {
binaryTreeNode = list.getFirst();
}
//弹出头元素并循环判断其是否为空是否含有左右孩子
result = list.poll();
}
} else {
System.out.println("当前为空树");
}
}

/**
* 获取二叉树的节点个数
* @param root
* @return
*/
public int size(BinaryTreeNode root) {
if(root == null) {
return 0;
} else {
return 1 + size(root.getLeftChild()) + size(root.getRightChild());
}
}

/**
* 获取二叉树的叶子数
* @param root
* @return
*/
public int leafSize(BinaryTreeNode root) {
if(root == null) {
return 0;
}
if(root.getLeftChild() == null && root.getRightChild() == null) {
return 1;
}
return leafSize(root.getLeftChild()) + leafSize(root.getRightChild());
}

/**
* 获取第k层节点的个数
* @param root
* @param k
* @return
*/
public int kLevelSize(BinaryTreeNode root, int k) {
if(root == null || k < 1) {
return 0;
}
if(k == 1) {
return 1;
}
return kLevelSize(root.getLeftChild(),k-1) + kLevelSize(root.getRightChild(),k-1);
}

/**
* 查找当前树的深度
* 如果根节点为空则深度为0 如果不为空 递归调用左右孩子比较谁大谁大就返回谁
* 求二叉树高度的方法一样
* @param root
* @return
*/
public int search_depth(BinaryTreeNode root) {
if(root == null) {
return 0;
} else {
int left = search_depth(root.getLeftChild()) + 1;
int right = search_depth(root.getRightChild()) + 1;
return left > right ? left : right;
}
}

/**
* 给定一个节点,返回左右子树
* @param data
* @return
*/
public BinaryTreeNode searchByData(Integer data) {
BinaryTreeNode binaryTreeNode = this.root;
BinaryTreeNode result = null;
if(data == binaryTreeNode.getData()) {
result = binaryTreeNode;
} else {
//判断当前节点与目标节点的大小比值
while(binaryTreeNode!=null && binaryTreeNode.getData() < data) {
binaryTreeNode = binaryTreeNode.getRightChild();
}
while(binaryTreeNode!=null && data < binaryTreeNode.getData()) {
binaryTreeNode = binaryTreeNode.getLeftChild();
}
if(binaryTreeNode !=null) {
result = binaryTreeNode;
}
}
return result;
}

public BinaryTreeNode getRoot() {
return root;
}

public void setRoot(BinaryTreeNode root) {
this.root = root;
}

}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package Tree;

public class TestBinaryTree {
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
tree.add(4);
tree.add(6);
tree.add(2);
tree.add(3);
tree.add(7);
tree.add(8);
tree.add(5);

System.out.println("前序遍历");
tree.search_DLR(tree.getRoot());
System.out.println();
System.out.println("中序遍历");
tree.search_LDR(tree.getRoot());
System.out.println();
System.out.println("后序遍历");
tree.search_LRD(tree.getRoot());
System.out.println();
System.out.println("按层遍历");
tree.search_level(tree.getRoot());
System.out.println();

System.out.println("当前树的深度");
System.out.println(tree.search_depth(tree.getRoot()));

System.out.println("二叉树的节点个数");
System.out.println(tree.size(tree.getRoot()));

System.out.println("二叉树的叶子个数");
System.out.println(tree.leafSize(tree.getRoot()));

System.out.println("获取第k层节点的个数");
System.out.println(tree.kLevelSize(tree.getRoot(),3));

System.out.println("查找某一元素");
BinaryTreeNode node = tree.searchByData(6);
if(node!=null){
System.out.println("当前元素为"+node.getData()+" 左孩子为"+node.getLeftChild().getData()+" 右孩子为"+node.getRightChild().getData());
}else{
System.out.println("当前元素不存在");
}


}
}
  • 运行结果
    这里写图片描述