二叉排序树

二叉排序树

在线性表中,我们可以通过数组和链表对数据进行查询、添加、删除。

在数组中查询的时间复杂度为O(1) , 添加删除的操作时间复杂度为O(n)

在链表中查询的时间复杂度为O(n) ,添加删除的操作时间复杂度为O(1) 【且当前已找到需要删除的数据】

因此我们通过二叉树来存储数据,以及与数据的一些处理。

二叉排序树的定义

二叉排序树(BST),又称二叉查找树、二叉搜索树。

对于二叉排序树的任何一个非叶子节点,要求左子节点的值比当前节点的值小,右子节点比当前节点的值大。

特别说明,如果有相同的值,可以将该节点放在左子节点或右子节点。

比如对下面的一组数据(7,3,10,8,5,15,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
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
class Node{
public int val;
public Node leftNode;
public Node rightNode;

public Node(int i) {
this.val = i;
}

//中序遍历
public void infixOrder(){
if(this.leftNode != null){
this.leftNode.infixOrder();
}

System.out.print(this.val + "\t");

if(this.rightNode != null){
this.rightNode.infixOrder();
}
}

//添加节点
public void add(Node node){
if(node == null)
return;
//如果新添加节点小于当前节点
if(node.val < this.val){
if(this.leftNode == null){
this.leftNode = node;
}else{
this.leftNode.add(node);
}
}else{//如果新添加节点大于等于当前节点
if(this.rightNode == null){
this.rightNode = node;
}else{
this.rightNode.add(node);
}
}


}
}

class Tree{
private Node root;

public Tree() {
}

//中序遍历
public void infixOrder(){
if(this.root != null){
this.root.infixOrder();
}else{
System.out.println("二叉排序树为空");
}
}

//二叉排序树添加节点
public void add(Node node){
if(root == null){
root = node;
}else{
root.add(node);
}
}
}


public class BinarySortTree {

public static void main(String[] args) {
Node node1 = new Node(7);
Node node2 = new Node(3);
Node node3 = new Node(10);
Node node4 = new Node(8);
Node node5 = new Node(5);
Node node6 = new Node(15);
Node node7 = new Node(1);

Tree tree = new Tree();

tree.add(node1);
tree.add(node2);
tree.add(node3);
tree.add(node4);
tree.add(node5);
tree.add(node6);
tree.add(node7);

tree.infixOrder(); //1 3 5 7 8 10 15

}
}

二叉排序树的删除

二叉排序树的删除需要考虑三种情况:

1、删除叶子节点

2、删除只有一个子树的节点

3、删除有两颗子树的节点

我们重新创建一个二叉排序树,节点值为:【7,3,10,12,5,1,9,2】

二叉排序树为:
在这里插入图片描述

第一种情况:删除节点2、5、9、12

1、找到需要删除的节点

2、找到需要删除节点的父节点

3、判断需要删除节点是父节点的左子节点或右子节点

4、如果为左子节点,parent.leftNode = null,如果为右子节点,parent.rightNode = null

删除节点2之后:
在这里插入图片描述

第二种情况:删除节点1

1、找到需要删除的节点targetNode

2、找到targetNode的父节点parent

3、确定targetNode的子结点是左子结点还是右子节点

4、确定targetNode是parent的左子节点还是右子节点。

5、如果targetNode有左子节点

​ 5.1、如果targetNode是parent的左子节点 parent.leftNode = targetNode.left;

​ 5.2、如果targetNode是parent的右子节点 parent.rightNode = targetNode.left;

6、如果targetNode有右子节点

​ 5.1、如果targetNode是parent的左子节点 parent.leftNode = targetNode.right;

​ 5.2、如果targetNode是parent的右子节点 parent.rightNode = targetNode.right;

删除节点1之后:
在这里插入图片描述

第三种情况 :删除节点3,10

1、找到需要删除的节点targetNode

2、找到targetNode的父节点parent

3、从targetNode的右子树中找到最小的节点【或者左子树中找到最大节点】 。

4、用一个临时变量,将最小的节点的值保存到temp中。

5、删除右子树中最小的节点【或左子树中最大的节点】

6、targetNode.val = temp;

删除节点3之后:

在这里插入图片描述

代码:

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
class Node{
public int val;
public Node leftNode;
public Node rightNode;

public Node(int i) {
this.val = i;
}

//中序遍历
public void infixOrder(){
if(this.leftNode != null){
this.leftNode.infixOrder();
}

System.out.print(this.val + "\t");

if(this.rightNode != null){
this.rightNode.infixOrder();
}
}

//添加节点
public void add(Node node){
if(node == null)
return;
//如果新添加节点小于当前节点
if(node.val < this.val){
if(this.leftNode == null){
this.leftNode = node;
}else{
this.leftNode.add(node);
}
}else{//如果新添加节点大于等于当前节点
if(this.rightNode == null){
this.rightNode = node;
}else{
this.rightNode.add(node);
}
}


}

//查找需要删除的节点
public Node Search(int val){
if(this.val == val){
return this;
}else if(this.val < val){
if(this.rightNode == null)
return null;
return this.rightNode.Search(val);
}else{
if(this.leftNode == null)
return null;

return this.leftNode.Search(val);
}
}

//查找需要删除节点的父节点
public Node SearchParent(int val){
if((this.leftNode != null && this.leftNode.val == val) || (this.rightNode != null && this.rightNode.val == val)) {
return this;
}else{
//如果查找的值小于当前节点的值,并且当前节点的左子节点不为空
if (val < this.val && this.leftNode != null){
return this.leftNode.SearchParent(val);
}else if (val >= this.val && this.rightNode != null){
return this.rightNode.SearchParent(val);
}else{
return null;
}
}
}

}

class Tree{
private Node root;

public Tree() {
}

//中序遍历
public void infixOrder(){
if(this.root != null){
this.root.infixOrder();
}else{
System.out.println("二叉排序树为空");
}
}

//二叉排序树添加节点
public void add(Node node){
if(root == null){
root = node;
}else{
root.add(node);
}
}


//查找需要删除的节点
public Node Search(int val){
if(root == null){
return null;
}else{
return root.Search(val);
}
}

//查找父节点
public Node SearchParent(int val){
if(this.root == null) {
return null;
}else{
return root.SearchParent(val);
}


}

//找到需要删除节点的右子树的最小值
public int delRightTreeMin(Node node){
Node target = node;
while(target.leftNode != null){
target = target.leftNode;
}

delNode(target.val);

return target.val;
}


//删除节点
public void delNode(int val){
if(root == null) {
return;
} else{
//1、找到需要删除的节点
Node targetNode = Search(val);
if(targetNode == null){
return;
}

//如果当前二叉排序树只有一个节点
if(root.leftNode == null || root.rightNode == null){
root = null;
return;
}

//找到targetNode 的父节点,因为不是根节点,所以一定右父节点
Node parent = SearchParent(val);

//如果要删除的节点是叶子节点
if(targetNode.leftNode == null && targetNode.rightNode == null){
if(parent.leftNode != null && parent.leftNode.val == val){
parent.leftNode = null;
}else if(parent.rightNode != null && parent.rightNode.val == val){
parent.rightNode = null;
}
//如果删除的节点右两个子结点
}else if(targetNode.leftNode != null && targetNode.rightNode != null){
int minVal = delRightTreeMin(targetNode.rightNode);
targetNode.val = minVal;
}else{//如果删除的节点只有一个子结点
//子结点为左节点时
if(targetNode.leftNode != null){
if(parent != null){
if(parent.leftNode.val == val){
parent.leftNode = targetNode.leftNode;
}else{
parent.rightNode = targetNode.leftNode;
}
}else{
root = targetNode.leftNode;
}
}else{
//子结点为右节点时
if(parent != null){
if(parent.leftNode.val == val){
parent.leftNode = targetNode.rightNode;
}else{
parent.rightNode = targetNode.rightNode;
}
}else{
root = targetNode.rightNode;
}
}
}
}
}

}

测试:

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
public static void main(String[] args) {
Node node1 = new Node(7);
Node node2 = new Node(3);
Node node3 = new Node(10);
Node node4 = new Node(12);
Node node5 = new Node(5);
Node node6 = new Node(1);
Node node7 = new Node(9);
Node node8 = new Node(2);

Tree tree = new Tree();

tree.add(node1);
tree.add(node2);
tree.add(node3);
tree.add(node4);
tree.add(node5);
tree.add(node6);
tree.add(node7);
tree.add(node8);

tree.infixOrder();
System.out.println();

tree.delNode(1); //2 3 5 7 9 10 12
tree.delNode(12); //2 3 5 7 9 10
tree.delNode(10); //2 3 5 7 9
tree.infixOrder();
}

二叉排序树
https://johnjoyjzw.github.io/2020/01/08/二叉排序树/
Author
John Joy
Posted on
January 8, 2020
Licensed under