Skip to content

Commit

Permalink
gogog
Browse files Browse the repository at this point in the history
  • Loading branch information
hunterhug committed Mar 31, 2020
1 parent c245dcb commit afce11f
Show file tree
Hide file tree
Showing 13 changed files with 651 additions and 21 deletions.
498 changes: 484 additions & 14 deletions algorithm/search/llrb_tree.md

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion basic/refer.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@
- [维基百科,AVL树:https://zh.wikipedia.org/wiki/AVL%E6%A0%91](https://zh.wikipedia.org/wiki/AVL%E6%A0%91)
- [2-3树与2-3-4树:https://blog.csdn.net/qq_25940921/article/details/82183601](https://blog.csdn.net/qq_25940921/article/details/82183601)
- [什么是2-3树:https://zhuanlan.zhihu.com/p/92394224](https://zhuanlan.zhihu.com/p/92394224)
- [2-3树与红黑树:https://riteme.site/blog/2016-3-12/2-3-tree-and-red-black-tree.html](https://riteme.site/blog/2016-3-12/2-3-tree-and-red-black-tree.html)
- [2-3树与红黑树:https://riteme.site/blog/2016-3-12/2-3-tree-and-red-black-tree.html](https://riteme.site/blog/2016-3-12/2-3-tree-and-red-black-tree.html)
- [2-3TreePPT:https://www.cs.drexel.edu/~amd435/courses/cs260/lectures/L-6_2-3_Trees.pdf](https://www.cs.drexel.edu/~amd435/courses/cs260/lectures/L-6_2-3_Trees.pdf)
- [左倾红黑树代码实现:https://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html](https://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html)
170 changes: 164 additions & 6 deletions code/llrbt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,42 @@ func RotateRight(h *LLRBTNode) *LLRBTNode {
return x
}

// 颜色转换
// 红色左移
// 节点 h 是红节点,其左儿子和左儿子的左儿子都为黑节点,左移后使得其左儿子或左儿子的左儿子有一个是红色节点
func MoveRedLeft(h *LLRBTNode) *LLRBTNode {
// 应该确保 isRed(h) && !isRed(h.left) && !isRed(h.left.left)
ColorChange(h)

// 右儿子有左红链接
if IsRed(h.Right.Left) {
// 对右儿子右旋
h.Right = RotateRight(h.Right)
// 再左旋
h = RotateLeft(h)
ColorChange(h)
}

return h
}

// 红色右移
// 节点 h 是红节点,其右儿子和右儿子的左儿子都为黑节点,右移后使得其右儿子或右儿子的右儿子有一个是红色节点
func MoveRedRight(h *LLRBTNode) *LLRBTNode {
// 应该确保 isRed(h) && !isRed(h.right) && !isRed(h.right.left);
ColorChange(h)

// 左儿子有左红链接
if IsRed(h.Left.Left) {
// 右旋
h = RotateRight(h)
// 变色
ColorChange(h)
}

return h
}

// 颜色变换
func ColorChange(h *LLRBTNode) {
if h == nil {
return
Expand Down Expand Up @@ -111,6 +146,7 @@ func (node *LLRBTNode) Add(value int64) *LLRBTNode {
nowNode := node

// 右链接为红色,那么进行左旋,确保树是左倾的
// 这里做完操作后就可以结束了,因为插入操作,新插入的右红链接左旋后,nowNode节点不会出现连续两个红左链接,因为它只有一个左红链接
if IsRed(nowNode.Right) && !IsRed(nowNode.Left) {
nowNode = RotateLeft(nowNode)
} else {
Expand Down Expand Up @@ -170,11 +206,6 @@ func (node *LLRBTNode) FindMaxValue() *LLRBTNode {

// 查找指定节点
func (tree *LLRBTree) Find(value int64) *LLRBTNode {
if tree.Root == nil {
// 如果是空树,返回空
return nil
}

return tree.Root.Find(value)
}

Expand Down Expand Up @@ -221,6 +252,123 @@ func (node *LLRBTNode) MidOrder() {
node.Right.MidOrder()
}

// 修复左倾红黑树特征
func (node *LLRBTNode) FixUp() *LLRBTNode {
// 辅助变量
nowNode := node

// 红链接在右边,左旋恢复,让红链接只出现在左边
if IsRed(nowNode.Right) {
nowNode = RotateLeft(nowNode)
}

// 连续两个左链接为红色,那么进行右旋
if IsRed(nowNode.Left) && IsRed(nowNode.Left.Left) {
nowNode = RotateRight(nowNode)
}

// 旋转后,可能左右链接都为红色,需要变色
if IsRed(nowNode.Left) && IsRed(nowNode.Right) {
ColorChange(nowNode)
}

return nowNode
}

// 对该节点所在的子树删除最小元素
func (node *LLRBTNode) DeleteMin() *LLRBTNode {
// 辅助变量
nowNode := node

// 没有左子树,那么删除它自己
if nowNode.Left == nil {
return nil
}

// 判断是否需要红色左移,因为最小元素在左子树中
if !IsRed(nowNode.Left) && !IsRed(nowNode.Left.Left) {
nowNode = MoveRedLeft(nowNode)
}

// 递归从左子树删除
nowNode.Left = nowNode.Left.DeleteMin()

// 修复左倾红黑树特征
return nowNode.FixUp()
}

// 左倾红黑树删除元素
func (tree *LLRBTree) Delete(value int64) {
// 当找不到值时直接返回
if tree.Find(value) == nil {
return
}

if !IsRed(tree.Root.Left) && !IsRed(tree.Root.Right) {
// 左右子树都是黑节点,那么先将根节点变为红节点,方便后面的红色左移或右移
tree.Root.Color = RED
}

tree.Root = tree.Root.Delete(value)

// 最后,如果根节点非空,永远都要为黑节点,赋值黑色
if tree.Root != nil {
tree.Root.Color = BLACK
}
}

// 对该节点所在的子树删除元素
func (node *LLRBTNode) Delete(value int64) *LLRBTNode {
// 辅助变量
nowNode := node
// 删除的元素比子树根节点小,需要从左子树删除
if value < nowNode.Value {
// 因为从左子树删除,所以要判断是否需要红色左移
if !IsRed(nowNode.Left) && !IsRed(nowNode.Left.Left) {
// 左儿子和左儿子的左儿子都不是红色节点,那么没法递归下去,先红色左移
nowNode = MoveRedLeft(nowNode)
}

// 现在可以从左子树中删除了
nowNode.Left = nowNode.Left.Delete(value)
} else {
// 删除的元素等于或大于树根节点

// 左节点为红色,那么需要右旋,方便后面可以红色右移
if IsRed(nowNode.Left) {
nowNode = RotateRight(nowNode)
}

// 值相等,且没有右孩子节点,那么该节点一定是要被删除的叶子节点,直接删除
// 为什么呢,反证,它没有右儿子,但有左儿子,因为左倾红黑树的特征,那么左儿子一定是红色,但是前面的语句已经把红色左儿子右旋到右边,不应该出现右儿子为空。
if value == nowNode.Value && nowNode.Right == nil {
return nil
}

// 因为从右子树删除,所以要判断是否需要红色右移
if !IsRed(nowNode.Right) && !IsRed(nowNode.Right.Left) {
// 右儿子和右儿子的左儿子都不是红色节点,那么没法递归下去,先红色右移
nowNode = MoveRedRight(nowNode)
}

// 删除的节点找到了,它是中间节点,需要用最小后驱节点来替换它,然后删除最小后驱节点
if value == nowNode.Value {
minNode := nowNode.Right.FindMinValue()
nowNode.Value = minNode.Value
nowNode.Times = minNode.Times

// 删除其最小后驱节点
nowNode.Right = nowNode.Right.DeleteMin()
} else {
// 删除的元素比子树根节点大,需要从右子树删除
nowNode.Right = nowNode.Right.Delete(value)
}
}

// 最后,删除叶子节点后,需要恢复左倾红黑树特征
return nowNode.FixUp()
}

func main() {
tree := NewLLRBTree()
values := []int64{2, 3, 7, 10, 10, 10, 10, 23, 9, 102, 109, 111, 112, 113, 115, 18}
Expand Down Expand Up @@ -249,4 +397,14 @@ func main() {
}

tree.MidOrder()

tree.Delete(9)

// 查找存在的9
node = tree.Find(9)
if node != nil {
fmt.Println("find it 9!")
} else {
fmt.Println("not find it 9!")
}
}
Binary file added picture/2-3_tree_delete1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added picture/2-3_tree_delete2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added picture/2-3_tree_delete3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added picture/2-3_tree_delete4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added picture/2-3_tree_delete5.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added picture/2-3_tree_delete6.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added picture/llbr_tree_delete4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added picture/llrb_tree_delete1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added picture/llrb_tree_delete2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added picture/llrb_tree_delete3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit afce11f

Please sign in to comment.