zoukankan      html  css  js  c++  java
  • 二叉搜索树,和红黑树,

    二叉搜索树
    class node():
         def __init__(self,a):
             self.val=a
             self.left=None
             self.right=None
    #当函数写起来复杂时候,考虑给函数加变量来细化,
    #类似的想法就是动态规划时候的说不清时候就考虑用更高维的动态规划来刻画
    def insert(root,a):#本质就是存储root节点
        if root==None:#建立一个二叉查询树
            root=node(a)
        else:
            if root.val>a:
                root.left=insert(root.left,a)
                #这里面说明insert(root.left,a)函数跑完就自动析构掉了,
                #他的函数是先拷贝再然后调用函数,所以返回的东西就不是
                #原来的root.left了,要再赋值回去才行.
            if root.val<a:
                root.right=insert(root.right,a)
            if root.val==a:
                pass
        return root
    a=insert(None,3)    
    b=insert(a,2)  
    c=insert(b,4)  
    d=insert(c,5) 
    e=insert(d,4.5) 
    f=insert(e,1)
    print (c)
    def max(root):
               if root.right!=None:
                          return max(root.right)
               if root.right==None:
                          return root.val
    print (max(a))
    
    def min(root):
               if root.left!=None:
                          return min(root.left)
               if root.left==None:
                          return root.val
    print (min(a))     
    View Code

     终于自己写好了:

    class node():
         def __init__(self,a):
             self.val=a
             self.left=None
             self.right=None
    #当函数写起来复杂时候,考虑给函数加变量来细化,
    #类似的想法就是动态规划时候的说不清时候就考虑用更高维的动态规划来刻画
    
    
    
    
    
    
    
    def search(root,point):#返回val=point 的节点的node对象
        if root==None:
            return None
        if root.val==point:
            return root
        
        print (point)
        if root.val>point:
    
             print (root.val)
             print (point)
             return search(root.left,point)
    
        if root.val<point:
    
                
             return search(root.right,point)
    
    
             
    def insert(root,a):#本质就是存储root节点
        if root==None:#建立一个二叉查询树
            root=node(a)
        else:
            if search(root,a)!=None:
                return root
            if root.val>a:
                root.left=insert(root.left,a)
                #这里面说明insert(root.left,a)函数跑完就自动析构掉了,
                #他的函数是先拷贝再然后调用函数,所以返回的东西就不是
                #原来的root.left了,要再赋值回去才行.
            if root.val<a:
                root.right=insert(root.right,a)
            if root.val==a:
                pass
        return root
    a=insert(None,3)    
    b=insert(a,2)  
    c=insert(b,4)  
    d=insert(c,5) 
    e=insert(d,4.5) 
    f=insert(e,1)
    f=insert(f,2.5)
    f=insert(f,3.5)
    print (c)
    def max(root):#返回以root节点为根节点的子树的max
               if root==None:
                   return None
               if root.right!=None:
                          return max(root.right)
               if root.right==None:
                          return root.val
    print (max(a))
    
    def min(root):
               if root==None:
                   return None
               if root.left!=None:
                          return min(root.left)
               if root.left==None:
                          return root.val
    print (min(a))
    
    print (search(a,2))
    def pre(root,point):#返回root这个子树的val=point节点的中序遍历的上一个.
        if search(root,point)==None:
            return None
        else:
         if root.left==None and root.right==None:
            return None
         if min(root.right)==point and root.val<point :
             return root.val
         if root.val==point:
             return max(root.left)
         if point>root.val:
             return pre(root.right,point)
         if point<root.val: 
             return pre(root.left,point)
    def next(root,point):#返回root这个子树的val=point节点的中序遍历的上一个.
        if search(root,point)==None:
            return None
        else:
         if root.left==None and root.right==None:
            return None
         if root.val>point and max(root.left)==point  :
             return root.val
         if root.val==point:
             print (root.val)
             return min(root.right)
         if point>root.val:
             return next(root.right,point)
         if point<root.val: 
             return next(root.left,point)
    
    def dele(root,point):#这个是二叉搜索树里面最复杂的:
        if search(root,point)==None:
            print ('没有的东西删毛')
            raise ValueError
            return None
        #第一种情况:被删除的节点是叶子
        if search(root, point).left==None and search(root, point).right==None:
            
            try :#这里面用try省去了很多废话判断,注意后面要写except:pass
              if search(root,next(root,point)).left.val==point:
                 search(root,next(root,point)).left=None
                 return None
            except:
                pass
            try :
                if search(root,pre(root,point)).right.val==point:
                   search(root,pre(root,point)).right=None
                   return None
            except:
                pass
        #第二种情况是被删除的节点,有左孩子,没有右孩子.
        if search(root, point).left!=None and search(root, point).right==None:
            a=search(root, point)
            aval=a.val
            left=next(root,aval)
            search(root,left).left=a.left
            return 
            #第3种情况是被删除的节点,有you孩子,没有zuo孩子.
        if search(root, point).right!=None and search(root, point).left==None:
            a=search(root, point)
            aval=a.val
            left=pre(root,aval)
            search(root,left).right=a.right
            return
            #第4种情况是被删除的节点,有you孩子,有zuo孩子.
        if search(root, point).right!=None and search(root, point).left!=None:
            a=search(root, point)
            print (a)
            print (77777777)
            aval=a.left
            swappoint=max(aval)
            print (swappoint)
            print (888888888888)
            search(root,swappoint).val,a.val=a.val,search(root,swappoint).val
            print (point)
            dele(a.left,point)
            return 
    
    print (a.left.right.val)
    dele(a,3)
    print (search(a,3))
    dele(a,999)
    View Code

     红黑树:

    具体的理解还不够,特别是删除比较难!

    '''
    算法导论13章:恶心到爆的红黑树.
    1.首先写为什么要使用红黑树:
      1.对于一个高度为h的二叉搜索树,他的增删改查需要时间都是O(h),但是
        二叉搜索树不一定平衡,比如根是5,然后数据是4,3,2,1那么高度h=n,所以O(n)非常慢.
        速度=链表速度.
        原因就是这个二叉树不平衡.
        所以用一个平衡二叉树来做.这里面就是红黑树.
      2.本来以为这东西很偏,后来发现计算几何里面很有用,所以返回来学.
    '''
    '''
    AVL是一种高度平衡的二叉树,所以通常的结果是,维护这种高度平
    衡所付出的代价比从中获得的效率收益还大,故而实际的应用不多,更
    多的地方是用追求局部而不是非常严格整体平衡的红黑树。当然,如果场
    景中对插入删除不频繁,只是对查找特别有要求,AVL还是优于红黑的。
    
    红黑树的应用就很多了,除了上面同学提到的STL,还有著名的linux进程调
    度Completely Fair Scheduler,用红黑树管理进程控制块epoll在内核中的
    实现,用红黑树管理事件块nginx中,用红黑树管理timer等Java的TreeMap
    实现B和B+主要用在文件系统以及数据库中做索引等,比如Mysql:B-Tree In
    dex in MySqltrie 树的一个典型应用是前缀匹配,比如下面这个很常见的场
    景,在我们输入时,搜索引擎会给予提示
    
    作者:夏萌吓懵瞎蒙
    链接:https://www.zhihu.com/question/30527705/answer/52750388
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    所以红黑树非常实用
    '''
    
    '''
    红黑树的哨兵:
    外部结点就是指叶子结点,内部结点就是指非叶子结点
    
    红黑树有一个性质是:叶结点的左右两边必须为黑色。也就是本来
    叶结点如果没有左右孩子直接初始化为NULL就是了,但它居然要黑
    色,意味着我需要新分配两块内存空间啥数据也不保存,tm就是为了
    给它涂上黑色然后挂到叶结点的left、right。当叶结点多起来的时候
    你说多浪费内存空间?理想的二叉树结构是为了让我们保存数据(key
    ),而不是为了保存颜色吧?所以哨兵这个外援就来了,我们申请一块
    内存命名为哨兵,然后把这块内存涂上黑色,之后所有没有孩子的叶结
    点left、right都指向这个已涂上黑色的哨兵。
    
    作者:匿名用户
    链接:https://www.zhihu.com/question/27155932/answer/111548574
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    '''
    #类似2叉搜索树里面的方法search,minimum,maximum,successor,predecessor他们可以
    #自然推广到红黑树上. 然后红黑树特别的是insert和delete.
    class node2():#单独为了给nil做一个node2类,避免类定义的循环
         def __init__(self,a,color='black'):#用默认值来建立对象
             self.val=a
             self.left=None
             self.right=None
             self.color=color
             self.p=None
    
    
    
    class T():#T代表这个tree,这个地方一定要用类进行封装这两个nil和root,
              #不然后面的来回变换就不会自动修改这些东西,利用:类的属性修改是原地址修改这个性质.
              ##!!用这个类的技巧可以实现类似C语言的指针.
         nil=node2(None)  #定义2个类变量,来保存这2个特俗的root和nil
    class node():
         def __init__(self,a,color='black'):#用默认值来建立对象
             self.val=a
             self.left=T.nil
             self.right=T.nil
             self.color=color
             self.p=None
    
    
    #当函数写起来复杂时候,考虑给函数加变量来细化,
    #类似的想法就是动态规划时候的说不清时候就考虑用更高维的动态规划来刻画
    
    
    #来建立一个例子试试:
    
    
    
    #先建立所有节点,再建立所有的连线.一行写多句用分号,多行写一句用/
    ##a1=node(17,'red')
    ##a2=node(41);a3=node(14);a4=node(21),
    ##a5=node(30,'red');a6=node(47);a7=node(10,'red');a8=node(16);
    ##a9=node(19);a10=node(23);a11=node(28);a12=node(38);a13=node(7);
    ##a14=node(12);a15=node(15,'red');a16=node(20,'red');a17=node(35,'red');
    ##a18=node(39,'red');#红黑树里面黑色跟黑色可以相连,黑色和红色不能相连
    ##root.left=a1;root.right=a2;a1.f=a2.f=root
    ##a1.left=a3;a1.right=a4;a2.left=a5!!!!!!实在太慢了,正确方法应该用数组来建立.
    #然后利用二叉搜索树的父节点和儿子节点之间的交表关系直接建立关联,不用手动写.
    
    
    
    
    
    def left_rotate(Tree,x):#再x节点处进行左旋转.
    
        y=x.right
        x.right=y.left
        if y.left!=T.nil:
         y.left.p=x
        y.p=x.p
        
        
        if x.p==T.nil:
       
         T.root=y
         
        elif x==x.p.left:
            x.p.left=y
        else:
            x.p.right=y
        y.left=x
        x.p=y
            
    
    
    
    def right_rotate(Tree,x):#再x节点处进行左旋转.
    
        y=x.left
        x.left=y.right
        if y.right!=T.nil:
         y.right.p=x
        y.p=x.p
    
        
        if x.p==T.nil:
        
         T.root=y
     
        elif x==x.p.left:
            x.p.left=y
        else:
            x.p.right=y
        y.right=x
        x.p=y
    
    
    #上面成功的跑出来了左旋和右旋两个操作.
    #插入
    def rb_insert_fixup(T,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
                        left_rotate(T,z)
                    z.p.color='black'
                    z.p.p.color='red'
                    right_rotate(T,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
                        right_rotate(T,z)
                    z.p.color='black'
                    z.p.p.color='red'
                    left_rotate(T,z.p.p)
         T.root.color='black'
    def insert(T,z):#把节点插入root这个红黑树里面.
                    #函数变量可以是一个类.
         y=T.nil
         x=T.root
         while x!=T.nil:
            
            
            y=x
            if z.val<x.val:
                 x=x.left
            else:
                 x=x.right
         z.p=y
         if y==T.nil:
              T.root=z
         elif z.val<y.val:
              y.left=z
         else:
              y.right=z
         z.left=T.nil
         z.right=T.nil
         z.color='red'
    
         rb_insert_fixup(T,z)
         
    #利用insert建立这个树:
    a=node(2.5)
    T.root=a
    
    T.root.p=T.nil
    T.nil.left=T.nil.right=T.root
    T.nil.p=T.root
    
    
    
    
    
    
    
    
    
    def mid_traverse(T):
         mid_traverse_output=[]
         now_node=T.root
         
         def littel_mid_traverse(now_node):
              print(now_node.val)
              tmp=str(now_node.val)+' '+now_node.color
              if now_node.left!=T.nil:
               littel_mid_traverse(now_node.left)
              mid_traverse_output.append(tmp)
              if now_node.right!=T.nil:
               littel_mid_traverse(now_node.right)
         littel_mid_traverse(now_node)
         
         return mid_traverse_output
    print (mid_traverse(T))
    #为了更清晰的输出红黑树的图形,下面做一个按层输出的函数.
    
    def traverse_by_layer(T):
         output=[]
         now_node=T.root
         listtmp=T.root
         #为了看的清晰只能补满这个2叉树.
         T.nil.left=T.nil.right=T.nil
         oip=[T.nil]
         listtmp=[listtmp]
         while set(listtmp)!=set(oip):
              b=[]
              for i in listtmp:
                tmp=str(i.val)+' '+i.color
                b.append(tmp)
              c=[]
              for i in listtmp:
                   c.append(i.left);c.append(i.right)
              listtmp=c
              output.append(b)
         T.nil.left=T.nil.right=T.root#最后再把树变回去保持代码的正确性.
         return output
    print ('打印红黑树表')
    
    for i in traverse_by_layer(T):
         print (i)
    
    
    
    
    
    '''
    结果:
    打印红黑树表
    ['4 black']
    ['2 black', '5 red']
    ['1 red', '3 red', 'None black', 'None black']
    注意一个node的黑高并不算这个node自己的颜色不算里面.
    所以4的黑高是2,2的黑高是1,5的黑高是1.1的黑高是1,3的黑高是1
    '''
    
    
    
    
    
    
    
    
    
    
    
    
    
    #从结果可以看出来这个2叉树非常满,尽量不出现None值,所以效率最高.
    
    
    #我借鉴了https://blog.csdn.net/napo1987/article/details/37928985
    '''
    他的代码,他实在是狠,最后居然能图形输出2叉树.
    '''
    
    #下面做删除函数.
    def transplant(T,u,v):#把树T里面的u节点开始用v来替换
         print('333333333333333')
         print(u.p.val)
         if u.p == T.nil:
              T.root=v
         elif u==u.p.left:
              u.p.left=v
         else:
              u.p.right=v
         v.p=u.p
    def mini(x):#树中对于x节点构成的子树中最小的val
         while x.left!=T.nil:
           x=x.left
         return x
    black='black'
    red='red'
    def delete_fixup(T,x) :
         while x!=T.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
                     left_rotate(T,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
                       right_rotate(T,w)
                       w=x.p.right
                  w.color=x.p.color
                  x.p.color=black
                  w.right.color=black
                  left_rotate(T,x.p)
                  x=T.root
              if x==x.p.right:
                w=x.p.left
                if w.color==red:
                     w.color=black
                     x.p.color=red
                     right_rotate(T,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
                       left_rotate(T,w)
                       w=x.p.left
                  w.color=x.p.color
                  x.p.color=black
                  w.left.color=black
                  right_rotate(T,x.p)
                  x=T.root
         x.color=black
    def delete(T, z):  
       y = z  
       y_original_color = y.color  
       if z.left == T.nil:  
           x = z.right  
           transplant(T,z,z.right)  
       elif z.right == T.nil:  
           x = z.left  
           transplant(T,z,z.left)  
       else:  
           y = mini(z.right)  
           y_original_color = y.color  
           x = y.right  
           if y.p == z:  
               x.p = y  
           else:  
               transplant(T,y,y.right)  
               y.right = z.right  
               y.right.p = y  
           transplant(T,z, y)  
           y.left = z.left  
           y.left.p = y  
           y.color = z.color  
       if y_original_color == 'black':  
           delete_fixup(T,x)  
    
    
    
    
    
    
    
    print ('ceshi')
    
    
    insert(T,node(4))
    
    insert(T,node(3))
    
    insert(T,node(2))
    
    
    insert(T,node(1))
    
    insert(T,node(6))
    insert(T,node(8))
    insert(T,node(66))
    print('删除之前的图')
    for i in traverse_by_layer(T):
         print (i)
    
    
    delete(T,T.root)
    
    
    print('打印删除后的图')
    
    for i in traverse_by_layer(T):
         print (i)
    View Code
  • 相关阅读:
    md测试
    安利好用的小工具及软件(常更新)
    08-无人值守自动批量安装系统(下)
    建立本地yum仓库
    如何知道命令是由哪个服务提供的
    08-无人值守自动批量安装系统(上)
    07-软件管理
    06-时间管理
    05-用户和组以及权限
    04-编辑文本
  • 原文地址:https://www.cnblogs.com/zhangbo2008/p/8548208.html
Copyright © 2011-2022 走看看