-
Notifications
You must be signed in to change notification settings - Fork 312
/
23-《进阶》有序表介绍及其原理.md
1445 lines (1106 loc) · 39.8 KB
/
23-《进阶》有序表介绍及其原理.md
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
[TOC]
# 1 有序表原理及扩展
## 1.1 搜索二叉树
经典的搜索二叉树,是没有重复值的,任何节点为头的数,左孩子都比自己小,右孩子都比自己大
允许重复值的改进的搜索二叉树,可以在每个节点上增加一个统计词频的数据项。表示出现了几次;但是不可相等的放到左右孩子上,搜索二叉树变平衡时,会影响后续的旋转
1、搜索二叉树一定要说明以什么标准来排序
2、经典的搜索二叉树,树上没有重复的用来排序的key值
3、如果有重复节点的需求,可以在一个节点内部增加数据项
## 1.2 搜索二叉树的增删改查
### 1.2.1 搜索二叉树的查找和添加
- 查找
搜索二叉树查询key(查询某个key存在还是不存在),当前节点比自己小,到右子树上去找,当前节点比自己大,到其左孩子上去找,越界,说明不存在
1、如果当前节点的value==key,返回true
2、如果当前节点的value<key,当前节点向左移动
3、如果当前节点的value>key,当前节点向右移动
4、如果当前节点变成null,返回false
- 添加
和查询过程一样,但当前节点滑到空的时候,就插入在这里
- 删除
1、先找到key所在的节点
2、如果该节点没有左孩子、没有右孩子,直接删除即可(好理解)
3、如果该节点有左孩子、没有右孩子,直接用左孩子顶替该节点(好理解)
4、如果该节点没有左孩子、有右孩子,直接用右孩子顶替该节点(好理解)
5、如果该节点有左孩子、有右孩子,用该节点后继节点顶替该节点(需要旋转调整,没法用左右孩子去替换,原因是左右孩子也有左右孩子)
> 一个节点的后继节点,就是该节点右孩子的最左的那个节点。
```
graph TD
2-->1
2-->5
5-->3
5-->10
10-->8
10-->13
8-->6
6-->7
```
比如我要删除5节点,那么5节点的后继节点就是其右子树的最左的孩子,也就是6。把6替换掉5,6的右孩子给它父亲作为左孩子,得到
```
graph TD
2-->1
2-->6
6-->3
6-->10
10-->8
10-->13
8-->7
```
```Go
package main
import "fmt"
type Node struct {
Value int
Left *Node // 左孩子指针
Right *Node // 右孩子指针
Parent *Node // 指向父亲的指针
}
// BinarySearchTree 二叉搜索树
type BinarySearchTree struct {
Root *Node
Size int
}
// createNode 构建一个树节点
func createNode(value int, parent *Node, left *Node, right *Node) *Node {
return &Node{
Value: value,
Left: left,
Right: right,
Parent: parent,
}
}
// Search 在二叉搜索树中寻找element是否存在,如果不存在返回nil
func (tree *BinarySearchTree) Search(element int) *Node {
node := tree.Root
for node != nil && node.Value != element {
if element < node.Value { // 小于当前节点,找左孩子对比
node = node.Left
} else { // 大于当前节点,找右孩子对比
node = node.Right
}
}
return node
}
// Insert 向二叉搜索树中插入一个节点
func (tree *BinarySearchTree) Insert(element int) *Node {
// 首先如果这个树是空的,把该节点当成头节点
if tree.Root == nil {
tree.Root = createNode(element, nil, nil, nil)
tree.Size++
return tree.Root
}
// 需要插入在该节点下面。经过上面的base case,这里tree.root一定不为nil
searchTempNode := tree.Root
insertParentNode := searchTempNode
for searchTempNode != nil {
insertParentNode = searchTempNode
if element < searchTempNode.Value {
searchTempNode = searchTempNode.Left
} else {
searchTempNode = searchTempNode.Right
}
}
newNode := createNode(element, insertParentNode, nil, nil)
if insertParentNode.Value > newNode.Value {
insertParentNode.Left = newNode
} else {
insertParentNode.Right = newNode
}
tree.Size++
return newNode
}
// delete 删除二叉搜索树中某个值的对应的节点。删除节点,每个节点由于加入向上的指针,那么旋转的时候会方便些
func (tree *BinarySearchTree) delete(element int) *Node {
deleteNode := tree.Search(element)
if deleteNode != nil {
return tree.deleteByNode(deleteNode)
} else {
return nil
}
}
// deleteNode 删除二叉搜索树中指定的某个节点。注意,删除方法返回的是删除后接管删除节点的位置的节点,返回
func (tree *BinarySearchTree) deleteByNode(deleteNode *Node) *Node {
var nodeToReturn *Node
if deleteNode != nil {
if deleteNode.Left == nil {
// 左孩子为空,右孩子直接替换该节点,达到删除的效果
// transplant(a,b) b去替换a的环境,a断连掉,把b返回
nodeToReturn = tree.transplant(deleteNode, deleteNode.Right)
} else if deleteNode.Right == nil {
// 右孩子为空,左孩子直接替换,达到删除的目的
nodeToReturn = tree.transplant(deleteNode, deleteNode.Left)
} else {
// 否则,要删除的节点既有左孩子,又有右孩子,找右子树的最左的孩子
successorNode := tree.getMinimumNode(deleteNode.Right)
// 要删除的节点的右孩子,有左孩子。最左孩子的右孩子要它父亲来接管
if successorNode.Parent != deleteNode {
tree.transplant(successorNode, successorNode.Right)
successorNode.Right = deleteNode.Right
successorNode.Right.Parent = successorNode
}
// 如果要删除的节点的右孩子,没有左孩子。直接用要删除的节点的右孩子进行替换即可
tree.transplant(deleteNode, successorNode)
successorNode.Left = deleteNode.Left
successorNode.Left.Parent = successorNode
nodeToReturn = successorNode
}
tree.Size--
}
return nodeToReturn
}
// transplant 将树上的一个节点(newNode)放到另一个节点(nodeToReplace)的位置。
func (tree *BinarySearchTree) transplant(nodeToReplace *Node, newNode *Node) *Node {
if nodeToReplace.Parent == nil {
tree.Root = newNode
} else if nodeToReplace == nodeToReplace.Parent.Left { // nodeToReplace是其父亲的左孩子
nodeToReplace.Parent.Left = newNode
} else {
nodeToReplace.Parent.Right = newNode
}
if newNode != nil {
newNode.Parent = nodeToReplace.Parent
}
return newNode
}
// getMinimumValue 查找二叉搜索树中最小的值
func (tree *BinarySearchTree) getMinimumValue() int {
return tree.getMinimumNode(tree.Root).Value
}
// getMinimumNode 查找二叉搜索树中最小值所在的节点
func (tree *BinarySearchTree) getMinimumNode(node *Node) *Node {
for node.Left != nil {
node = node.Left
}
return node
}
func (tree *BinarySearchTree) getMaximumValue() int {
return tree.getMaximumNode(tree.Root).Value
}
func (tree *BinarySearchTree) getMaximumNode(node *Node) *Node {
for node.Right != nil {
node = node.Right
}
return node
}
// contains 判断二叉搜索树中存不存在element
func (tree *BinarySearchTree) contains(element int) bool {
return tree.Search(element) != nil
}
// getSuccessor 获取下一个比提供的元素大的元素值。
func (tree *BinarySearchTree) getSuccessorValue(element int) int {
return tree.getSuccessorNode(tree.Search(element)).Value
}
// getSuccessorNode 获取下一个比提供的元素大的元素节点。
func (tree *BinarySearchTree) getSuccessorNode(node *Node) *Node {
// if there is right branch, then successor is leftmost node of that
// subtree
if node.Right != nil {
return tree.getMinimumNode(node.Right)
} else { // otherwise it is a lowest ancestor whose left child is also
// ancestor of node
curNode := node
parentNode := node.Parent
for parentNode != nil && curNode == parentNode.Right {
// go up until we find parent that currentNode is not in right
// subtree.
curNode = parentNode
parentNode = parentNode.Parent
}
return parentNode
}
}
// printTreeInOrder 中序遍历
func (tree *BinarySearchTree) printTreeInOrder() {
printInOrder(tree.Root)
}
// printTreePreOrder 先序遍历
func (tree *BinarySearchTree) printTreePreOrder() {
printPreOrder(tree.Root)
}
// printTreePostOrder 后序遍历
func (tree *BinarySearchTree) printTreePostOrder() {
printPostOrder(tree.Root)
}
func printInOrder(head *Node) {
if head != nil {
printInOrder(head.Left)
fmt.Println(head.Value)
printInOrder(head.Right)
}
}
func printPreOrder(head *Node) {
if head != nil {
fmt.Println(head.Value)
printInOrder(head.Left)
printInOrder(head.Right)
}
}
func printPostOrder(head *Node) {
if head != nil {
printInOrder(head.Left)
printInOrder(head.Right)
fmt.Println(head.Value)
}
}
```
## 1.3 传统搜索二叉树存在的问题
1)基础的搜索二叉树,添加、删除时候不照顾平衡性
2)数据状况很差时,性能就很差
> 给搜索二叉树引入两个动作:左旋、右旋
输入状况,决定性能。比如输入状况构建出来的树,严重不平衡。极端情况是只有一条通往底部的路径,高度为n;
平衡二叉树的定义,任何子树,左子树的高度和右子树的高度差,不大于1。所以对于n个节点,平衡二叉树的高度,就是logN
### 1.3.1 平衡搜索二叉树
平衡搜索二叉树,就是在插入和删除的过程中,动态的保持平衡性。保持平衡的代价保持在logN。平衡搜索二叉树的实现有很多,红黑树只是其中一种
### 1.3.2 左旋和右旋
左旋和右旋针对头结点而言的,即对哪个头结点进行左旋还是右旋;顾名思义如果对头结点为a的子树右旋,那么a倒到右边,a的左孩子顶上来,到a原来的位置上去。a原来左孩子的右孩子,现在当做a的左孩子,如下图
```
graph TD
a-->b
a-->c
c-->d
c-->e
b-->f
b-->g
```
a右旋,得到:
```
graph TD
b-->f
b-->a
a-->g
a-->c
c-->d
c-->e
```
同理,a左旋,得到:
```
graph TD
c-->a
c-->e
a-->b
a-->d
b-->f
b-->g
```
带左旋和右旋的搜索二叉树,在经典搜索二叉树上做的扩展,继承经典搜索二叉树。
```Go
package main
// BalancingBinarySearchTree 平衡二叉搜索树,继承二叉搜索树
type BalancingBinarySearchTree struct {
*BinarySearchTree
}
// rotateLeft 平衡二叉搜索树的左旋操作
func (tree *BalancingBinarySearchTree) rotateLeft(node *Node) *Node {
temp := node.Right
temp.Parent = node.Parent
node.Right = temp.Left
if node.Right != nil {
node.Right.Parent = node
}
temp.Left = node
node.Parent = temp
if temp.Parent != nil {
if node == temp.Parent.Left {
temp.Parent.Left = temp
} else {
temp.Parent.Right = temp
}
} else {
tree.Root = temp
}
return temp
}
// rotateRight 平衡二叉树的右旋操作
func (tree *BalancingBinarySearchTree) rotateRight(node *Node) *Node {
temp := node.Left
temp.Parent = node.Parent
node.Left = temp.Right
if node.Left != nil {
node.Left.Parent = node
}
temp.Right = node
node.Parent = temp
// temp took over node's place so now its parent should point to temp
if temp.Parent != nil {
if node == temp.Parent.Left {
temp.Parent.Left = temp
} else {
temp.Parent.Right = temp
}
} else {
tree.Root = temp
}
return temp
}
```
## 1.4 有序表
在Java中,就是TreeMap,有序表和Hash表(HashMap)的操作类似,但是有序表中自动把我们的key排好了顺序,我们也可以传入比较器,自定义对比和排序的规则;我们可以通过TreeMap直接得到最大节点和最小节点,也可以获取大于某个值的第一个Key是什么等等
为什么TreeMap可以做到有序,原因是TreeMap的底层是一个平衡搜索二叉树
- Hash表和有序表对比
1、HashMap的所有操作是O(1)的,TreeMap的所有操作是O(logN)
2、使用有序表的Key必须是可以比较的,没法自然比较的需要传入自定义比较器
## 1.5 有序表的实现(AVL树,SB树,红黑树)
在有序表中,有序表是一种规范,类似于接口名。规范为key要按序组织,所有操作要是O(logN)等。各种树结构可以实现有序表的功能。其中红黑树只是有序表的一个实现
**AVL树,SB树,红黑树,都是有序表的一种实现。都是平衡搜索二叉树,这三种树在功能和时间复杂度上几乎无差别,在实现细节上也就是在常数时间上,会有差别。三种树调整检查哪些节点的平衡性相同,下文进行说明。每种树针对每个节点的平衡性调整不同,但是都是使用左旋和右旋两个动作**
- AVL树,SB树,红黑树的共性
1)都是搜索二叉树
2)插入、删除、查询(一切查询)搜索二叉树怎么做,这些结构都这么做
3)使用调整的基本动作都只有左旋、右旋
4)插入、删除时,从最底层被影响到的节点开始,对往上路径的节点做平衡性检查
5)因为只对一条向上路径的每个节点做O(1)的检查和调整,所以可以做到O(logN)
- AVL树,SB树,红黑树不同之处
1)平衡性的约束不同
AVL树最严格、SB树稍宽松、红黑树最宽松
2)插入、删除和搜索二叉树一样,但是额外,做各自的平衡性调整。各自的平衡性调整所使用的动作都是左旋或者右旋
### 1.5.1 AVL树
是这三个平衡搜索二叉树中,平衡性最严格的,左树高度和右树高度的绝对值,严格小于2
AVL树在插入节点的时候,只会向上检查节点的平衡性有没有被破坏。删除节点也一样,只会检查删除的那个节点向上的那条链上的节点有没被破坏。删除的时候,如果被删除的节点没有左右孩子那么直接检查,如果有右孩子,是去检查后继节点原来所在的位置的向上节点的平衡性
**实质上三种树删除和插入节点,检查哪些节点需要调整平衡都是这样的查找规则,对于删除来说,只有左树和只有右树没影响,如果左右树都存在,是去检查后继节点原来所在的位置向上的平衡性。只是具体到某个节点平衡性的处理上,三种树不一样**
#### 1.5.1.1 AVL树针对某个节点的平衡性处理
1、该节点左树高度和右树高度差的绝对值|L-R|,小于2。不违规,无须调整
2、|L-R|大于1,说明要不然左树高度大了,要不然右树高度大了。而且之前的每一步都进行了调整,所以高度差不会超过2。高度不平衡对应四种情况,被称为RR形违规,RL形违规,LL形违规,LR形违规。首字母表示左树变高了还是右树变高了,比如RR和RL都表示经过插入或者删除,右树的高度变大了
RR表示,右子节点的右树过长,RL表示右子节点的左树过长。同理LL表示左子节点的左子树高度过长导致,LR表示左子节点的右树高度过长导致的不平衡
- LL形违规,对该节点进行一次右旋即可
```
graph TD
x-->y
x-->p
y-->z
y-->t
z-->k
```
右旋后得到:
```
graph TD
y-->z
y-->x
z-->k
x-->t
x-->p
```
- 同理RR形违规,对该节点进行一次左旋即可
- LR形,让底部的孙子节点,来到顶部来。
下面例子,想办法让x的孙子节点t节点来到顶部,先对y节点进行一次左旋,再对x节点做一次右旋
```
graph TD
x-->y
x-->p
y-->z
y-->t
t-->k
```
先对y节点进行一次左旋
```
graph TD
x-->t
x-->p
y-->z
t-->y
t-->k
```
再对x节点做一次右旋
```
graph TD
t-->y
t-->x
x-->k
x-->p
y-->z
```
原x的孙子节点t此时,调整到的顶部
- 同理RL形,也是让超过长度的那一侧底部的孙子节点,来到顶部来。
**LL形和RR形旋转一次O(1),LR和RL形旋转两次,也是O(1)。那么即使删除或者添加的节点影响的整个向上的链路,整体复杂度也是O(logN)**
AVL树继承自带左右旋的平衡搜索二叉树,在此基础上做的扩展,重写继承的抽象类平衡二叉搜索树的相应方法实现即可。
Avl树的一种实现方式参考:https://github.com/emirpasic/gods/blob/master/trees/avltree/avltree.go
### 1.5.2 SB树
对于平衡性而言,任何叔叔节点的子节点格式,不少于该节点的任何一个侄子节点子节点的个数
```
graph TD
c-->a
c-->e
a-->b
a-->d
e-->f
e-->g
```
即a是一个叔叔节点,一定不少于f和g的子节点个数
对于这种约束,也可保证任何节点的左右节点的个数不会有很大悬殊,即使高度不满足严格相减的绝对值小于2,也无伤大雅。整体仍然是O(logN)
#### 1.5.2.1 SB树针对某个节点的平衡性处理
2007年,读高中的时候,承志峰研究出来的;常被用作比赛时,AVL树反而在ACM比赛中使用的相对少点
也分为LL,LR,RR,RL四种类型。
当删除和插入某个节点,影响的节点的左孩子,不如其右孩子的左孩子节点个数多,RL形
当删除和插入某个节点,影响的节点的左孩子,不如其右孩子的右孩子节点个数多,RR形
当删除和插入某个节点,影响的节点的右孩子,不如其左孩子的左孩子节点个数多,LL形
当删除和插入某个节点,影响的节点的右孩子,不如其左孩子的右孩子节点个数多,LR形
1、 对于LL形违规,对头结点x进行一次右旋,结束后,递归调用所以节点孩子个数发生变化的节点。右旋的时候,头结点x,和原x左孩子现在变成了头节点的b。这两个节点孩子个数发生了变化,要递归调用这两个节点。原因是原来不违规的节点,调整了位置后,pk的对象变了,要基于现在的结构再检查平衡性。这里虽然套了两个递归,整体仍然是O(1),证明略
2、 RR形违规,和LL形违规类似处理;
**SB树平衡性相对于AVL树要模糊,所以平衡性调整比AVL的调整粒度要粗,也意味着SB树比AVL树速度要快,比赛常用。而且SB树可以设计成删除节点的时候,不进行平衡性调整,只有在添加节点的时候再进行平衡性调整,添加节点的时候有可能积压了很多的不平衡,但是我们有递归行为,仍然可以调整回平衡的状态;可能为棒状,有可能该次递归行为时间复杂度比较高,但是均摊下来仍然O(logN)水平;该结构比较重要**
**如果是违规的加点的左树高度超了,且左孩子的左右子节点个数相同,必须做LL形的调整,反之RR形同理**
- SB树的树结构版本
```Go
package main
import "fmt"
// SBTNode SBT树的节点类型
type SBTNode struct {
// 该节点的Key
key string
// 该节点的V
value int
// 节点的左孩子
l *SBTNode
// 节点的右孩子
r *SBTNode
// 不同的key的数量
size int
}
type Comparator func(a, b interface{}) int
// StringComparator 字符串字典序比较器。参考标准库实现,返回0,1,-1。
func StringComparator(a, b interface{}) int {
s1 := a.(string)
s2 := b.(string)
if s1 == s2 {
return 0
}
if s1 < s2 {
return -1
}
return +1
}
type SBTree struct {
Root *SBTNode
Comparator Comparator
}
// InitSBTTree 构建一个SBT树,返回头节点
func InitSBTTree(key string, value int) *SBTree {
root := &SBTNode{
key: key,
value: value,
size: 1,
}
sbTree := &SBTree{
Root: root,
Comparator: StringComparator,
}
return sbTree
}
// rightRotate 右旋交换节点时,size要互换,维护正确的size信息。返回右旋之后的新头部
func (tree *SBTree) rightRotate(cur *SBTNode) *SBTNode {
// 由于右旋,要维护好左子树
leftNode := cur.l
// 左孩子的右,给当前节点的左
cur.l = leftNode.r
// 左孩子的右,指向当前节点,画图可以清晰看到就是右旋操作
leftNode.r = cur
// 维护size
leftNode.size = cur.size
lSize := 0
rSize := 0
if cur.l != nil {
lSize = cur.l.size
} else {
lSize = 0
}
if cur.r != nil {
rSize = cur.r.size
} else {
rSize = 0
}
cur.size = lSize + rSize + 1
return leftNode
}
// leftRotate 左旋操作和右旋操作同理
func (tree *SBTree) leftRotate(cur *SBTNode) *SBTNode {
rightNode := cur.r
cur.r = rightNode.l
rightNode.l = cur
rightNode.size = cur.size
lSize := 0
rSize := 0
if cur.l != nil {
lSize = cur.l.size
} else {
lSize = 0
}
if cur.r != nil {
rSize = cur.r.size
} else {
rSize = 0
}
cur.size = lSize + rSize + 1
return rightNode
}
// maintain 对传入的cur节点,做平衡性调整。包含四种不平衡的调整策略:LL, LR, RL, RR
func (tree *SBTree) maintain(cur *SBTNode) *SBTNode {
if cur == nil {
return nil
}
if cur.l != nil && cur.l.l != nil && cur.r != nil && cur.l.l.size > cur.r.size { // LL形不平衡调整策略
// 当前节点右旋
cur = tree.rightRotate(cur)
// 递归调整个右孩子
cur.r = tree.maintain(cur.r)
// 递归调用调整当前节点
cur = tree.maintain(cur)
} else if cur.l != nil && cur.l.r != nil && cur.r != nil && cur.l.r.size > cur.r.size { // LR形不平衡调整策略
// 当前节点左孩子左旋
cur.l = tree.leftRotate(cur.l)
// 当前节点右旋
cur = tree.rightRotate(cur)
// 递归调用调整节点左孩子
cur.l = tree.maintain(cur.l)
// 递归调用调整节点右孩子
cur.r = tree.maintain(cur.r)
// 递归调用调整当前节点
cur = tree.maintain(cur)
} else if cur.r != nil && cur.r.r != nil && cur.l != nil && cur.r.r.size > cur.l.size { // RR形不平衡调整策略
// 当前节点左旋
cur = tree.leftRotate(cur)
// 递归调整当前节点左孩子
cur.l = tree.maintain(cur.l)
// 递归调整当前节点右孩子
cur = tree.maintain(cur)
} else if cur.r != nil && cur.r.l != nil && cur.l != nil && cur.r.l.size > cur.l.size { // RL形不平衡调整策略
// 当前节点右孩子右旋
cur.r = tree.rightRotate(cur.r)
// 当前节点左旋
cur = tree.leftRotate(cur)
// 递归调整当前节点左孩子
cur.l = tree.maintain(cur.l)
// 递归调整当前节点右孩子
cur.r = tree.maintain(cur.r)
// 递归调用调整当前节点
cur = tree.maintain(cur)
}
return cur
}
// findLastIndex 查找以key为节点key的节点是否存在
func (tree *SBTree) findLastIndex(key string) *SBTNode {
pre := tree.Root
cur := tree.Root
for cur != nil {
pre = cur
if tree.Comparator(key, cur.key) == 0 {
break
} else if tree.Comparator(key, cur.key) < 0 {
cur = cur.l
} else {
cur = cur.r
}
}
return pre
}
// findLastNoSmallIndex 找到第一个不比key小的节点,返回。即搜索树中字典序大于key的第一个节点
func (tree *SBTree) findLastNoSmallIndex(key string) *SBTNode {
var ans *SBTNode
cur := tree.Root
for cur != nil {
if tree.Comparator(key, cur.key) == 0 {
ans = cur
break
} else if tree.Comparator(key, cur.key) < 0 {
ans = cur
cur = cur.l
} else {
cur = cur.r
}
}
return ans
}
// findLastNoBigIndex 在搜索树上查找不大于key的第一个数,即小于等于key的第一个节点返回
func (tree *SBTree) findLastNoBigIndex(key string) *SBTNode {
var ans *SBTNode
cur := tree.Root
for cur != nil {
if tree.Comparator(key, cur.key) == 0 {
ans = cur
break
} else if tree.Comparator(key, cur.key) < 0 {
cur = cur.l
} else {
ans = cur
cur = cur.r
}
}
return ans
}
// add tree树上,加(key, value)这样的一条记录。cur传入tree的头节点
// 加完之后,会对tree做检查,该调整调整
// 返回,调整完之后,整棵树的新头部, 被替换掉了。把新树头节点返回
func (tree *SBTree) add(cur *SBTNode, key string, value int) *SBTNode {
if cur == nil {
return InitSBTTree(key, value).Root
} else {
cur.size++
if tree.Comparator(key, cur.key) < 0 {
cur.l = tree.add(cur.l, key, value)
} else {
cur.r = tree.add(cur.r, key, value)
}
return tree.maintain(cur)
}
}
// 在cur这棵树上,删掉key所代表的节点。cur为tree的头节点
// 返回cur这棵树的新头部
func (tree *SBTree) delete(cur *SBTNode, key string) *SBTNode {
cur.size--
if tree.Comparator(key, cur.key) > 0 {
cur.r = tree.delete(cur.r, key)
} else if tree.Comparator(key, cur.key) < 0 {
cur.l = tree.delete(cur.l, key)
} else { // 当前要删掉cur
if cur.l == nil && cur.r == nil {
cur = nil // free cur memory
} else if cur.l == nil && cur.r != nil {
cur = cur.r // free cur memory
} else if cur.l != nil && cur.r == nil {
cur = cur.l // free cur memory
} else { // 有左右右的情况
var pre *SBTNode
des := cur.r
des.size--
for des.l != nil {
pre = des
des = des.l
des.size--
}
if pre != nil {
pre.l = des.r
des.r = cur.r
}
des.l = cur.l
desRSize := 0
if des.r == nil {
desRSize = 0
} else {
desRSize = des.r.size
}
des.size = des.l.size + desRSize + 1
// free cur memory
cur = des
}
}
return cur
}
func (tree *SBTree) getIndex(cur *SBTNode, kth int) *SBTNode {
lSize := 0
if cur.l != nil {
lSize = cur.l.size
} else {
lSize = 0
}
if kth == lSize+1 {
return cur
} else if kth <= lSize {
return tree.getIndex(cur.l, kth)
} else {
return tree.getIndex(cur.r, kth-lSize-1)
}
}
func (tree *SBTree) size() int {
if tree.Root == nil {
return 0
} else {
return tree.Root.size
}
}
func (tree *SBTree) containsKey(key string) (bool, error) {
if len(key) == 0 {
return false, fmt.Errorf("invalid parameter")
}
lastNode := tree.findLastIndex(key)
isEqual := false
if tree.Comparator(key, lastNode.key) == 0 {
isEqual = true
} else {
isEqual = false
}
return lastNode != nil && isEqual, nil
}
// put 方法,有可能是新增有可能是覆盖更新
func (tree *SBTree) put(key string, value int) error {
if len(key) == 0 {
return fmt.Errorf("invalid parameter")
}
lastNode := tree.findLastIndex(key)
if lastNode != nil && tree.Comparator(key, lastNode.key) == 0 {
lastNode.value = value
} else {
// 不存在的话,从根节点调用递归,加入到合适的位置。sb树由于没有向上指针,这里需要从头结点开始调用递归
// 添加进去后,有可能需要调整,头部有可能会变,返回新的头部
tree.Root = tree.add(tree.Root, key, value)
}
return nil
}
func (tree *SBTree) remove(key string) error {
if len(key) == 0 {
return fmt.Errorf("invalid parameter")
}
if b, e := tree.containsKey(key); e == nil && b {
tree.Root = tree.delete(tree.Root, key)
}
return nil
}
func (tree *SBTree) getIndexKey(index int) (string, error) {
if index < 0 || index > tree.Root.size {
return "", fmt.Errorf("invalid parameter")
}
return tree.getIndex(tree.Root, index + 1).key, nil
}
func (tree *SBTree) getIndexValue(index int) (int, error) {
if index < 0 || index > tree.Root.size {
return -1, fmt.Errorf("invalid parameter")
}
return tree.getIndex(tree.Root, index + 1).value, nil
}
func (tree *SBTree) get(key string) (int, error) {
if len(key) == 0 {
return -1, fmt.Errorf("invalid parameter")
}
lastNode := tree.findLastIndex(key)
if lastNode != nil && tree.Comparator(key, lastNode.key) == 0 {
return lastNode.value, nil
} else {
return -1, fmt.Errorf("not find")
}
}
func (tree *SBTree) firstKey() (string, error) {
if tree.Root == nil {
return "", fmt.Errorf("not find because root is nil")
}
cur := tree.Root
for cur.l != nil {
cur = cur.l
}
return cur.key, nil
}
func (tree *SBTree) lastKey() (string, error) {
if tree.Root == nil {