next = tree.ceilingEntry(r + 1);
56 | if (next != null && next.getValue().v == v && next.getKey() == r + 1) {
57 | tree.remove(next.getKey());
58 | r = next.getValue().r;
59 | }
60 |
61 | tree.put(l, new Node(l, r, v));
62 | }
63 |
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/datastructrue/src/rbtree/RBTree.java:
--------------------------------------------------------------------------------
1 | package rbtree;
2 |
3 | /**
4 | * 红黑树的实现
5 | *
6 | * 2-3-4树是四阶的 B树(Balance Tree),它的结构有以下限制:
7 | *
8 | * 所有叶子节点都拥有相同的深度。
9 | * 节点只能是 2-节点、3-节点、4-节点之一。
10 | *
11 | * 2-节点:包含 1 个元素的节点,有 2 个子节点;
12 | * 3-节点:包含 2 个元素的节点,有 3 个子节点;
13 | * 4-节点:包含 3 个元素的节点,有 4 个子节点;
14 | * 元素始终保持排序顺序,整体上保持二叉查找树的性质,
15 | * 即父结点大于左子结点,小于右子结点;而且结点有多个元素时,每个元素必须大于它左边的和它的左子树中元素。
16 | *
17 | * 红黑树就是2-3-4树的一种等同实现
18 | *
19 | * 红黑树和 2-3-4树的结点添加和删除都有一个基本规则:避免子树高度变化。
20 | * 因为无论是 2-3-4树还是红黑树,一旦子树高度有变动,势必会影响其他子树进行调整,所以我们在插入和删除结点时尽量通过子树内部调整来达到平衡。
21 | * 2-3-4树实现平衡是通过结点的旋转和结点元素数变化,红黑树是通过结点旋转和变色。
22 | *
23 | * 插入和删除方法上来对照着 2-3-4树说一下红黑树结点的添加和删除
24 | *
25 | * @param 泛型Key
26 | */
27 | public class RBTree> {
28 |
29 | private RBTreeNode root;// 红黑树根节点
30 |
31 | // Red-black mechanics
32 |
33 | private static final boolean RED = false;
34 | private static final boolean BLACK = true;
35 |
36 | /**
37 | * 红黑树节点
38 | *
39 | * @param
40 | */
41 | private static final class RBTreeNode> {
42 | T key;// 键值
43 | RBTreeNode left;
44 | RBTreeNode right;
45 | RBTreeNode parent;
46 | boolean color = BLACK;// 节点默认黑色
47 |
48 | RBTreeNode(T key) {
49 | this(key, null);
50 | }
51 |
52 | RBTreeNode(T key, RBTreeNode parent) {
53 | this.key = key;
54 | this.parent = parent;
55 | }
56 |
57 | public T getKey() {
58 | return key;
59 | }
60 |
61 | @Override
62 | public int hashCode() {
63 | return key == null ? 0 : key.hashCode();
64 | }
65 |
66 | }
67 |
68 | //--以下设计这些方法避免大量的空指针判断
69 |
70 | /**
71 | * 关于节点的颜色
72 | *
73 | * 空节点都是黑色
74 | *
75 | * @param node RBTNode
76 | * @return color
77 | */
78 | private boolean colorOf(RBTreeNode node) {
79 | return node == null ? BLACK : node.color;
80 | }
81 |
82 | /**
83 | * 设置节点的颜色
84 | *
85 | * @param node RBTNode
86 | * @param color color
87 | */
88 | private void setColor(RBTreeNode node, boolean color) {
89 | if (node != null) {
90 | node.color = color;
91 | }
92 | }
93 |
94 | /**
95 | * 关于节点的父亲
96 | *
97 | * @param node RBTNode
98 | * @return node.parent
99 | */
100 | private RBTreeNode parentOf(RBTreeNode node) {
101 | return node == null ? null : node.parent;
102 | }
103 |
104 | /**
105 | * 关于节点的左孩子
106 | *
107 | * @param node RBTNode
108 | * @return node.left
109 | */
110 | private RBTreeNode leftOf(RBTreeNode node) {
111 | return node == null ? null : node.left;
112 | }
113 |
114 | /**
115 | * 关于节点的右孩子
116 | *
117 | * @param node RBTNode
118 | * @return node.right
119 | */
120 | private RBTreeNode rightOf(RBTreeNode node) {
121 | return node == null ? null : node.right;
122 | }
123 |
124 | /**
125 | * 关于节点的key
126 | *
127 | * @param node RBTNode
128 | * @return key
129 | */
130 | private T keyOf(RBTreeNode node) {
131 | return node == null ? null : node.key;
132 | }
133 | //--以上设计这些方法避免大量的空指针判断
134 |
135 | /**
136 | * 获取最小的key
137 | *
138 | * @return 最小key
139 | */
140 | public final T getFirstKey() {
141 | RBTreeNode node = getFirstNode();
142 | return keyOf(node);
143 | }
144 |
145 | /**
146 | * 获取最小节点
147 | *
148 | * 最左子树节点就是最小节点
149 | *
150 | * @return 最小RBTNode
151 | */
152 | private RBTreeNode getFirstNode() {
153 | RBTreeNode node = root;
154 | if (node != null) {
155 | while (node.left != null) {
156 | node = node.left;// 左孩子不空,一直往左子树迭代
157 | }
158 | }
159 | return node;
160 | }
161 |
162 | /**
163 | * 获取最大的key
164 | *
165 | * @return 最大key
166 | */
167 | public final T getLastKey() {
168 | RBTreeNode node = getLastNode();
169 | return keyOf(node);
170 | }
171 |
172 | /**
173 | * 获取最大节点
174 | *
175 | * 最右子树节点就是最大节点
176 | *
177 | * @return 最大RBTNode
178 | */
179 | private RBTreeNode getLastNode() {
180 | RBTreeNode node = root;
181 | if (node != null) {
182 | while (node.right != null) {
183 | node = node.right;// 右孩子不空,一直往右子树迭代
184 | }
185 | }
186 | return node;
187 | }
188 |
189 | /**
190 | * 寻找当前节点的前驱节点
191 | *
192 | * @param node RBTNode
193 | * @return 当前node的前驱节点
194 | */
195 | RBTreeNode predecessor(RBTreeNode node) {
196 | if (node == null) {
197 | return null;
198 | }
199 | // 左子树不空,前驱节点为左子树的最右孩子
200 | if (node.left != null) {
201 | RBTreeNode temp = node.left;
202 | while (temp.right != null) {
203 | temp = temp.right;
204 | }
205 | return temp;
206 | } else {
207 | // 左子树为空,找到node所在子树为第一个右孩子的父节点
208 | RBTreeNode temp = node;
209 | RBTreeNode p = temp.parent;
210 | while (p != null && temp == p.left) {
211 | // temp == p.left 表示 temp < p,则p一定在temp的后继中
212 | // temp往p移动,之后的temp>node是恒成立的,因为node一直在temp的左子树中
213 | // 只有temp == p.right了,才表示 parent < temp,则parent是node的前驱
214 | // 因为此时node没有左孩子,node就是p的直接后继
215 | temp = p;
216 | p = p.parent;
217 | }
218 | return p;
219 | }
220 | }
221 |
222 | /**
223 | * 寻找当前节点的后继节点
224 | *
225 | * @param node RBTNode
226 | * @return 当前node的前驱节点
227 | */
228 | RBTreeNode successor(RBTreeNode node) {
229 | if (node == null) {
230 | return null;
231 | }
232 | // 右子树不空,后继节点为右子树的最左孩子
233 | if (node.right != null) {
234 | RBTreeNode temp = node.right;
235 | while (temp.left != null) {
236 | temp = temp.left;
237 | }
238 | return temp;
239 | } else {
240 | // 右子树为空,找到node所在子树为第一个左孩子的父节点
241 | RBTreeNode temp = node;
242 | RBTreeNode p = temp.parent;
243 | while (p != null && temp == p.right) {
244 | // temp == p.right 表示 temp > p,则p一定是在temp的前驱中
245 | // temp往p移动,之后的temp < node是恒成立的,因为node一直在temp的右子树中
246 | // 只有temp == p.left了,才表示 parent > temp,则parent是node的后继
247 | // 因为此时node没有右孩子,node就是p的直接前驱
248 | temp = p;
249 | p = p.parent;
250 | }
251 | return p;
252 | }
253 | }
254 |
255 | /**
256 | * 对当前节点进行左旋
257 | *
258 | * @param node RBTNode
259 | */
260 | private void rotateLeft(RBTreeNode node) {
261 | if (node == null) {
262 | return;
263 | }
264 | // 左旋,node和right向左转
265 | RBTreeNode right = node.right;
266 | // node和right左孩子建立父-右孩子关系
267 | node.right = right.left;
268 | if (right.left != null) {
269 | right.left.parent = node;
270 | }
271 | // node.parent和right建立父子关系
272 | right.parent = node.parent;
273 | if (node.parent == null) {
274 | root = right;
275 | } else if (node == node.parent.right) {
276 | node.parent.right = right;// right节点取代node在node.parent的孩子位置
277 | } else {
278 | node.parent.left = right;
279 | }
280 | // 交换node和right的父子关系
281 | right.left = node;
282 | node.parent = right;
283 | }
284 |
285 | /**
286 | * 对当前节点进行右旋
287 | *
288 | * @param node RBTNode
289 | */
290 | private void rotateRight(RBTreeNode node) {
291 | if (node == null) {
292 | return;
293 | }
294 | // 右旋,node和left向右转
295 | RBTreeNode left = node.left;
296 | // node和left右孩子建立父-左孩子关系
297 | node.left = left.right;
298 | if (left.right != null) {
299 | left.right.parent = node;
300 | }
301 | left.parent = node.parent;
302 | // node.parent和left建立父子关系
303 | if (node.parent == null) {// root节点的特殊处理
304 | root = left;// 父节点是空的,就是root
305 | } else if (node == node.parent.left) {
306 | node.parent.left = left;// left节点取代node在node.parent的孩子位置
307 | } else {
308 | node.parent.right = left;
309 | }
310 | // 交换node和left的父子关系
311 | left.right = node;
312 | node.parent = left;
313 | }
314 |
315 | /**
316 | * RBT查询元素(这个好像没什么意义)
317 | *
318 | * @param key 查询的key
319 | * @return T.key
320 | */
321 | public T searchRBTkey(T key) {
322 | RBTreeNode node = getRBTNode(key);
323 | return keyOf(node);
324 | }
325 |
326 | /**
327 | * 通过key获取RBTNode
328 | *
329 | * @param key 查询的key
330 | * @return RBTNode
331 | */
332 | private RBTreeNode getRBTNode(T key) {
333 | if (key == null) {
334 | return null;
335 | }
336 | // 二叉搜索树查找元素的方法
337 | RBTreeNode node = root;
338 | while (node != null) {
339 | int cmp = key.compareTo(node.key);
340 | if (cmp < 0) {
341 | node = node.left;
342 | } else if (cmp > 0) {
343 | node = node.right;
344 | } else {
345 | return node;
346 | }
347 | }
348 | return null;
349 | }
350 |
351 | /**
352 | * RBT新增节点
353 | *
354 | *
355 | * 2-3-4树中结点添加需要遵守以下规则:
356 | *
357 | * 插入都是向最下面一层插入;
358 | * 升元:将插入结点由 2-结点升级成 3-结点,或由 3-结点升级成 4-结点;
359 | * 向 4-结点插入元素后,需要将中间元素提到父结点升元,原结点变成两个 2-结点,再把元素插入 2-结点中,
360 | * 如果父结点也是 4-结点,则递归向上层升元,至到根结点后将树高加1;
361 | * 而将这些规则对应到红黑树里,就是:
362 | *
363 | * 新插入的结点颜色为 红 色,这样才可能不会对红黑树的高度产生影响。
364 | * 2-结点对应红黑树中的单个黑色结点,插入时直接成功(对应 2-结点升元)。
365 | * 3-结点对应红黑树中的 黑+红 子树,插入后将其修复成 红+黑+红 子树(对应 3-结点升元);
366 | * 4-结点对应红黑树中的 红+黑+红 子树,插入后将其修复成 红色祖父+黑色父叔+红色孩子 子树,
367 | * 然后再把 祖父结点 当成新插入的红色结点 递归向上层修复,直至修复成功或遇到 root 结点;
368 | *
369 | * @param key 新增的key
370 | */
371 | public void insertRBTNode(T key) {
372 | if (key == null) {
373 | return;// 需要compare的元素,都不能为空,简单点,不报错了
374 | }
375 | RBTreeNode node = root;
376 | if (node == null) {
377 | root = new RBTreeNode<>(key);// 根节点为空,生成根节点
378 | return;
379 | }
380 | int cmp;
381 | RBTreeNode parent;// 父节点标记插入的位置
382 | do {
383 | parent = node;// 父节点记录
384 | cmp = key.compareTo(node.key);
385 | // 比当前节点小,往左子树迭代,否则往右子树迭代
386 | if (cmp < 0) {
387 | node = node.left;
388 | } else if (cmp > 0) {
389 | node = node.right;
390 | } else {
391 | return;// 相同的,不插入了,直接返回
392 | }
393 | } while (node != null);
394 | // 新节点生成
395 | RBTreeNode newNode = new RBTreeNode<>(key);
396 | // 比父节点小,为左孩子,否则为右孩子
397 | if (cmp < 0) {
398 | parent.left = newNode;
399 | } else {
400 | parent.right = newNode;
401 | }
402 | // 节点插入后的调整
403 | // fixInsert(newNode);
404 | fixAfterInsert(newNode);
405 | }
406 |
407 | /**
408 | * RBTNode插入后的调整
409 | * 这种写法易于理解,但是会存在大量的空指针问题,操作的思想和文字说明,请看fixAfterInsert
410 | *
411 | * @param node RBTNode
412 | */
413 | private void fixInsert(RBTreeNode node) {
414 | node.color = RED;// 新插入的节点都是红色的
415 | // node不是root,且parent颜色为红,才要调整
416 | // 所有的调整都是基于node和parent为双红
417 | while (node != root && node.parent.color == RED) {
418 | // 父节点是祖父节点的左孩子
419 | if (node.parent == node.parent.parent.left) {
420 | RBTreeNode uncle = node.parent.parent.right;
421 | // case1 : 叔叔节点是红色
422 | if (uncle.color == RED) {
423 | // 父节点和叔叔节点颜色变黑
424 | node.parent.color = BLACK;
425 | uncle.color = BLACK;
426 | // 祖父节点颜色变红
427 | node.parent.parent.color = RED;
428 | // 关注节点变为祖父节点
429 | node = node.parent.parent;
430 | // 根据叔叔节点的颜色,决定是继续case1还是进入case2,case3
431 | } else {// 叔叔节点是黑色
432 | // case2 : node是父节点的右孩子
433 | if (node == node.parent.right) {
434 | // 关注节点变为父节点
435 | node = node.parent;
436 | // 对父节点进行左旋,进入case3
437 | rotateLeft(node);
438 | }
439 | // case3 : node是父节点的左孩子
440 | // 父节点和祖父节点颜色互换,父节点一定红色,祖父节点一定黑色
441 | node.parent.color = BLACK;// 把父节点变黑
442 | node.parent.parent.color = RED;// 把祖父节点变红
443 | // 围绕祖父节点右旋
444 | rotateRight(node.parent.parent);
445 | // 调整结束
446 | // 这里写不写break都一样,因为此时关注节点的父节点已经变成了黑色,不再满足调整的两红节点互连的情况
447 | break;
448 | }
449 | } else {// symmetric
450 | // 父节点是祖父节点的右孩子
451 | RBTreeNode uncle = node.parent.parent.left;
452 | // case1 : 叔叔节点是红色
453 | if (uncle.color == RED) {
454 | // 父节点和叔叔节点颜色变黑
455 | node.parent.color = BLACK;
456 | uncle.color = BLACK;
457 | // 祖父节点颜色变红
458 | node.parent.parent.color = RED;
459 | // 关注节点变为祖父节点
460 | node = node.parent.parent;
461 | // 根据叔叔节点的颜色,决定是继续case1还是进入case2,case3
462 | } else {
463 | // case2 : node是父节点的左孩子
464 | if (node == node.parent.left) {
465 | // 关注节点变为父节点
466 | node = node.parent;
467 | // 对父节点进行右旋,进入case3
468 | rotateRight(node);
469 | }
470 | // case3 : node是父节点的左孩子
471 | // 父节点和祖父节点颜色互换,父节点一定红色,祖父节点一定黑色
472 | node.parent.color = BLACK;// 把父节点变黑
473 | node.parent.parent.color = RED;// 把祖父节点变红
474 | // 围绕祖父节点左旋
475 | rotateLeft(node.parent.parent);
476 | // 调整结束
477 | // 这里写不写break都一样,因为此时关注节点的父节点已经变成了黑色,不再满足调整的两红节点互连的情况
478 | break;
479 | }
480 | }
481 | root.color = BLACK;// root永远是黑色的
482 | }
483 | }
484 |
485 | /**
486 | * RBTNode插入后的调整
487 | *
488 | * 插入节点的核心思想:新增的红节点,如果违反了红红不相邻,就要找兄弟树,往兄弟树转移。
489 | * 兄弟树如果是黑的,就把红节点转移到兄弟树。
490 | * 兄弟如果也是红的,就把红节点往上(祖父)移动,继续找兄弟树,直到兄弟树为黑树。
491 | * 如果找到根节点还没找到,就把根节点变黑,树的高度+1。
492 | *
493 | * 类比2-3-4树来说
494 | * 2-3-4树中结点添加需要遵守以下规则:
495 | *
496 | * 插入都是向最下面一层插入;
497 | * 升元:将插入结点由 2-结点升级成 3-结点,或由 3-结点升级成 4-结点;
498 | * 向 4-结点插入元素后,需要将中间元素提到父结点升元,原结点变成两个 2-结点,再把元素插入 2-结点中,
499 | * 如果父结点也是 4-结点,则递归向上层升元,至到根结点后将树高+1;
500 | *
501 | * 而将这些规则对应到红黑树里,就是:
502 | *
503 | * 新插入的结点颜色为红色,这样才可能不会对红黑树的高度产生影响。
504 | * 2-结点对应红黑树中的单个黑色结点,插入时直接成功(对应 2-结点升元)。
505 | * 3-结点对应红黑树中的黑+红子树,插入后将其修复成 红+黑+红 子树(对应 3-结点升元);
506 | * 4-结点对应红黑树中的红+黑+红子树,插入后将其修复成红色祖父+黑色父叔+红色孩子子树,
507 | * 然后再把祖父结点当成新插入的红色结点递归向上层修复,直至修复成功或遇到 root 结点;
508 | *
509 | * 安全写法
510 | *
511 | * @param node RBTNode
512 | */
513 | private void fixAfterInsert(RBTreeNode node) {
514 | node.color = RED;// 新插入的节点都是红色的
515 | // node不是root,且parent颜色为红,才要调整
516 | // 所有的调整都是基于node和parent为双红
517 | while (node != null && node != root && node.parent.color == RED) {
518 | // 父节点是祖父节点的左孩子
519 | if (parentOf(node) == leftOf(parentOf(parentOf(node)))) {
520 | // 获取叔叔节点
521 | RBTreeNode uncle = rightOf(parentOf(parentOf(node)));
522 | // case1 : 叔叔节点是红色
523 | if (colorOf(uncle) == RED) {
524 | // 父节点和叔叔节点颜色变黑
525 | setColor(parentOf(node), BLACK);
526 | setColor(uncle, BLACK);
527 | // 祖父节点颜色变红
528 | setColor(parentOf(parentOf(node)), RED);
529 | // 关注节点变为祖父节点
530 | node = parentOf(parentOf(node));
531 | // 根据叔叔节点的颜色,决定是继续case1还是进入case2,case3
532 | } else {// 叔叔节点是黑色
533 | // case2 : node是父节点的右孩子
534 | if (node == rightOf(parentOf(node))) {
535 | // 关注节点变为父节点
536 | node = parentOf(node);
537 | // 对父节点进行左旋,进入case3
538 | rotateLeft(node);
539 | }
540 | // case3 : node是父节点的左孩子
541 | // 父节点和祖父节点颜色互换,父节点一定红色,祖父节点一定黑色
542 | setColor(parentOf(node), BLACK);// 把父节点变黑
543 | setColor(parentOf(parentOf(node)), RED);// 把祖父节点变红
544 | // 围绕祖父节点右旋
545 | rotateRight(parentOf(parentOf(node)));
546 | // 调整结束
547 | // 这里写不写break都一样,因为此时关注节点的父节点已经变成了黑色,不再满足调整的两红节点互连的情况
548 | break;
549 | }
550 | } else {// symmetric
551 | // 父节点是祖父节点的右孩子
552 | // 获取叔叔节点
553 | RBTreeNode uncle = leftOf(parentOf(parentOf(node)));
554 | // case1 : 叔叔节点是红色
555 | if (colorOf(uncle) == RED) {
556 | // 父节点和叔叔节点颜色变黑
557 | setColor(parentOf(node), BLACK);
558 | setColor(uncle, BLACK);
559 | // 祖父节点颜色变红
560 | setColor(parentOf(parentOf(node)), RED);
561 | // 关注节点变为祖父节点
562 | node = parentOf(parentOf(node));
563 | // 根据叔叔节点的颜色,决定是继续case1还是进入case2,case3
564 | } else {
565 | // case2 : node是父节点的左孩子
566 | if (node == leftOf(parentOf(node))) {
567 | // 关注节点变为父节点
568 | node = parentOf(node);
569 | // 对父节点进行右旋,进入case3
570 | rotateRight(node);
571 | }
572 | // case3 : node是父节点的左孩子
573 | // 父节点和祖父节点颜色互换,父节点一定红色,祖父节点一定黑色
574 | setColor(parentOf(node), BLACK);// 把父节点变黑
575 | setColor(parentOf(parentOf(node)), RED);// 把祖父节点变红
576 | // 围绕祖父节点左旋
577 | rotateLeft(parentOf(parentOf(node)));
578 | // 调整结束
579 | // 这里写不写break都一样,因为此时关注节点的父节点已经变成了黑色,不再满足调整的两红节点互连的情况
580 | break;
581 | }
582 | }
583 | }
584 | root.color = BLACK;// root永远是黑色的
585 | }
586 |
587 | /**
588 | * 红黑树的删除
589 | *
590 | * 删除的核心思想:
591 | * 主要说一下黑节点被删除,替换节点也是黑节点的情况,首先不能破坏黑色高度,也不能造成红红相邻
592 | * 平衡方式就是从兄弟树中“借”红色节点(一般就是兄弟节点和兄弟的直接孩子节点)过来,填充为黑色节点。
593 | * 如果兄弟树没有红色节点,就把黑色节点上移(父亲节点),继续找兄弟节点的红色节点。
594 | * 如果一直找到了根节点还是找不到可以借的红色节点,就抛弃这个黑色节点,整棵树高度-1。
595 | *
596 | *
597 | * 红黑树的删除要比插入要复杂一些,我们还是类比 2-3-4树来讲:
598 | *
599 | * 查找最近的叶子结点中的元素替代被删除元素,删除替代元素后,从替代元素所处叶子结点开始处理;
600 | * 降元:4-结点变 3-结点,3-结点变 2-结点;
601 | * 2-结点中只有一个元素,所以借兄弟结点中的元素来补充删除后的造成的空结点;
602 | * 当兄弟结点中也没有多个元素可以补充时,尝试将父结点降元,失败时向上递归,至到子树降元成功或到 root 结点树高减1;
603 | * 将这些规则对应到红黑树中即:
604 | *
605 | * 查找离当前结点最近的叶子结点作为 替代结点
606 | * (左子树的最右结点或右子树的最左结点都能保证替换后保证二叉查找树的结点的排序性质,叶子结点的替代结点是自身)
607 | *
608 | * 替换掉被删除结点,从替代的叶子结点向上递归修复;
609 | * 替代结点颜色为红色(对应 2-3-4树中 4-结点或 3-结点)时删除子结点直接成功;
610 | *
611 | * 替代结点为黑色(对应 2-3-4树中 2-结点)时,意味着替代结点所在的子树会降一层,需要依次检验以下三项,以恢复子树高度:
612 | *
613 | * 兄弟结点的子结点中有红色结点(兄弟结点对应 3-结点或 4-结点)能够“借用”,旋转过来后修正颜色;
614 | * 父结点是红色结点(父结点对应 3-结点或 4-结点,可以降元)时,将父结点变黑色,自身和兄弟结点变红色后删除;
615 | * 父结点和兄弟结点都是黑色时,将子树降一层后把父结点当作替代结点递归向上处理。
616 | *
617 | * @param key 删除的key
618 | */
619 | public void deleteRBTNode(T key) {
620 | RBTreeNode node = getRBTNode(key);
621 | if (node == null) {
622 | return;// key都不存在,就不管了
623 | }
624 | // 如果node有两个孩子节点,用他的后继节点来代替他,当然用前驱也可以,是一样的
625 | // 为什么先判断两个孩子节点呢,因为两个孩子节点会转化为只有一个孩子节点情况,将问题归纳为一种情况
626 | if (node.left != null && node.right != null) {
627 | // 找到后继节点
628 | RBTreeNode successorNode = successor(node);
629 | // 后继节点内容替换当前节点内容
630 | node.key = successorNode.key;
631 | // 删除节点指针指向node的后继节点
632 | node = successorNode;
633 | }
634 | // 此时node只有0个或者1个孩子节点,左孩子或者右孩子来取代node的位置
635 | RBTreeNode replaceNode = (node.left != null ? node.left : node.right);
636 |
637 | if (replaceNode != null) {
638 | // 存在孩子节点的情况
639 | RBTreeNode parent = node.parent;
640 | replaceNode.parent = parent;
641 | if (parent == null) {// 删除的是根节点
642 | root = replaceNode;
643 | } else if (node == parent.left) {
644 | parent.left = replaceNode;
645 | } else {
646 | parent.right = replaceNode;
647 | }
648 | // Null out links so they are OK to use by fixAfterDeletion.
649 | node.parent = node.left = node.right = null;
650 |
651 | // 黑色节点需要调整
652 | if (node.color == BLACK) {
653 | // 调整代替的节点
654 | fixAfterDeletion(replaceNode);
655 | }
656 | } else {
657 | // 没有孩子节点的情况
658 | RBTreeNode parent = node.parent;
659 | if (parent == null) {// 删除的是根节点
660 | root = null;// 根节点没了,也不用管后面了
661 | return;
662 | }
663 | // 删除的如果是黑节点,还得做调整
664 | if (node.color == BLACK) {
665 | fixAfterDeletion(node);
666 | }
667 | // 这时候父节点要重新获取,因为经过一系列调整和旋转后,node.parent很可能发生了变化
668 | parent = node.parent;
669 | // node父指针移除
670 | node.parent = null;
671 | if (parent != null) {
672 | if (node == parent.left) {
673 | parent.left = null;
674 | } else {
675 | parent.right = null;
676 | }
677 | }
678 | }
679 | }
680 |
681 | /**
682 | * RBTNode删除后的调整
683 | *
684 | * 替代结点为黑色(对应 2-3-4树中 2-结点)时,意味着替代结点所在的子树会降一层,需要依次检验以下三项,以恢复子树高度:
685 | *
686 | * 兄弟结点的子结点中有红色结点(兄弟结点对应 3-结点或 4-结点)能够“借用”,旋转过来后修正颜色,这时候兄弟节点一定是黑色的;
687 | * 父结点是红色结点(父结点对应 3-结点或 4-结点,可以降元)时,将父结点变黑色,自身和兄弟结点变红色后删除;
688 | * 父结点和兄弟结点都是黑色时,将子树降一层后把父结点当作替代结点递归向上处理。对应case2的情况
689 | * 安全写法
690 | *
691 | * @param node RBTNode
692 | */
693 | private void fixAfterDeletion(RBTreeNode node) {
694 | // 如果node.color是红色,那么只需要把node的颜色设置成黑色就可以了
695 | // 所以,这个方法最后一步就是把node.color设置为黑色
696 | while (node != root && colorOf(node) == BLACK) {
697 | if (node == leftOf(parentOf(node))) {
698 | // 获取兄弟节点
699 | RBTreeNode brother = rightOf(parentOf(node));
700 | // case1 :兄弟是红色节点
701 | if (colorOf(brother) == RED) {
702 | // 这个时候直接把兄弟节点借过来了,但是又要保持兄弟树的黑色高度稳定
703 | // 就交换父节点和兄弟节点的颜色(兄弟是红,父节点肯定是黑色了),把父节点借过来了
704 | setColor(brother, BLACK);// 兄弟节点变黑
705 | setColor(parentOf(node), RED);// 父节点变红
706 | rotateLeft(parentOf(node));// 父节点左旋
707 | brother = rightOf(parentOf(node));// 重新获取兄弟节点
708 | // 这个时候兄弟节点肯定是黑色了,因为之前的兄弟节点是红色的,那么他的子节点肯定是黑色的
709 | // 这时候不是简单把转过来的父节点变红就可以了,
710 | // 因为node是x-1(x表示原高度),而兄弟节点(红色)转过来的孩子树的高度还是x(画图理解)
711 | // 所以本身高度就不统一,所以要进入接下来的case2;(case3或case4)
712 | }
713 | // case2 : 兄弟节点是黑色,并且两个孩子也是黑色
714 | // 如果兄弟节点是黑色,那么node节点高度是x-1,兄弟节点孩子节点的高度也是x-1了(因为要去掉黑色兄弟节点)
715 | if (colorOf(leftOf(brother)) == BLACK && colorOf(rightOf(brother)) == BLACK) {
716 | // 兄弟子树高度-1,往根节点递归处理,和插入不同的是,这里是到父节点,不是祖父
717 | setColor(brother, RED);// 兄弟节点变成红色,兄弟子树高度-1
718 | node = parentOf(node);// 关注节点变成父节点
719 | // 这时候如果node节点(原父节点)是红色了,就跳出循环了,
720 | // 再把node节点(原父节点)变黑,兄弟子树高度+1,原来自己子树高度也+1
721 | // 新node(原父节点)是黑色,需要继续循环
722 | } else {
723 | // case3 : 兄弟节点是黑色;兄弟节点的左孩子是红色,右孩子是黑色的
724 | if (colorOf(rightOf(brother)) == BLACK) {
725 | setColor(leftOf(brother), BLACK);// 兄弟左孩子变黑
726 | setColor(brother, RED);// 兄弟变红
727 | rotateRight(brother);// 兄弟节点右旋
728 | brother = rightOf(parentOf(node));// 重新获取兄弟节点
729 | // 要把红节点转过去,就要先右旋,在左旋,为了保证旋转后还是红黑树,就要交换一下兄弟左孩子和兄弟节点的颜色了
730 | }
731 | // case4 : 兄弟节点是黑色;兄弟节点的右孩子是红色的,x的兄弟节点的左孩子任意颜色
732 | setColor(brother, colorOf(parentOf(node)));// 父节点的颜色,赋值给兄弟节点
733 | setColor(parentOf(node), BLACK);// 父节点设置为黑色,准备通过旋转把这个黑色节点借过来
734 | // 为什么染黑兄弟的右孩子,个人认为,真正左旋过去的,是兄弟节点的黑色,兄弟节点本身的高度-1。
735 | // 为了维持这个高度平衡,就把兄弟右孩子变成黑色,
736 | // 因为左旋后,右孩子的位置,就是原来兄弟节点位置,黑色高度恢复(+1-1抵消)
737 | setColor(rightOf(brother), BLACK);// 兄弟孩子的右节点设置为黑色,
738 | rotateLeft(parentOf(node));// 父节点左旋,这个时候就把节点借过来了,而且染黑了
739 | // 这一步后,删除调整已经结束,根节点依旧要保持黑色的属性,把node执行root,与之前的情况合并处理
740 | node = root;
741 | }
742 | } else { // symmetric,对称方同理,这里就不写了
743 | // 获取兄弟节点
744 | RBTreeNode brother = leftOf(parentOf(node));
745 | // case1 :兄弟是红色节点
746 | if (colorOf(brother) == RED) {
747 | setColor(brother, BLACK);// 兄弟节点变黑
748 | setColor(parentOf(node), RED);// 父节点变红
749 | rotateRight(parentOf(node));// 父节点右旋
750 | // 这个时候兄弟节点肯定是黑色了,因为之前的兄弟节点是红色的,那么他的子节点肯定是黑色的
751 | brother = leftOf(parentOf(node));// 重新获取兄弟节点
752 | }
753 | // case2 : 兄弟节点是黑色,并且两个孩子也是黑色
754 | if (colorOf(leftOf(brother)) == BLACK && colorOf(rightOf(brother)) == BLACK) {
755 | setColor(brother, RED);// 兄弟节点变成红色
756 | node = parentOf(node);// 关注节点变成父节点
757 | } else {
758 | // case3 : 兄弟节点是黑色;兄弟节点的右孩子是红色,做孩子是黑色的
759 | if (colorOf(leftOf(brother)) == BLACK) {
760 | setColor(rightOf(brother), BLACK);// 兄弟右孩子变黑
761 | setColor(brother, RED);// 兄弟变红
762 | rotateLeft(brother);// 兄弟节点左旋
763 | brother = leftOf(parentOf(node));// 重新获取兄弟节点
764 | }
765 | // case4 : 兄弟节点是黑色;兄弟节点的左孩子是红色的,x的兄弟节点的右孩子任意颜色
766 | setColor(brother, colorOf(parentOf(node)));// 父节点的颜色,赋值给兄弟节点
767 | setColor(parentOf(node), BLACK);// 父节点设置为黑色
768 | setColor(leftOf(brother), BLACK);// 兄弟孩子的右节点设置为黑色
769 | rotateRight(parentOf(node));
770 | node = root;
771 | }
772 | }
773 | }
774 | // 节点设置为黑色,兼容node两种颜色的情况
775 | setColor(node, BLACK);// 节点变黑
776 | }
777 | }
778 |
--------------------------------------------------------------------------------
/datastructrue/src/segmenttree/SegTree.java:
--------------------------------------------------------------------------------
1 | package segmenttree;
2 |
3 | /**
4 | * 线段树板子
5 | */
6 | public class SegTree {
7 |
8 | private TreeNode root;
9 |
10 | private int mod = (int) (1e9 + 7);
11 |
12 | private static class TreeNode {
13 | long val;
14 |
15 | long left;
16 | long right;
17 |
18 | TreeNode leftNode;
19 | TreeNode rightNode;
20 |
21 | long lazyAdd;
22 |
23 | long lazyMul;
24 | TreeNode(long left, long right) {
25 | this(left, right, 0L);
26 | }
27 |
28 | TreeNode(long left, long right, long val) {
29 | this.val = val;
30 | this.left = left;
31 | this.right = right;
32 | this.lazyAdd = 0L;
33 | this.lazyMul = 1L;
34 | }
35 |
36 | private long getMid() {
37 | return left + (right - left >> 1);
38 | }
39 |
40 | private TreeNode getLeftNode() {
41 | if (leftNode == null) {
42 | leftNode = new TreeNode(left, getMid(),val);
43 | }
44 | return leftNode;
45 | }
46 |
47 | private TreeNode getRightNode() {
48 | if (rightNode == null) {
49 | rightNode = new TreeNode(getMid() + 1, right,val);
50 | }
51 | return rightNode;
52 | }
53 | }
54 |
55 | public SegTree() {
56 | root = new TreeNode(Long.MIN_VALUE, Long.MAX_VALUE);
57 | }
58 |
59 | public SegTree(long left, long right) {
60 | root = new TreeNode(left, right);
61 | }
62 |
63 | public SegTree(long left, long right, long val) {
64 | root = new TreeNode(left, right, val);
65 | }
66 |
67 | public long query(long left,long right) {
68 | return query(root,left,right);
69 | }
70 |
71 | private long query(TreeNode node,long left,long right) {
72 | if(right < node.left || left > node.right) {
73 | return 0L;
74 | }
75 | if(left <= node.left && node.right <= right) {
76 | return node.val;
77 | }
78 | // 更新子树
79 | pushDown(node);
80 | return (query(node.getLeftNode(),left,right) + query(node.getRightNode(),left,right)) % mod;
81 | }
82 |
83 | public void add(long left,long right,long val) {
84 | add(root,left,right,val);
85 | }
86 |
87 | private void add(TreeNode node,long left,long right,long val) {
88 | if(left > node.right || node.left > right) {
89 | return;
90 | }
91 | if(left <= node.left && node.right <= right) {
92 | node.val += (node.right - node.left + 1) * val;
93 | node.val %= mod;
94 | node.lazyAdd += val;
95 | node.lazyAdd %= mod;
96 | return;
97 | }
98 |
99 | // 更新子树
100 | pushDown(node);
101 |
102 | long mid = node.getMid();
103 | if(right <= mid) {
104 | add(node.getLeftNode(),left,right,val);
105 | } else if(left > mid) {
106 | add(node.getRightNode(),left,right,val);
107 | } else {
108 | add(node.getLeftNode(),left,mid,val);
109 | add(node.getRightNode(),mid + 1,right,val);
110 | }
111 | pushUp(node);
112 | }
113 |
114 | public void mul(long left,long right,long val) {
115 | mul(root,left,right,val);
116 | }
117 |
118 | private void mul(TreeNode node,long left,long right,long val) {
119 | if(left > node.right || node.left > right) {
120 | return;
121 | }
122 | if(left <= node.left && node.right <= right) {
123 | node.val *= val;
124 | node.val %= mod;
125 | node.lazyMul *= val;
126 | node.lazyMul %= mod;
127 | node.lazyAdd *= val;
128 | node.lazyAdd %= mod;
129 | return;
130 | }
131 |
132 | // 更新子树
133 | pushDown(node);
134 | long mid = node.getMid();
135 | if(right <= mid) {
136 | mul(node.getLeftNode(),left,right,val);
137 | } else if(left > mid) {
138 | mul(node.getRightNode(),left,right,val);
139 | } else {
140 | mul(node.getLeftNode(),left,mid,val);
141 | mul(node.getRightNode(),mid + 1,right,val);
142 | }
143 | pushUp(node);
144 | }
145 |
146 | private void pushUp(TreeNode node) {
147 | node.val = (node.getLeftNode().val + node.getRightNode().val) % mod;
148 | }
149 |
150 |
151 | private void pushDown(TreeNode node) {
152 | if(node.lazyMul != 1L) {
153 | if(node.leftNode != null) {
154 | node.leftNode.val = (node.leftNode.val * node.lazyMul) % mod;
155 | node.leftNode.lazyMul = (node.leftNode.lazyMul * node.lazyMul) % mod;
156 | node.leftNode.lazyAdd = (node.leftNode.lazyAdd * node.lazyMul) % mod;
157 |
158 | }
159 | if(node.rightNode != null) {
160 | node.rightNode.val = (node.rightNode.val * node.lazyMul) % mod;
161 | node.rightNode.lazyMul = (node.rightNode.lazyMul * node.lazyMul) % mod;
162 | node.rightNode.lazyAdd = (node.rightNode.lazyAdd * node.lazyMul) % mod;
163 | }
164 | node.lazyMul = 1L;
165 | }
166 | if(node.lazyAdd != 0L) {
167 | if(node.leftNode != null) {
168 | node.leftNode.val += (node.leftNode.right - node.leftNode.left + 1) * node.lazyAdd;
169 | node.leftNode.val %= mod;
170 | node.leftNode.lazyAdd += node.lazyAdd;
171 | node.leftNode.lazyAdd %= mod;
172 | }
173 | if(node.rightNode != null) {
174 | node.rightNode.val += (node.rightNode.right - node.rightNode.left + 1) * node.lazyAdd;
175 | node.rightNode.val %= mod;
176 | node.rightNode.lazyAdd += node.lazyAdd;
177 | node.rightNode.lazyAdd %= mod;
178 | }
179 | node.lazyAdd = 0L;
180 | }
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/datastructrue/src/snowflake/SnowFlake.java:
--------------------------------------------------------------------------------
1 | package snowflake;
2 |
3 | /**
4 | * 雪花算法
5 | */
6 | public class SnowFlake {
7 | /**
8 | * 起始的时间戳
9 | */
10 | private final static long START_STMP = 1480166465631L;
11 |
12 | /**
13 | * 每一部分占用的位数
14 | */
15 | private final static long SEQUENCE_BIT = 12; //序列号占用的位数
16 | private final static long MACHINE_BIT = 5; //机器标识占用的位数
17 | private final static long DATACENTER_BIT = 5;//数据中心占用的位数
18 |
19 | /**
20 | * 每一部分的最大值
21 | */
22 | private final static long MAX_DATACENTER_NUM = ~(-1L << DATACENTER_BIT);
23 | private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
24 | private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
25 |
26 | /**
27 | * 每一部分向左的位移
28 | */
29 | private final static long MACHINE_LEFT = SEQUENCE_BIT;
30 | private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
31 | private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
32 |
33 | private long datacenterId; //数据中心
34 | private long machineId; //机器标识
35 | private long sequence = 0L; //序列号
36 | private long lastStmp = -1L;//上一次时间戳
37 |
38 | public SnowFlake(long datacenterId, long machineId) {
39 | if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
40 | throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
41 | }
42 | if (machineId > MAX_MACHINE_NUM || machineId < 0) {
43 | throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
44 | }
45 | this.datacenterId = datacenterId;
46 | this.machineId = machineId;
47 | }
48 |
49 | /**
50 | * 产生下一个ID
51 | *
52 | * @return
53 | */
54 | public synchronized long nextId() {
55 | long currStmp = getNewstmp();
56 | if (currStmp < lastStmp) {
57 | throw new RuntimeException("Clock moved backwards. Refusing to generate id");
58 | }
59 |
60 | if (currStmp == lastStmp) {
61 | //相同毫秒内,序列号自增
62 | sequence = (sequence + 1) & MAX_SEQUENCE;
63 | //同一毫秒的序列数已经达到最大
64 | if (sequence == 0L) {
65 | currStmp = getNextMill();
66 | }
67 | } else {
68 | //不同毫秒内,序列号置为0
69 | sequence = 0L;
70 | }
71 |
72 | lastStmp = currStmp;
73 |
74 | return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
75 | | datacenterId << DATACENTER_LEFT //数据中心部分
76 | | machineId << MACHINE_LEFT //机器标识部分
77 | | sequence; //序列号部分
78 | }
79 |
80 | private long getNextMill() {
81 | long mill = getNewstmp();
82 | while (mill <= lastStmp) {
83 | mill = getNewstmp();
84 | }
85 | return mill;
86 | }
87 |
88 | private long getNewstmp() {
89 | return System.currentTimeMillis();
90 | }
91 |
92 | public static void main(String[] args) {
93 | SnowFlake snowFlake = new SnowFlake(2, 3);
94 |
95 | long start = System.currentTimeMillis();
96 | for (int i = 0; i < 1000000; i++) {
97 | System.out.println(snowFlake.nextId());
98 | }
99 |
100 | System.out.println(System.currentTimeMillis() - start);
101 |
102 |
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/datastructrue/src/unionfind/UnionFind.java:
--------------------------------------------------------------------------------
1 | package unionfind;
2 |
3 | /**
4 | * 并查集模板,包含路径压缩和按秩合并
5 | */
6 | public class UnionFind {
7 | int[] parent;
8 | int[] rank;
9 |
10 | public UnionFind(int n) {
11 | parent = new int[n];
12 | for (int i = 0; i < n; i++) {
13 | parent[i] = i;
14 | }
15 | rank = new int[n];
16 | }
17 |
18 | public void union(int x, int y) {
19 | int rootx = find(x);
20 | int rooty = find(y);
21 | if (rootx != rooty) {
22 | if (rank[rootx] > rank[rooty]) {
23 | parent[rooty] = rootx;
24 | } else if (rank[rootx] < rank[rooty]) {
25 | parent[rootx] = rooty;
26 | } else {
27 | parent[rooty] = rootx;
28 | rank[rootx]++;
29 | }
30 | }
31 | }
32 |
33 | public int find(int x) {
34 | if (parent[x] != x) {
35 | parent[x] = find(parent[x]);
36 | }
37 | return parent[x];
38 | }
39 | }
40 |
--------------------------------------------------------------------------------