红黑树增删查python实现

'''
一、红黑树性质

结点必须是红色或者黑色。
根节点必须是黑色。
叶节点(NIL)必须是黑色(NIL节点无数据,是空节点)。
红色结点不能连续。
从任一节点出发到其每个叶子节点的路径,黑色节点的数量必须相等。

'''
from dataStructures.tree.biTree.bst import BST

class RBNode:
def init(self, data):
self.elem = data
self.parent = None
self.lchild = None
self.rchild = None
self.color = 'r'

class RBTree(BST):
def init(self, li):
BST.init(self, li)

def changeColor(self, p, c):
    pre_p = p.parent
    pre_p.lchild.color = 'b'
    pre_p.rchild.color = 'b'
    pre_p.color = 'r'

    if pre_p == self.root:
        p.parent.color = 'b'

    return pre_p


def rotate_left_left(self, p, c):
    #祖父结点右旋
    pre_p = p.parent
    rchild_p = p.rchild
    p.rchild = pre_p
    pre_p.parent = p
    pre_p.lchild = rchild_p
    if rchild_p:
        rchild_p.parent = pre_p

    #变色
    pre_p.color = 'r'
    p.color = 'b'

    return p

def rotate_right_right(self, p, c):
    #祖父结点左旋
    pre_p = p.parent
    lchild_p = p.lchild
    p.lchild = pre_p
    pre_p.parent = p
    pre_p.rchild = lchild_p
    if lchild_p:
        lchild_p.parent = pre_p

    #变色
    pre_p.color = 'r'
    p.color = 'b'

    return p

def rotate_left_right(self, p, c):
    #父节点左旋
    pre_p = p.parent
    lchild_c = c.lchild
    c.lchild = p
    p.parent = c
    p.rchild = lchild_c
    if lchild_c:
        lchild_c.parent = p
    c.parent = pre_p
    pre_p.lchild = c

    #祖父节点右旋
    rchild_c = c.rchild
    c.rchild = pre_p
    pre_p.lchild = rchild_c
    pre_p.parent = c
    if rchild_c:
        rchild_c.parent = pre_p

    #变色
    c.color = 'b'
    pre_p.color = 'r'

    return c

def rotate_right_left(self, p, c):
    # 父节点右旋
    pre_p = p.parent
    rchild_c = c.rchild
    c.rchild = p
    p.parent = c
    p.lchild = rchild_c
    if rchild_c:
        rchild_c.parent = p
    c.parent = pre_p
    pre_p.rchild = c

    #祖父节点左旋
    lchild_c = c.lchild
    c.lchild = pre_p
    pre_p.rchild = lchild_c
    pre_p.parent = c
    if lchild_c:
        lchild_c.parent = pre_p

    #变色
    c.color = 'b'
    pre_p.color = 'r'

    return c

def insert_no_rec(self, val):
    # 1. 和BST一样,插入
    p = self.root
    if not p:  # 空树
        self.root = RBNode(val)
        self.root.color = 'b'
        return
    while True:
        if val < p.elem:
            if p.lchild:
                p = p.lchild  # node存储就是插入的结点
            else:  # 左孩子不存在
                p.lchild = RBNode(val)
                p.lchild.parent = p
                node = p.lchild  # node 存储的就是插入的节点
                break
        elif val > p.elem:
            if p.rchild:
                p = p.rchild
            else:
                p.rchild = RBNode(val)
                p.rchild.parent = p
                node = p.rchild
                break
        else:  # val == p.data
            return


    while node.parent and node.parent != self.root:
        if node.color == 'b' or node.parent.color == 'b' :
            break

        else:
            pre_p = node.parent.parent
            pre_pre_p = pre_p.parent  # 祖祖节点
            p = node.parent
            if node.color == 'r' and p.color == 'r':
                # 祖父节点左子树
                if pre_p.lchild == p:
                    # 如果叔父节点都为红直接变色再判断
                    if pre_p.rchild and pre_p.rchild.color == 'r':
                        node = self.changeColor(node.parent, node)
                        continue
                    #父亲节点左子树
                    if p.lchild == node:
                        #判断祖父节点右子树的情况
                        node = self.rotate_left_left(node.parent, node)
                    else:
                        node = self.rotate_left_right(node.parent, node)

                # 祖父节点右子树
                elif pre_p.rchild == p:
                    # 如果叔父节点都为红直接变色再判断
                    if pre_p.lchild and pre_p.lchild.color == 'r':
                        node = self.changeColor(node.parent, node)
                        continue
                    if p.lchild == node:
                        node = self.rotate_right_left(node.parent, node)
                    else:
                        node = self.rotate_right_right(node.parent, node)

            # 连接旋转后都子树
            node.parent = pre_pre_p
            if pre_pre_p:
                if pre_p == pre_pre_p.lchild:
                    pre_pre_p.lchild = node
                else:
                    pre_pre_p.rchild = node
                node.parent = pre_pre_p
                break
            else:
                self.root = node
                break

