zoukankan      html  css  js  c++  java
  • 红黑树

    package main
    
    import (
        "fmt"
        "unsafe"
    )
    
    /*
    定义:
    1)每个结点要么是红的,要么是黑的。
    2)根结点是黑的。
    3)每个叶结点(叶结点即指树尾端NIL指针或NULL结点)是黑的。
    4)如果一个结点是红的,那么它的俩个儿子都是黑的。
    5)对于任一结点而言,其到叶结点树尾端NIL指针的每一条路径都包含相同数目的黑结点。
    */
    //红黑树(平衡二叉树)
    type RBTree struct {
        index, height                 int
        isRed                         bool
        parent, leftChild, rightChild *RBTree
        ptr                           unsafe.Pointer //记录数据地址
    }
    
    func NewRBTree(index int, ptr unsafe.Pointer) *RBTree {
        return &RBTree{
            index:  index,
            isRed:  false,
            height: 1,
            ptr:    ptr,
        }
    }
    
    //判断一个节点是左孩子还是右孩子,排除根节点情况
    func (root *RBTree) IsLeftChild() bool {
        if root.parent == nil {
            return false
        }
        return root.parent.leftChild == root
    }
    
    //左旋 左斜线的情况
    func (h *Head) LeftRotate(root *RBTree) {
        var isParentLeft bool
        zufu := root.parent.parent
        isParentLeft = root.parent.IsLeftChild()
        root.leftChild = root.parent
        root.leftChild.parent = root
        root.leftChild.height++
        //将旋转得到的叶子节点左右孩子清空内存
        root.leftChild.leftChild = nil
        root.leftChild.rightChild = nil
        if zufu != nil {
            if isParentLeft {
                zufu.leftChild = root
            } else {
                zufu.rightChild = root
            }
            root.parent = zufu
            root.height = zufu.height + 1
        } else {
            h.ptr = root
            root.parent = nil
            root.height = 1
        }
    
        if root.rightChild != nil {
            root.rightChild.height--
        }
    }
    
    //右旋 右斜线的情况
    func (h *Head) RightRotate(root *RBTree) {
        var isParentLeft bool
        zufu := root.parent.parent
        isParentLeft = root.parent.IsLeftChild()
        root.rightChild = root.parent
        root.rightChild.parent = root
        root.rightChild.height++
        //将旋转得到的叶子节点左右孩子清空内存
        root.rightChild.leftChild = nil
        root.rightChild.leftChild = nil
        if zufu != nil {
            if isParentLeft {
                zufu.leftChild = root
            } else {
                zufu.rightChild = root
            }
            root.parent = zufu
            root.height = zufu.height + 1
        } else {
            h.ptr = root
            root.parent = nil
            root.height = 1
        }
    
        if root.leftChild != nil {
            root.leftChild.height--
        }
    }
    
    func (h *Head) Insert(node *RBTree) {
        p := h.ptr
        q := p
        for p != nil {
            q = p
            if node.index == p.index {
                return
            }
    
            if node.index < p.index {
                p = p.leftChild
            } else {
                p = p.rightChild
            }
        }
    
        if q.index < node.index {
            q.rightChild = node
            node.parent = q
        }
        if q.index > node.index {
            q.leftChild = node
            node.parent = q
        }
        //插入的新节点是红色
        node.isRed = true
        node.height = q.height + 1
        //如果父节点是黑色,不需要进行调整
        if !q.isRed {
            return
        }
    
        //父节点是红色
        //1.叔叔节点为红色 ==>父节点和叔叔节点改黑色
        if q.parent.leftChild != nil && q.parent.rightChild != nil {
            q.parent.leftChild.isRed = false
            q.parent.rightChild.isRed = false
            return
        }
    
        //2.叔叔节点为空,新节点和父节点,祖父节点一条线上
        //a.父节点和新节点都是左孩子
        if q.IsLeftChild() && node.IsLeftChild() {
            h.RightRotate(q)
            q.isRed = false
            q.leftChild.isRed = true
            q.rightChild.isRed = true
            return
        }
        //b.父节点和新节点都是右孩子
        if !q.IsLeftChild() && !node.IsLeftChild() {
            h.LeftRotate(q)
            q.isRed = false
            q.leftChild.isRed = true
            q.rightChild.isRed = true
            return
        }
    
        //3.叔叔节点为空,新节点和父节点,祖父节点不在一条线上
        //a.父节点为右孩子,新节点为左孩子
        if !q.IsLeftChild() && node.IsLeftChild() {
            //对新节点右旋,变成一条线上
            h.RightRotate(node)
            //再对新节点左旋
            h.LeftRotate(node)
            node.isRed = false
            node.leftChild.isRed = true
            node.rightChild.isRed = true
            return
        }
        //b.父节点为左孩子,新节点为右孩子
        if q.IsLeftChild() && !node.IsLeftChild() {
            //对新节点左旋,变成一条线上
            h.LeftRotate(node)
            //再对新节点右旋
            h.RightRotate(node)
            node.isRed = false
            node.leftChild.isRed = true
            node.rightChild.isRed = true
            return
        }
    }
    
    //层次遍历
    func Print(root *RBTree) {
        queq := make([]*RBTree, 0)
        if root == nil {
            return
        }
        i := 0
        queq = append(queq, root)
        for i < len(queq) {
            fmt.Println(queq[i].index, queq[i].height, queq[i].isRed, queq[i].parent)
            if queq[i].leftChild != nil {
                queq = append(queq, queq[i].leftChild)
            }
            if queq[i].rightChild != nil {
                queq = append(queq, queq[i].rightChild)
            }
            i++
        }
    }
    
    type Data struct {
        id   int
        name string
    }
    
    type Head struct {
        ptr *RBTree
    }
    
    func main() {
        //用链表头指向树的root地址
        test := []int{8, 7, 4, 5, 3, 2, 1}
        root := NewRBTree(6, unsafe.Pointer(&Data{10, "xxx"}))
        head := Head{root}
        fmt.Println(&root)
        fmt.Println(unsafe.Pointer(&root))
        for _, v := range test {
            head.Insert(&RBTree{index: v})
        }
        fmt.Println(&root)
        Print(head.ptr)
    }
  • 相关阅读:
    mybatis+spring报错PropertyAccessException 1: org.springframework.beans.MethodInvocationException
    jQuery实现判断li的个数从而实现其他功能
    移动平台对 meta 标签的定义
    移动平台对 meta 标签的定义
    HTML5手机网站开发页面宽度解决方案
    HTML5手机网站开发页面宽度解决方案
    别做“不会思考的码农”
    别做“不会思考的码农”
    myeclipse+spket1.6+Extjs4.2开发环境搭建
    myeclipse+spket1.6+Extjs4.2开发环境搭建
  • 原文地址:https://www.cnblogs.com/fwdqxl/p/8534504.html
Copyright © 2011-2022 走看看