c++二叉查找树,AVL树,红黑树,treap,splay树及笛卡尔树整理

在数据结构中,树的种类不计其数,百度百科上就有50多种,

因此就把最近看的一些二叉查找树的特性和用途整理一下:

二叉查找数的基本操作:插入insert,删除delete,查找search,遍历iterator,从某个节点开始的最大值minMum,某个节点开始的最小值maxMum

为了保证查找的效率,人们提出让树尽量平衡的思想,也就是二叉平衡树,通过尽量控制树的高度来缩小查找的复杂度。因此就提出了一系列,平衡树及类平衡树的数据结构,下面简单介绍一下

说道树的平衡就必须得提到树的旋转,这是让树趋向平衡的关键。

AVL树:这是比较基础的平衡树,教材都会提到,每个节点都有以下属性 :平衡因子bl,左右孩子l、r,父节点p,节点的高度h,并满足各个子树的平衡因子的绝对值不大于1.

      当进行插入操作时,先找到插入位置判断父节点的平衡性,设置其深度,如果父节点平衡因子=-2或2,则进行旋转,更新节点的平衡因子和高度。具体旋转有四种情况,及左旋,右旋

      和左右旋及右左旋。将当前节点跳到父节点继续进行判断,直到当前节点为根节点。

      删除操作,有多种方式,1、懒删除,标记节点不可用。2,如果为叶子节点,直接删除,如果只有左孩子或者右孩子,直接上移,否则用后继节点代替,然后向上进行旋转调整,3如果为

      叶子节点,直接删除,如果只有左孩子或者右孩子,直接上移结束旋转,否则将节点向下旋转(向平衡因子高的一端旋转),直至不同时存在左右孩子,然后从该节点的父节点向上调整

可以看出AVL树中树是高度平衡的,插入删除都在logn时间完成,但是插入和删除过程依旧比较繁琐。

红黑树:这是一种近视平衡的数,其主要由以下性质:1.节点要么是红的,要么是黑的 2.根节点是黑的 3.根节点的父节点和叶子节点的孩子节点指向黑的NIL节点 4.红节点后不能接红节点          5.从任意一个子树的跟节点出发,到其任意叶子节点的路径上的黑节点数(黑高度)是相等的。   属性:颜色c,左右孩子lr,父节点p,健key。

      其近视与平衡的原因 是因为 树的高度 有根节点处的树高度为 最长红高度(rh)和黑高度(bh)之和,显而易见 有性质4可以推断出 最长红高度rh<bh,因此树的高度<2bh。

      由性质5可知,以x为根的树的黑高度 bh(x)满足条件 :n(x) >= 2^bh(x)-1,n(x)为以x为根的子树的节点树,根据归纳法,当x的高度为0,时满足要求,以x为根的左右子树

      黑高度为bh(x) 或bh(x)-1 取决于x的颜色,因此x的子树的内节点至少在(2^(bh(x)-1)-1),所以 其 父节点 至少包含(2^(bh(x)-1)-1)*2+1个节点;因此bh(x)<log(n+1).

      因此树的高度 小于 2log(n+1),近似于平衡。

      

      相比于AVL树,红黑树的插入操作就要简单的多了,有节点插入时,当插入节点在左节点上时,设置该节点颜色为红,如果父节为黑,不破坏任何性质,当父节点为红时,破坏性质4,需要进行调整,此时只要考虑6种情况,其中针对左右子树的各三种,所以只要考虑三种情况,具体当当前插入节点的父节点为左孩子时三种情况: 

       1.叔叔为红,则让叔叔和父亲都变为黑,将祖父变为红,将当期节点跳到祖父

       2.叔叔为黑,当前节点为右孩子,从父节点进行一次左旋进入3

       3.叔叔为黑,当前节点为左孩子,从祖父节点进行一次右旋,完成调整。

      显而易见红黑树的调整最多需要旋转两次,以及logn次操作1,

      

      红黑树的删除操作同样简单,如果删除的当前节点是叶子节点,直接删除,如果是只有一个孩子,直接将孩子上移,如果有两孩子,直接找后继节点删除,并将后继节点的属性(除了颜色属性)赋给当前节点,在删除节点时,如果该节点为红,不影响性质,直接删除,因此被删除的节点总是叶子节点或者单亲节点。如果该节点为黑节点,破坏了性质5,该路径上的黑高度少了1.如果被删除节点为根节点,则直接让其孩子(有的话)变成根节点,颜色调整为黑,不是根节点的话则要针删除节点的孩子节点对以下左右对称各四种情况进行调整:目前只考虑父节点为左孩子的情况:当当前节点颜色为红时,结束调整 并将该节点最后设为黑色

       1.兄弟为红,对父节点做一次左旋

       2.兄弟为黑,兄弟的双孩子都为黑,将兄弟变为红,该节点跳到父节点

       3.兄弟为红,兄弟的左孩子为红,右孩子为黑,对兄弟节点进行一次右旋

       4.兄弟为红,右孩子为红,对父亲节点做一次左旋,完成调整

splay树:也称为伸展树,在每次操作对节点的操作时都进行一次splay(x)操作,将x节点调整至根节点,因此操作次数越多就越靠近根节点,因此其类似于huffman,其调整操作有6种:

       1.zag 和左旋一致 2.zig 和右旋一致 3.zig-zig 先对祖父进行zig再对父节点做zig 4 zag-zag  先对祖父进行zag再对父节点做zag

       5 zig-zag  先对父进行zig再对父节点做zag  6 zag-zig  先对父进行zag再对父节点做zig


treap:也称为树堆,其主要是为了尽量让树保持平衡,构造伪平衡树,对每个节点增加了一个val值,在进行插入操作时,该值是随机生成的在维持二叉查找树的前提下,保证,对val值满足堆        的性质。插入操作是找到插入点后,向上进行堆调整,时间复杂度为logn,

       删除操作时,是对节点进行选择,每次与val值大的一半进行旋转直至其为叶子节点或者单亲节点。然后删除


笛卡尔树:其性质与treap完全一致,但是其val值是固定的,主要应用于范围top k查询,其构造方法如下:

      1.先将元素按key排序,然后依次插入构造,由于key值递增,故key插入位置在树的最右端,最右端的路径上找到A[i]使得 A[i].val> value 而且A[i].right.val<value,然后让A[i].right = newNode,newNode.left=A[i].right,所以平均复杂度o(n^2) (这个方法好屎,网上说的乱七八糟的)

           2.排序后左旋的方法:先排序,使用treap插入,但由于key排序了,所以都是左旋,时间复杂度O(N^2)

           3.类似于1,先将key排序,依次插入,从跟到所有右节点构成右链,用栈存储,如果新的插入点newNodeval最大直接插入,并插入栈,如果不是,依次出栈直至newNode.val处于栈顶A和已出栈元素B之间,让A.right=newNode newNode.left=B,将newNode入栈


    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/earthma/article/details/45322049
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