二叉搜索树,和红黑树,
二叉搜索树
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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))
终于自己写好了:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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)
红黑树:
具体的理解还不够,特别是删除比较难!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
''' 算法导论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)