def del_red_no_leaf(self, c):
    if c.parent.lchild == c:
        c.parent.lchild = None
    else:
        c.parent.rchild = None

def del_black_cur_1(self, c, p, b):
    # 兄弟结点是黑色的,而且有一个同方向的子结点(可断定右节点是红色)
    # 兄弟节点只有一个子节点
    # c为左子树,有兄弟节点并且兄弟节点有右孩子
    if c == p.lchild and b.rchild:
        b.color = p.color         #1、父节点颜色赋给兄弟结点
        b.rchild.color = 'b'      #2、将父亲节点和兄弟结点右孩子设为黑色)
        p.color = 'b'
        p.lchild = None           #3、将被删除节点删除
        b.lchild = p              #4、父节点左旋
        p.parent = b
        p.lchild, p.rchild = None, None

        return b        #返回旋转后的子树的根节点

    # c为左子树,有兄弟节点并且兄弟节点有左孩子
    elif c == p.lchild and b.lchild:
        #兄弟结点是黑色的,且有一个左节点(可以断定左节点是红色)
        b.lchild.color = 'b'        #1、将该左孩子设置为黑色
        b.color = 'r'               #2、将兄弟结点设置为红色
        p.rchild = b.lchild
        b.lchild.parent = p
        p.rchild.rchild = b
        b.parent = p.rchild
        b.lchild, b.rchild = None, None

        b = p.rchild
        #回到情况1
        b.color = p.color  # 1、父节点颜色赋给兄弟结点
        b.rchild.color = 'b'  # 2、将父亲节点和兄弟结点右孩子设为黑色)
        p.color = 'b'
        p.lchild = None  # 3、将被删除节点删除
        b.lchild = p  # 4、父节点左旋
        p.parent = b
        p.lchild, p.rchild = None, None

        return b  # 返回旋转后的子树的根节点

    # c为右子树,有兄弟节点并且兄弟节点有左孩子
    elif c == p.rchild and b.lchild:
        b.color = p.color        #1、父节点颜色赋给兄弟结点
        p.color = 'b'            #2、将父亲节点和兄弟结点左孩子设为黑色
        b.lchild.color = 'b'
        c = None   #3、删除节点c
        p.rchild = None
        b.rchild = p              #4、对父亲节点右旋转
        p.parent = b
        p.lchild, p.rchild = None, None

        return b

    # c为右子树,有兄弟节点并且兄弟结点有右孩子
    else:
        # 兄弟结点是黑色的,且有一个右节点(可以断定右节点是红色)
        b.rchild.color = 'b'  # 1、将该右孩子设置为黑色
        b.color = 'r'  # 2、将兄弟结点设置为红色
        b_rchild = b.rchild  # 3、对兄弟结点左旋转
        b_rchild.lchild = b
        b.parent = b_rchild
        p.lchild = b_rchild
        b_rchild.parent = p

        b = p.lchild

        b.color = p.color  # 1、父节点颜色赋给兄弟结点
        p.color = 'b'  # 2、将父亲节点和兄弟结点左孩子设为黑色
        b.lchild.color = 'b'
        p.rchild = None # 删除节点c
        b.rchild = p  # 4、对父亲节点右旋转
        p.parent = b
        p.lchild, p.rchild = None, None

        return b

