前言

对二叉树有一定了解之后,学习一下对二叉树的操作,有时候这些东西一学就忘,反复操作几回就熟了。
二叉树的概念已经了解了,那么得知道怎么操作。现在就讲讲怎么操作二叉树。

构建二叉树

首先得先种一颗树,然后才能操作树。
怎么构建?有哪些对象、需要什么方法?

主要对象

  1. Node 节点对象
  2. BinaryTree 树对象

Node 节点对象

作用:存数据的。
大白话就是树中的每一个节点,存着外面进来的数据。最简单的理解就是HashMap就是一颗树的实现,每次不明白,就想想HashMap,是不是就通了。

四个关键要素:

  1. left
  2. right
  3. key
  4. value

BinaryTree 对象

作用:操作node节点数据,维护树结构。
大白话,就是把Node拼起来,成为一颗大树。
主要操作:

  1. put
  2. get
  3. delete
  4. size
  5. min
  6. max

put 完以后要返回整棵树,开始是始于 root,返回也是返回 root。

实现

实现就是把NodeBinaryTree这两结合起来用,还用的没问题。
需要考虑几个问题:

  1. 怎么结合起来用
  2. 从哪开始写

怎么结合起来用?
即然要操作,那就需要对外暴露操作接口BinaryTree就是最外操作的对象。

从哪开始写?
先定义数据结构,再定义方法。

查询 和 添加 逻辑基本相同,都是通过递归的形式。
删除比较麻烦,如果被删除的节点有子节点,不能让丢掉这些子节点,需要重新维护这些子节点。
删除的节点,左子树的所有节点一定比右子树的节点小,所以只需要从右子树中拿到最小的那个节点即可,也就是右子树中最左边的叶子节点。

删除步骤

  1. 找到要删除的 key

  2. 判断如果左子树为空,就用右边最小

  3. 判断如果右子树为空,就用左边最小

  4. 删除找到的最小值

  5. 将最小值替换被删除的节点,重新跟左右子节点建立连接

  6. 简化的情况
    被删除节点只有一个 左子树 或 右子树,直接拿过来替换当前节点就行

实现代码:

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
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;

/**
* 二叉树
* 左小右大
*
* @author liu kai
* @since 2015/5/30 19:30.
*/
public class BinaryTree<Key extends Comparable<Key>, Value> {

//根节点
private Node root;
//个数
private int size;

private class Node {
public Node left;
public Node right;
public Key key;
public Value value;

public Node(Key key, Value value, Node left, Node right) {
this.left = left;
this.right = right;
this.key = key;
this.value = value;
}
}

public void put(Key key, Value value) {
root = put(root, key, value);
}

// 插入
private Node put(Node x, Key key, Value value) {
if (x == null) {
size++;
return new Node(key, value, null, null);
}
int comp = key.compareTo(x.key);
// key 比当前节点小,往左
if (comp > 0) {
x.right = put(x.right, key, value);
// key 比当前节点大,往右
} else if (comp < 0) {
x.left = put(x.left, key, value);
// 相等,就是当前节点,替换值
} else {
x.value = value;
}
return x;
}

// 查询
public Value get(Key key) {
return get(root, key);
}

private Value get(Node x, Key key) {
if (x == null) {
return null;
}

int comp = key.compareTo(x.key);
// key 比当前节点小,往左
if (comp > 0) {
return get(x.right, key);
// key 比当前节点大,往右
} else if (comp < 0) {
return get(x.left, key);
// 相等,就是当前节点,替换值
} else {
return x.value;
}
}

public int size() {
return size;
}

public Node delete(Key key) {
return delete(root, key);
}

// x 当前要被删除的点节
private Node delete(Node x, Key key) {
if (x == null) {
return null;
}
int comp = key.compareTo(x.key);
// 1 张三
// / \
// 2李四 3王五
// \
// 4工作
if (comp > 0) {
x.right = delete(x.right, key);
} else if (comp < 0) {
x. left = delete(x.left, key);
} else {

//1.简单情况:
// 被删除节点只有一个 左子树 或 右子树,直接拿过来替换当前节点就行
if (x.left == null) {
size--;
return x.right;
}
if (x.right == null) {
size--;
return x.left;
}
size--;
Node minNode = x.right;
//2.找到最左节点
while (minNode.left != null) {
// 如果 minNode 没有子节点了,说明 minNode 是最小节点
// 这里 minNode 是当前节点, .left 就是它的子节点
minNode = minNode.left;
}

// 3.断开最左节点和上个节点的联系
// 由于没有记录父节点是谁,所以需要再次遍历
Node parent = x.right;
while (parent.left != null) {
// 当前节点的子节点没有子节点,就是最小节点
if (parent.left.left != null) {
parent.left = null;
} else {
parent = parent.left;
}
}

// 4.建立连接
// 再跟左右子树建立连接,再跟父节点建立连接
minNode.left = x.left;
minNode.right = x.right;

return x;
}
return x;
}
}

总结

二叉树的构建和查找,相对比较简单,需要理清的是这个操作,有些写法经常不用就会忘。
为什么业务中用的东西不会忘,因为你天天在写,如果你天天写这些东西,你也不会忘的,唯手熟尔。