美文网首页
算法导论之红黑树&区间树

算法导论之红黑树&区间树

作者: 东来_198c | 来源:发表于2018-12-13 23:43 被阅读0次

    实验要求

    image.png

    实验代码

    区间树的很多操作是红黑树进行一点简单的修改,区间树中加入的max域 注意在插入和旋转的时候进行对max域进行维护与更新。

    一点新学到的tricks

    多用python的定向输出比较适合需要输出多个文件的时候。

    一点问题

    对于NIL的指针,处理的还不够巧妙,整个代码基本是算法导论照搬,但是NIL指针的定义和处理还需要修改和理解

    代码

    #USTC Donglai Ma
    
    # The basic code come from 'Introduction to Algorithms'
    import sys
    class RBTreenode(object):
        def __init__(self,inter):
            nil = Inter(-1,-1)
            self.parent = None
            self.key = inter.low
            self.left = None
            self.right = None
            self.color = "black"
            self.max = 0
    
            # Inter for code x
            self.inter = inter
    
    
    
    
    
        # def printnode_inorder(self):
        #     # In-order traversal
        #     if self.left:
        #         self.left.print()
        #     print(self.key)
        #     if self.right:
        #         self.right.print()
        #
        #
    class Inter:
        def __init__(self,low,high):
            self.low = low
            self.high = high
    
    
    class RBTree:
        # Insert,Delete,Print,Left Rotate, Right Rotate
        def __init__(self):
            # Notice that the nil here use 0 to present
            nil = RBTreenode(Inter(-1,-1))
            self.nil = nil
            self.root = self.nil
    
    # Left Rotate
    
    
    def left_rotate(T, x):
        # Left Rotate
    
        y = x.right
        x.right = y.left
        if y.left != T.nil:
            y.left.parent = x
        y.parent = x.parent
        if x.parent == T.nil:
            T.root = y
        elif x == x.parent.left:
            x.parent.left = y
        else:
            x.parent.right = y
        y.left = x
        x.parent = y
    
        # update the max
        y.max = x.max
        x.max = max(x.inter.high,x.left.max,x.right.max)
    
    
    def right_rotate( T, x):
        # Right Rotate
        y = x.left
        x.left = y.right
        if y.right != T.nil:
            y.right.parent = x
        y.parent = x.parent
        if x.parent == T.nil:
            T.root = y
        elif x == x.parent.right:
            x.parent.right = y
        else:
            x.parent.left = y
        y.right = x
        x.parent = y
        # update the max
        x.max = y.max
        y.max = max(y.right.max,y.left.max,y.inter.high)
    
    
    def rb_insert(T, z):
        # insert the node
        y = T.nil
        x = T.root
        while x != T.nil:
            y = x
            if z.key < x.key:
                x = x.left
            else:
                x = x.right
        z.parent = y
        if y == T.nil:
            T.root = z
        elif z.key < y.key:
            y.left = z
        else:
            y.right = z
        z.left = T.nil
        z.right = T.nil
        z.color = 'red'
        # update the max of z
        z.max = max(z.inter.high,z.left.max,z.right.max)
        rb_insert_fixup(T, z)
        # update to root's  max
        while z.parent!=T.nil:
            z.parent.max = max(z.parent.max,z.max)
            z=z.parent
    
    
    
    def rb_insert_fixup( T, z):
    
        while z.parent.color == 'red':
            if z.parent == z.parent.parent.left:
                y = z.parent.parent.right
                if y.color == 'red': # case 1
                    z.parent.color = 'black'
                    y.color = 'black'
                    z.parent.parent.color = 'red'
                    z = z.parent.parent
                else:
                    if z == z.parent.right: #case 2
                        z = z.parent
                        left_rotate(T, z)
                    z.parent.color = 'black' # case 3
                    z.parent.parent.color = 'red'
                    right_rotate(T,z.parent.parent)
            else:
                y = z.parent.parent.left
                if y.color == 'red':
                    z.parent.color = 'black'
                    y.color = 'black'
                    z.parent.parent.color = 'red'
                    z = z.parent.parent
                else:
                    if z == z.parent.left:
                        z = z.parent
                        right_rotate(T, z)
                    z.parent.color = 'black'
                    z.parent.parent.color = 'red'
                    left_rotate(T, z.parent.parent)
        T.root.color = 'black'
    
    
    def rb_transplant(T, u, v):
        if u.parent == T.nil:
            T.root = v
        elif u == u.parent.left:
            u.parent.left = v
        else:
            u.parent.right = v
        v.parent = u.parent
    
    
    def rb_delete(T, m):
        # delete the z node
        #z = search_tree(T.root,m)
        z = interval_search(T,m)
        y = z
        y_original_color = y.color
        if z.left == T.nil:
            x = z.right
            rb_transplant(T, z, z.right)
        elif z.right == T.nil:
            x = z.left
            rb_transplant(T, z, z.left)
        else:
            y = tree_minimum(T,z.right)
            y_original_color = y.color
            x = y.right
            if y.parent == z:
                x.parent = y
            else:
                rb_transplant(T, y, y.right)
                y.right = z.right
                y.right.parent = y
            rb_transplant(T, z, y)
            y.left = z.left
            y.left.parent = y
            y.color = z.color
        if y_original_color == 'black':
            rb_delete_fixup(T, x)
    
    
    def rb_delete_fixup(T, x):
        while x != T.root and x.color == 'black':
            if x == x.parent.left:
                w = x.parent.right
                if w.color == 'red':
                    w.color = 'black' #case 1
                    x.parent.color = 'red'
                    left_rotate(T, x.parent)
                    w = x.parent.right
                if w.left.color == 'black' and w.right.color == 'black':
                    w.color = 'red' #case 2
                    x = x.parent
                else:
                    if w.right.color == 'black':
                        w.left.color = 'black' # case 3
                        w.color = 'red'
                        right_rotate(T, w)
                        w = x.parent.right
                    w.color = x.parent.color  # case 4
                    x.parent.color = 'black'
                    w.right.color = 'black'
                    left_rotate(T, x.parent)
                    x = T.root
            else:
                w = x.parent.left
                if w.color == 'red':
                    w.color = 'black'
                    x.parent.color = 'red'
                    right_rotate(T, x.parent)
                    w = x.parent.left
                if w.right.color == 'black' and w.left.color == 'black':
                    w.color = 'red'
                    x = x.parent
                else:
                    if w.left.color == 'black':
                        w.right.color = 'black'
                        w.color = 'red'
                        left_rotate(T, w)
                        w = x.parent.left
                    w.color = x.parent.color
                    x.parent.color = 'black'
                    w.left.color = 'black'
                    right_rotate(T, x.parent)
                    x = T.root
        x.color = 'black'
    
    
    def tree_minimum(T,x):
        while x.left != T.nil:
            x = x.left
        return x
    
    # def search_tree(A,x):
    #    while x != A.key:
    #        if x<A.key:
    #            A = A.left
    #        else:
    #            A = A.right
    #
    #    return A
    
    
    #Here we need to check the interval,i = interval
    def search_tree(A,i):
        while i.low !=A.key:
            if i.low <A.key:
                A = A.left
            else:
                A = A.right
        return A
    
    # Although it's interval , the key is interval.low and
    #   I assume key is same which means the i must in the Tree
    
    
    
    
    
    
    def interval_search(T,interval):
        x = T.root
        #not overlap
        while x!= T.nil and(x.inter.low >interval.high or x.inter.high<interval.low):
            if x.left!=T.nil and x.left.max>=interval.low:
                x=x.left
            else:
                x=x.right
        return x
    
    
    
    def Insort(x):
        if x!= None:
            Insort(x.left)
            if x.key!=0:
                print('key:', x.key,'x.parent',x.parent.key)
            Insort(x.right)
    
    
    #def preorder_sort(x):
        # if x!=None:
        #     if x.key!=0:print(x.key)
        #     preorder_sort(x.left)
        #     preorder_sort(x.right)
    
    
    def inorder_sort(x):
        if x!= None:
            inorder_sort(x.left)
            if x.key!=-1:
                print(x.inter.low,x.inter.high,x.max)
    
            inorder_sort(x.right)
    
    #def postorder_sort(x):
        # if x!= None:
        #     postorder_sort(x.left)
        #     postorder_sort(x.right)
        #     if x.key!=0:print(x.key)
    
    # Generate the inputB
    import numpy as np
    import random
    import time
    # list = []
    
    
    
    # list_left = [x for x in range(0,25)]
    # for i in range (30,50):
    #     list_left.append(i)
    # random.shuffle(list_left)
    # print(list_left)
    # list = []
    #
    #
    # for i in range(len(list_left)):
    #     if list_left[i]<25:
    #         list.append((list_left[i],random.randint(list_left[i]+1,25)))
    #     else:
    #         list.append((list_left[i],random.randint(list_left[i]+1,50)))
    # print(list)
    #
    #
    # np.savetxt("../inputB/random_interval_file.txt",list,fmt="%d")
    
    # read the input
    list_all= np.loadtxt("../inputB/random_interval_file.txt",dtype='int')
    #print(list_all[1,1])
    list_inter = []
    for i in range(len(list_all)):
        m = Inter(list_all[i,0],list_all[i,1])
        list_inter.append(m)
    
    T = RBTree()
    for i in range(0,30):
       rb_insert(T,RBTreenode(list_inter[i]))
    
    filename_inorder = str('../outputB/inorder.txt')
    filename_delete_data = str('../outputB/delete_data.txt')
    filename_search = str('../outputB/search.txt')
    savedStdout = sys.stdout   #保存标准输出流
    with open(filename_inorder, 'w+') as file:
        sys.stdout = file
        inorder_sort(T.root)
        file.close()
    
    
    with open(filename_delete_data, 'w+') as file:
        sys.stdout = file
        list_delete = random.sample(list_inter,3)
        rb_delete(T,list_delete[0])
        rb_delete(T,list_delete[1])
        rb_delete(T,list_delete[2])
        print('The deleted node is')
        for i in range(3):
    
            print(list_delete[i].low,list_delete[i].high,'\n')
    
        print ('The final inorder is ')
        inorder_sort(T.root)
        file.close()
    
    
    with open(filename_search, 'w+') as file:
        sys.stdout = file
        a = Inter(3,11)
        b = Inter(26,27)
        c = Inter(33,45)
        print('Search (3,11)')
        print(interval_search(T,a).inter.low,interval_search(T,a).inter.high)
        print('Search (26,27)')
        print(interval_search(T,b).inter.low,interval_search(T,b).inter.high)
        print('Search (33,45)')
        print(interval_search(T,c).inter.low,interval_search(T,c).inter.high)
    
        file.close()
    
    
    sys.stdout = savedStdout #恢复标准输出流
    
    
    
    

    相关文章

      网友评论

          本文标题:算法导论之红黑树&区间树

          本文链接:https://www.haomeiwen.com/subject/ukwihqtx.html