def del_black_cur_2(self, c, p, b):
    # 兄弟节点是黑色的,且有两个节点(可以断定左右节点都是红色的)
    if c == p.lchild and b.color == 'b':
        b.color = p.color       #1、将父节点的颜色赋给兄弟节点
        b.rchild.color = 'b'    #2、将兄弟结点的右孩子设为黑色
        p.color = 'b'           #3、将父亲节点设为黑色
        p.lchild = None         #4、删除节点c
        b_lchild = b.lchild     #5、对父亲节点左旋
        p.rchild = b_lchild
        b_lchild.parent = p
        b.lchild = p
        p.parent = b

        return b

    # 兄弟节点是红色的,那么根据红黑树性质有它有两个黑色子节点
    elif c == p.lchild and b.color == 'r':
        b.color = 'b'           # 1、将兄弟节点设为黑色
        b.lchild.color = 'r'    # 2、将兄弟结点的左孩子设为红色
        p.lchild = None         # 3、删除节点c
        b_lchild = b.lchild     # 4、对父亲节点左旋
        p.rchild = b_lchild
        b_lchild.parent = p
        b.lchild = p
        p.parent = b

        return b

    elif c == p.rchild and b.color == 'b':
        b.color = p.color  # 1、将父节点的颜色赋给兄弟节点
        b.lchild.color = 'b'  # 2、将兄弟结点的左孩子设为黑色
        p.color = 'b'  # 3、将父亲节点设为黑色
        p.rchild = None  # 4、删除节点c
        b_rchild = b.rchild  # 5、对父亲节点右旋
        p.lchild = b_rchild
        b_rchild.parent = p
        b.rchild = p
        p.parent = b

        return b

    else:
        b.color = 'b'  # 1、将兄弟节点设为黑色
        b.rchild.color = 'r'  # 2、将兄弟结点的右孩子设为红色
        p.rchild = None  # 3、删除节点c
        b_rchild = b.rchild  # 4、对父亲节点右旋
        p.rchild = b_rchild
        b_rchild.parent = p
        b.rchild = p
        p.parent = b

        return b


def del_black_cur_0(self,c, p, b):
    '''
    替换节点R是黑色,无子节点,而且是其黑色父节点的左子节点,而且替换节点的兄弟节点是黑色的,且都无子节点:此时对这三个节点无论怎样变换都无法在删除R节点后让树平衡,所以此时需要向上探索保持平衡,也就是将P节点视作R节点向上平衡(所谓将P节点视作R节点也就是将不在乎P节点的左右子节点,就当做这是要被替换删除的一个树末节点,然后向上重新平衡),但并不是要删除P节点,而是通过一层层向上调整(向上调整也就是将P节点是为要被删除的节点,判断其为3,4,5,6中的哪一种情况,如果是3,4,5情况就可以直接调整平衡,但如果是情况6则继续向上一层调整)来重新让树达到平衡,达到平衡后在删除R节点
    :param c:
    :param p:
    :param b:
    :return:
    '''
    #兄弟节点是黑色的,而且没有子节点
    #将兄弟结点设为红色,将父节点设为当前节点递归,直到根节点或遇到红色节点
    if c == p.lchild:  # 先删除节点
        p.lchild = None
        p.rchild.color = 'r'  # 右孩子设为红节点

    else:
        p.rchild = None
        p.lchild.color = 'r'  # 左孩子设为红节点

    c = p       #找到父节点为红或者树顶的子节点
    while c.parent.color != 'r' and c.parent != self.root:
        c = c.parent

    p = c.parent    #左旋右旋操作
    if p.rchild == c:
        p_lchild_rchild = p.lchild.rchild
        p_lchild = p.lchild
        p_lchild.rchild = p
        p.parent = p_lchild

        p.lchild = p_lchild_rchild
        p_lchild_rchild.parent = p

        t = p_lchild

    else:
        p_rchild_lchild = p.rchild.lchild
        p_rchild = p.rchild
        p_rchild.lchild = p
        p.parent = p_rchild

        p.rchild = p_rchild_lchild
        p_rchild_lchild.parent = p

        t = p_rchild

    return t

