算法导论程序33--动态顺序统计

顺序统计:

n个元素集合中的第i(i属于{1,2,...,n})个顺序统计量就是简单地规定该集合中的具有第i小关键字的元素。


本文介绍如何修改红黑树,使得可以在O(lgn)时间内确定任何的顺序统计量。


顺序统计树T只是简单地在每个结点上存储附加信息的一棵红黑树,在红黑树的结点x中,除了通常属性x.key,x.color,x.p,x.left和x.right之外,还包括另一个属性x.size。

这个属性包含了以x为根的子树(包括x本身)的(内)结点数,即这课子树的大小。


如果定义哨兵的size大小为0,也就是设置T.nil.size为0。则有等式:

x.size=x.left.size+x.right.size+1


class Node:
    def __init__(self,key,right,left,p,color,size):
        self.key=key
        self.right=right
        self.left=left
        self.p=p
        self.color=color
        self.size=size

class tree:
    def __init__(self,root,nil):
        self.root=root
        self.nil=nil
    def tree_insert(self,z):
        y=self.nil
        x=self.root
        while x!=self.nil:
            y=x
            if z.key<x.key:
                x=x.left
            else:
                x=x.right
        z.p=y
        if y==self.nil:
            self.root=z
        elif z.key<y.key:
            y.left=z
        else:
            y.right=z
        z.left=self.nil
        z.right=self.nil
        z.color="RED"
        #z插入成功后,size初始化为1
        z.size=1
        #红黑树性质维护
        self.rb_insert_fixup(z)
        #更新结点z的父结点直到根结点的size属性
        while z.p!=self.nil:
            z.p.size+=1
            z=z.p
            
    def left_rotate(self,x):
        y=x.right
        x.right=y.left
        if y.left!=self.nil:
            y.left.p=x
        y.p=x.p
        if x.p==self.nil:
            self.root=y
        elif x==x.p.left:
            x.p.left=y
        else:
            x.p.right=y
        y.left=x
        x.p=y
        #左旋导致两个结点的size属性失效,size属性更新如下:
        y.size=x.size
        x.size=x.left.size+x.right.size+1
        

    def right_rotate(self,y):
        x=y.left
        y.left=x.right
        if x.right!=self.nil:
            x.right.p=y
        x.p=y.p  
        if y.p==self.nil:
            self.root=x
        elif y==y.p.left:
            y.p.left=x
        else:
            y.p.right=x
        x.right=y
        y.p=x
        #右旋导致两个结点的size属性失效,size属性更新如下:
        x.size=y.size
        y.size=y.right.size+y.left.size+1

    def rb_insert_fixup(self,z):
        while z.p.color=="RED":
            if z.p==z.p.p.left:
                y=z.p.p.right
                if y.color=="RED":
                    z.p.color="BLACK"
                    y.color="BLACK"
                    z.p.p.color="RED"
                    z=z.p.p
                else:
                    if z==z.p.right:
                        z=z.p
                        self.left_rotate(z)
                    z.p.color="BLACK"
                    z.p.p.color="RED"
                    self.right_rotate(z.p.p)
            else:
                y=z.p.p.left
                if y.color=="RED":
                    z.p.color="BLACK"
                    y.color="BLACK"
                    z.p.p.color="RED"
                    z=z.p.p
                else:
                    if z==z.p.left:
                        z=z.p
                        self.right_rotate(z)
                    z.p.color="BLACK"
                    z.p.p.color="RED"
                    self.left_rotate(z.p.p)
        self.root.color="BLACK"
    def inorder_tree_walk(self,x):
        if x!=self.nil:
            self.inorder_tree_walk(x.left)
            print(x.key)
            self.inorder_tree_walk(x.right)
    def tree_search(self,x,k):
        if x==self.nil or k==x.key:
            return x
        if k < x.key:
            return self.tree_search(x.left,k)
        else: return self.tree_search(x.right,k)

    def rb_transplant(self,u,v):
        if u.p==self.nil:
            self.root=v
        elif u==u.p.left:
            u.p.left=v
        else:
            u.p.right=v
        v.p=u.p
    def tree_minimum(self,x):
        while x.left!=self.nil:
            x=x.left
        return x

    
    def rb_delete(self,z):
        y=z
        y_original_color=y.color
        if z.left==self.nil:
            x=z.right
            self.rb_transplant(z,z.right)
        elif z.right==self.nil:
            x=z.left
            self.rb_transplant(z,z.left)
        else:
            y=self.tree_minimum(z.right)
            y_original_color=y.color
            x=y.right
            if y.p==z:
                x.p=y
            else:
                self.rb_transplant(y,y.right)
                y.right=z.right
                y.right.p=y
            self.rb_transplant(z,y)
            y.left=z.left
            y.left.p=y
            y.color=z.color
            if y_original_color=="BLACK":
                self.rb_delete_fixup(x)       
            

    def rb_delete_fixup(self,x):
        while x!=self.root and x.color=="BLACK":
            if x==x.p.left:
                w=x.p.right
                if w.color=="RED":
                    w.color="BLACK"
                    x.p.color="RED"
                    self.left_rotate(x.p)
                    w=x.p.right
                if w.left.color=="BLACK" and w.right.color=="BLACK":
                    w.color="RED"
                    x=x.p
                else:
                    if w.right.color=="BLACK":
                        w.left.color=="BLACK"
                        w.color="RED"
                        self.right_rotate(w)
                        w=x.p.right
                    w.color=x.p.color
                    x.p.color="BLACK"
                    w.right.color="BLACK"
                    self.left_rotate(x.p)
                    x=self.root
            else:
                w=x.p.left
                if w.color=="RED":
                    w.color="BLACK"
                    x.p.color="RED"
                    self.right_rotate(x.p)
                    w=x.p.left
                if w.right.color=="BLACK" and w.left.color=="BLACK":
                    w.color="RED"
                    x=x.p
                else:
                    if w.left.color=="BLACK":
                        w.right.color=="BLACK"
                        w.color="RED"
                        self.left_rotate(w)
                        w=x.p.left
                    w.color=x.p.color
                    x.p.color="BLACK"
                    w.left.color="BLACK"
                    self.right_rotate(x.p)
                    x=self.root
        x.color="BLACK"

    def print_tree(self,z):
        if z!=self.nil:
            print(z.key,z.color,":",end='')
            print("( ",end='')
            print(z.left.key,z.left.color,"   ",end='')
            print(z.right.key,z.right.color,end='')
            print(" )",end='')
            
    #找出统计树中的第i小的关键字
    def os_select(self,x,i):
        r=x.left.size+1
        if i==r:
            return x
        elif x<r:
            return self.os_select(x.left,i)
        else:
            #注意这种情况就应该找以x为根结点的右子树中第i-r小的关键字了。
            return self.os_select(x.right,i-r)
                
    #确定一个元素的秩:返回对T中序遍历对应的线性序中x的位置
    def os_rank(self,x):
        r=x.left.size+1
        y=x
        while y!=self.root:
            if y==y.p.right:
                r+=y.p.left.size+1
            y=y.p
        return r
            
        

    
    

运行结果:

>>> nil=Node(0,None,None,None,"BLACK",0)
>>> root=Node(7,nil,nil,nil,"BLACK",0)
>>> t=tree(root,nil)
>>> T=[4,18,3,6,11,19,2,9,14,22,12,17,20]
>>> for i in T:
	z=Node(i,nil,nil,nil,"RED",0)
	t.tree_insert(z)

	
>>> t.os_select(t.root,5)
<__main__.Node object at 0x0337DF90>
>>> t.os_select(t.root,5).key
7
>>> t.os_rank(t.tree_search(t.root,6))
4








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值