数据结构与算法小结(2)

来源:互联网 发布:windows同步软件 编辑:程序博客网 时间:2024/06/03 21:31

一、二叉搜索树

1.BST试图解决的问题:

高效的兼顾静态的查找和动态的增删。在基本的数据结构中    数组通过寻秩可实现高效的查找,但增删效率低;    向量通过寻位置访问,增删高效,但查找低效,而且因为增删前通常都需要先找到对应的元素,这使得其效果更差。改进思路是改变访问方式,使用寻关键码访问。引入关键码,将数据项与其关键码绑定,统一的表示为词条的形式,根据关键码来访问元素,用数据项保存元素。关键码需支持比较器和判等器。

2.BST的特性

顺序性:任一节点均不小于/不大于其左/右后代单调性:BST的中序遍历序列必然单调非降。BST的充要条件BST中,根节点中序遍历的后继为右子树中最小的节点

3.BST的接口实现

查找:类似二分查找,最后得到匹配节点(无匹配项时为空的哨兵节点)以及其父节点_hot。插入:查找,无雷同元素则将待插入节点作为找到的_hot节点的子节点插入。删除:先查找,找到的节点只有一个子树时,直接删除,用其子树替换;若有两个子树,找到该节点的后继(比该节点大的最小的节点,该点必定只有一个子树),先交换这两个点,再删除需删除的节点。

这里写图片描述

删除的算法实现:Template <typename T> static BinNodePosi(T)removeAt( BinNodePosi(T) & x,BinNodePosi(T) & hot ){    BinNodePosi(T) w = x;               //实际被摘除的节点,初值同x    BinNodePost(T) succ = NULL;         //实际被删除节点的接替者    if(!hasLChild(*x)){        succ = x = x->rChild;           //情形一:待删除节点没有左孩子,直接以右孩子接替(右孩子可为空)。    }else if(!hasChild(*x)){        succ = x = x->lChild;           //这段代码不会走到,没有孩子时,肯定没有左孩子,会走情形一    }else{                              //情形二:待删除节点有左右孩子        w = w->succ();                  //先找到在中序遍历中,待删除节点的后继(即比待删节点大的最小节点)        swap(x->data,w->data);          //交换待删节点与其后继的值        BinNodePosi(T) u = w->parent;   //找后继是先找右孩子,然后沿左侧链到底,所以此处有此判断。需注意的是,左侧链到底,所以其必定没有左孩子,可能由右孩子        (u == x ? u->rChild :u->lChild) = succ = w->rChild;         }    hot = w->parent;    if(succ){        //若之前找到的后继有右孩子        succ->parent = hot;  //因为其一定没有左孩子,所以可以通情形一处理。    }    release(w->data);    release(w);    return succ;}

4.适度平衡

理想平衡:叶节点只能出现在最底部的两层,即完全树甚至满树。适度平衡:高度渐进地不超过o(logn),即可称作适度平衡。即平衡二叉搜索树BBST。    对于每个节点,其子节点数为偶数,即要么没有子节点,要么有两个子节点。等价BST:上下可变(父子关系可颠倒),左右不乱(中序遍历序列不变,全局保持单调非降)。    等价变换、旋转调整。zig顺时针,zag逆时针

适度平衡的例子之AVL树:

AVL树:所有节点左右子树的高度只差不大于1。    高度为h的AVL树,至少包含S(h) = fib(h + 3) - 1个节点。    由n的节点构成的AVL树,高度至多为o(logn)AVL实现:    每个节点需维护一个平衡因子,其值为左子树树高减去右子树树高,每次增删节点时,都需向上冒泡计算。所以,每个节点还需维护一个记录其树高的成员变量。    插入:若要失衡,共有四种情况,因对称的重复,可分两种情况讨论        1.左(右)侧链,此时单旋即可使子树高度复原        2.Z字链,此时双旋也可使子树高度复原        当子树高度复原时,其更高的祖先也必定平衡。    删除:同插入一样,也可以分为两种情况讨论,但不同的是,删除后经过单旋或双旋,原树高度不一定会复原,更高祖先仍可能失衡,这就是失衡传播现象,最坏需要做o(logn)次调整。    双旋:        zigzig都在左侧,顺时针旋转        zagzag都在右侧,逆时针旋转        zigzag 右、左,双旋,之字形排列        zagzig 左、右    双旋实现:将三个节点(a,b,c)、四颗子树(A,B,C,D)看做单个元素做中序遍历,传入7个参数,最后返回一颗子树,该子树以b为根,左右孩子分别为a、c,a的孩子为A、B,c的孩子为C、D。此时树高最小。    双旋实现的启发:理论分析时使用的是形象的工具,实际操作时,往往有更暴力、性能更优的解,当然,这些解需要对理论的工具有更深的理解才能想到。

二、高级搜索树

1.伸展树:

伸展树期望解决的问题:

更快的访问。它依赖于这样一个现象:刚被访问过的数据,很有可能会很快的被再次访问;下一个访问的数据极有可能在刚访问的数据附近。这就是数据访问的局部性。伸展树的策略:    节点一旦被访问,随即调整至树根。自下而上,逐层单旋,直到被推到树根。
0 0
原创粉丝点击