def delete_no_rec(self, val):
    # 1、查找
    c = self.query_no_rec(val)

    while c:
        # 2、
        #   A、删除的是叶子节点且该叶子节点是红色的 ---> 无需修复,因为它不会破坏红黑树的5个特性
        #   B、删除的是叶子节点且该叶子节点是黑色的 ---> 很明显会破坏特性5,需要修复
        if not c.lchild and not c.rchild:
            if c.color == 'r':
                #红节点直接删除
                self.del_red_no_leaf(c)
                return
            else:
                #若最后删除的为黑色叶子结点,则必定有兄弟结点
                p = c.parent   #父亲结点
                g = p.parent   #祖父节点
                before_p = p   #保留p后做判断
                b = p.rchild if p.lchild == c else p.lchild
                # 有兄弟结点并且兄弟节点有俩个孩子
                if b.color == 'b' and b.lchild and b.rchild:
                    p = self.del_black_cur_2(c, p, b)
                    break
                # 有兄弟结点并且兄弟节点有一个孩子
                elif b.color == 'b' and (b.lchild or b.rchild):
                    p = self.del_black_cur_1(c, p, b)
                    break
                # 有兄弟结点并且兄弟节点无孩子
                else:
                    p = self.del_black_cur_0(c, p ,b)
                    return

        #   C、删除的节点(为了便于叙述我们将其称为P)下面有一个子节点 S,对于这种情况我们通过 将P和S的值交换的方式,巧妙的将删除P变为删除S,S是叶子节点,这样C这种情况就会转 换为A, B这两种情况:
        #   C1: P为黑色,S为红色 ---> 对应 (1) 这种情况
        #   C2: P为黑色或红色,S为黑色 --- > 对应 (2) 这种情况
        #   不会出现超过两层的情况,因为红黑树会自动旋转调整树的高度
        elif (not c.lchild and c.rchild) or (c.lchild and not c.rchild):
            while c.lchild or c.rchild:
                # 与左孩子交换值
                if c.lchild:
                    c.elem = c.lchild.elem
                    c = c.lchild
                # 与右孩子交换值
                else:
                    c.elem = c.rchild.elem
                    c = c.rchild

        #   D、删除的节点有两个子节点,对于这种情况,我们通过将P和它的后继节点N的值交换的方 式,将删除节点P转换为删除后继节点N,而后继节点只可能是以下两种情况:

        #    D1: N是叶子节点 --- > 对应情况 A 或 B

        #    D2: N有一个子节点 ---- > 对应情况 C
        #    所以通过上面的分析我们发现,红黑树节点删除后的修复操作都可以转换为A或
        #    B这两种情况,而A不需要修复,所以我们只需要研究B这种情况如何修复就行了。
        elif c.lchild and c.rchild:
            # 找到后继结点
            tmp_c = c
            tmp_c = tmp_c.rchild
            while tmp_c.lchild:
                tmp_c = tmp_c.lchild

            #交换值
            c.elem = tmp_c.elem
            c = tmp_c

    # 连接旋转后都子树
    if g:
        if before_p == g.lchild:
            g.lchild = p
        else:
            g.rchild = p
        p.parent = g
    else:
        self.root = p

# 中序遍历
def in_order(self, root):
    if root:
        self.in_order(root.lchild)
        print(root.elem, root.color,end='\n')
        self.in_order(root.rchild)

import random
li = [random.randint(0, 10000) for i in range(20)]
print(li)
t = RBTree([10,22,55,49,33,69,44,3,1,0,5,2,15,17,90])
t.delete_no_rec(90)

print(t.root.elem,t.root.color)

print(t.root.lchild.elem,t.root.lchild.color)

print(t.root.rchild.elem,t.root.rchild.color)

print(t.root.rchild.rchild.elem,t.root.rchild.rchild.color)

print(t.root.lchild.rchild.elem,t.root.lchild.rchild.color)

print(t.root.lchild.elem,t.root.lchild.color)

t.in_order(t.root)

print(t.root.elem)

上一篇:树2 List Leaves


下一篇:内网域横向PTH&PTK&PTT哈希票据传递