首 页 网络编程
网页制作 图形图象 操作系统 冲浪宝典
软件教学 认证考试

网络安全 网络办公 行业资讯 评测对比
您当前位置:站长天空 -> 认证考试-> 微软认证
07 AVL 树-.NET教程,评论及其它
作者:网友供稿 点击:23
推荐
西部数码-全国虚拟主机10强!20余项虚拟主机管理功能,全国领先!第6代双线路虚拟主机,南北访问畅通无阻!可在线rar解压,自动数据恢复设置虚拟目录等.免费赠送访问统计,企业邮局.Cn域名注册10元/年,自助建站480元起,免费试用7天,满意再付款!P4主机租用799元/月.月付免压金
站内搜索
文章页数:[1] 

用二叉树的遍历来消除递归。

   前面说了模拟系统函数调用的方法消除递归,现在再说说利用遍历消除递归的方法。

   先看两个递归函数。

   void mergesort(int [] array,int left,int right){

      if(right<=left) return;

      int mid=(left+right)/2;

mergesort(array,left,mid);

mergesort(array,mid+1,right);

merge(array,left,mid,mid+1,right);

}

   void quicksort(int[] array,int left,int right){

if(right<=left) return;

选择枢轴,把它放到正确的位置,并把比它小的放到它的左边,比它大的放到右边;

quicksort(左边的数组);

quicksort(右边的数组);

   }

   这两个递归函数都调用自身两次。这和二叉树的遍历有什么关系呢?

   两次递归把整个代码分成三部分。比如:归并排序。

   part1       int mid=(left+right)/2;

   递归调用1  mergesort(array,left,mid);

   part2      

   递归调用2  mergesort(array,mid+1,right);

   part3       merge(array,left,mid,mid+1,right);

   函数的执行过程是:进入part1(当前节点),进入递归调用1(左孩子),part2(当前节点),进入递归调用2(右孩子),进入part3(当前节点)。

   哦,有点遍历的意思了,但遍历是每个节点访问一次,你都访问3次了!part2是空,就算少一次,还有part1part3呀!先我们不看part1,那么就是一个后序的遍历。

   quicksort比较简单part2part3本来就是空的,所以它是个先序的遍历。

   现在我们来看看为什么mergesort对应一个后续遍历?即为什么part1可以不理睬?

   mergesort的目的就是把输入――array[left….right]中的数从小到大排序并放到array[left…right]中。我们要处理的数据是array数组,而part1int mid=(left+right)/2;array是没有关系的。

 

 

 

 

 

avl

一般书讲avl树,一上来就是插入节点有两种情况(对称又两种),怎么旋转使它平衡;删除又有四种情况,怎么旋转使它平衡。却没有说明为什么插入有两种不平衡的情况?为什么没有34种?

先看插入节点。

首先当然是用bst的插入算法找到插入的位置。另外从根到插入节点路径上所有的节点(即插入节点的祖先们)都可能被用到,所以在查找的过程中要把他们都保存下来。

从被插入节点一直向上走,因为原来的树是平衡的(注意,这里说的平衡是只满足avl性质,即左右子树的高度之差的绝对值不超过1,而不是说树是最优平衡的),所以它遇到的节点的平衡因子只能是0,+1-1。如果遇到的是0,则插入一个节点后它的平衡因子就会变成-1+1,但树的高度加1,所以还要继续向上走。如果遇到的是+1-1,那么可能变成0,+2-2。如果变成0了,那么树还是平衡的,并且树的高度不再增加,所以不用再向走上了。如果变成2,则出现第一个不平衡的节点。

既然不平衡了,那么我们就想办法使它平衡。注意,除了使它平衡外,最好它的高度还不变,这样我们就不用向上走了。

总结一下:我们从被插入节点一直向上走,遇到0就把它变成+1-1(左上是+1,右上是-1),并继续向上走;遇到+1-1则分两种情况:一是变成0,一是变成+2-2。但不管哪种情况都不用再向上走了(变成0树高肯定不变,变成+2-2我们假设在使它平衡的同时还不增加树高,后面我们会发现只是可行的)。

假设向上第一个不平衡的节点(即平衡因子由+1-1变成+2-2的节点)为p,由于对称性我们假设它由+1变成+2。(万一没有节点从+1-1变成+2-2呢?那么有两种情况:有节点从+1-1变成0;一直到了根了。无论哪种情况树都已经平衡了。)

则原来的树一定是下面的形状。图上用括号括起来的是节点的平衡因子。

     p(+1)

    /  \

  (h)   q(0)

       /  \

     (h)  (h)

为什么q的平衡因子是0?因为根据前面的分析,从被插入节点一直向上p是第一个平衡因子是+1-1,其余的都是0

因此插入后又有两种情况:q的左子树变成高为h+1;q的右子树变成高为h+1

我们来分别讨论。

先讨论右子树增高的情况(先看简单的)。插入后的树变成下图的形状。

     p(+2)

    /  \

  (h)   q(+1)

       /  \

     (h)  (h+1)

树不平衡了!哪不平衡?p的右子树q(的右子树)太高了!所以要把它弄上去。当然不能随便弄上去,要保持bst树的性质。这就是所谓的rr旋转。旋转的结果是:

     q(0)

    /   \

  p(0)  (h+1)

  /  \

(h)   (h)

结果很好,比原来还平衡,而且树的高度不变(旋转前后都是h+2)。

再来看左子树增高的情况,如下图。

     p(+2)

    /  \

  (h)   q(-1)

       /  \

    (h+1)  (h)

如果我们还是依葫芦画瓢把q弄上去的话,则会变成下面的树:

     q(-2)

    /   \

  p(+1)  (h)

  /  \

(h)   (h+1)

还是不平衡!因为这次不平衡的元凶不是q的右子树而是左子树,因此我们要把q的左子树的根弄上去。

q的左子树也画出来的树如下:

     p(+2)

    /  \

  (h)   q(-1)

       /   \

     r(+1)  (h)

    /    \

  (h-1)   (h)

注意r-1的情况与+1是一样的;r不能为0,为什么?(因为原来r0,在向上走的过程中被变成了+1-1)。

我们先把r弄上去:

     p(+2)

    /  \

  (h)   r(+2)

       /   \

     (h-1)  q(0)

          /    \

        (h)     (h)

r又太高了,再把它也弄上去:

           r(0)

         /       \

       p(-1)     q(0)

       /   \     /    \

      (h)  (h-1) (h)   (h)

这下总算平衡了,而且经过两次旋转后,树的高度不变,还是h+2

这就是所谓的rl旋转。

除此之外还有对称的lllr旋转。

 

 

 

接着来看avl树删除节点的方法。

在这之前先来复习一下bst删除节点的算法。

分三种情况:删除叶子;被删除的节点有一个孩子;被删除的节点有两个孩子。

删除叶子最简单,直接把它的父亲节点的指针置成空就可以了。如下图:

         15                   15

        /  \    删除16       /   \

       4   20  -------->      4    20

      /    /                /  

     1   16               1

删除只有一个孩子的节点也不难,把它的父亲指向它的孩子就可以了。

         15                   15

        /  \    删除20       /   \

       4   20  -------->      4    16

      /    /                /  

     1   16               1

 

删除有两个孩子的节点有点麻烦。有两种方法――归并删除法和拷贝删除法。

归并删除的思路是:先安排被删除节点的左孩子,这和只有一个孩子的节点的删除是一样的;然后把被删除节点的右孩子插入到合适的位置(也就是被删除节点左子树的最右节点)。

        15                      10

      /     \      删除15       /  \

    10      30    --------->      5   11

   /  \     /   \                     \

  5   11  20   40                    12

        \                               \

         12                            30

                                       /  \

                                      20  40

上面的例子说明删除一个节点可能使得树的高度反而变高了。

拷贝删除的思路是:在被删除节点的左子树(或右子树)找到最大也即最右的节点(或最小的节点),左子树最右的节点最多只有一个孩子。把删除有两个孩子的节点转变成删除最多一个孩子的节点。然后把这个节点拷贝到真正被删除的节点里。

        15                        12

      /     \      删除15        /    \

    10      30    --------->     10      30

   /  \     /   \              /  \     /  \

  5   11  20   40           5   11  20   40

        \                            

         12                          

它的好处是树的高度不会增加。而且,真正被删除的节点为根的子树的高度是一定减少的。因为如果删除的是叶子,那么原来高度是1,现在变成0了;如果删除的是只有一个孩子的节点,那么它的子树替代了被删除的节点,也使树的高度少1

avl树的删除中我们会用第二种方法,因为我们不希望在删除节点和树反而变高了。

我们还使按照与插入类似的分析方法。

找到第一个真正被删除的节点(叶子或一个孩子的节点),删除这个节点后这个节点的子树还是平衡的(叶子的子树是空树,一个孩子的节点它的孩子原来就是平衡的)。但删除节点后,以它为根的子树高度减一,这可能导致它的父亲不平衡。

因此我们沿着这个被删除的节点一直向上走。遇到的节点不外乎0,+1-1三种。

如果遇到了0,则把它变成+1-1(向右向上是+1向左向上是-1),树依然平衡,由于这时树的高度不会减少,所以不用再向上走了。

如果遇到了+1-1,又有两种情况:变成0;变成+2-2

如果变成0的话树仍然是平衡的,但树的高度少一,所以还要往上走。

变成+2-2的话树就不平衡了,需要我们通过旋转使之平衡。但平衡的同时能不能保证树的高度不减少呢(这样就不用向上走了)?通过分析我们将会发现有时树的高度会减少的。

由于对称性,我们假设某个节点p+1变成了+2,原因是左子树变矮了。那么p的右孩子q的平衡因子有3种情况(0,+1-1)。

1q的平衡因子为1的如下图:

         p(+1)                    p(+2)                     q(0)

        /    \                    /    \                     /   \

      (h)    q(+1)              (h-1)   q(+1)               p(0)  (h)

            /   \                      /   \               /   \

          (h-1)  (h)                  (h-1)  (h)           (h-1)  (h-1)

      原来的情况                左子树变矮后            q转上去后

通过旋转,树变平衡了,但新树的高度减少了,因此还有继续往上走。

2q的平衡因子为0的情况如下图:

         p(+1)                    p(+2)                     q(-1)

        /    \                    /    \                     /   \

      (h)    q(0)              (h-1)    q(0)               p(+1)  (h)

            /   \                      /   \               /   \

          (h)    (h)                  (h)   (h)           (h-1)  (h)

      原来的情况                左子树变矮后            q转上去后

通过旋转,树平衡了,而且新树的高度不变,不用再向上走了。

3q的平衡因子为-1的情况。

   如果我们还是把q转上去的话,依然是不平衡的,如下图:

         p(+1)                    p(+2)                     q(-2)

        /    \                    /    \                     /   \

      (h)    q(-1)              (h-1)    q(-1)               p(+1)  (h-1)

            /   \                      /   \               /   \

          (h)    (h-1)                (h)   (h-1)          (h-1)  (h)

      原来的情况                左子树变矮后            q转上去后

   原因和插入的rl旋转有些类似,因为q的左子树太高了,所以我们先要把q的左子树r转上来(q下去),然后r再转上去(p下去)。但r的平衡因子可能有三种情况,这会不会影响其它的节点呢?我们分三种情况讨论。

   3.1  r的平衡因子是-1

   如下图:

   p(+1)             p(+2)             p(+2)                   r(0)      

  /     \            /    \             /   \                  /    \      

 (h)    q(-1)      (h-1)   q(-1)       (h-1)  r(+1)          p(0)     q(+1)     

       /   \             /    \            /   \           /  \      /   \

     r(-1)  (h-1)       r(-1)  (h-1)      (h-1)  q(+1)    (h-1) (h-1)  (h-2) (h-1)

     /   \             /   \                  /   \

   (h-1)  (h-2)       (h-1)  (h-2)            (h-2)   (h-1)

  原来的情况        左子树变矮后     r转到q上面后   r转到p上面后

通过两次旋转,树变得平衡了,但树的高度减少。

 

3.2  r的平衡因子是+1

   p(+1)             p(+2)             p(+2)                   r(0)      

  /     \            /    \             /   \                  /    \      

 (h)    q(-1)      (h-1)   q(-1)       (h-1)  r(+2)          p(-1)     q(0)     

       /   \             /    \            /   \           /  \      /   \

     r(+1)  (h-1)       r(+1)  (h-1)      (h-2)  q(0)     (h-1) (h-2)  (h-1) (h-1)

     /   \             /   \                  /   \

   (h-2)  (h-1)       (h-2)  (h-1)            (h-1)   (h-1)

  原来的情况        左子树变矮后     r转到q上面后   r转到p上面后

通过两次旋转,树变得平衡了,但树的高度减少。

 

3.3  r的平衡因子是0

   p(+1)             p(+2)             p(+2)                   r(0)      

  /     \            /    \             /   \                  /    \      

 (h)    q(-1)      (h-1)   q(-1)       (h-1)  r(+1)          p(0)     q(0)     

       /   \             /    \            /   \           /  \      /   \

     r(0)  (h-1)       r(0)  (h-1)      (h-1)  q(0)      (h-1)  (h-1) (h-1)  (h-1)

     /   \             /   \                  /   \

   (h-1)  (h-1)       (h-1)  (h-1)            (h-1)  (h-1)

  原来的情况        左子树变矮后     r转到q上面后   r转到p上面后

通过两次旋转,树变得平衡了,但树的高度减少。

 

从上面的图中可以看出r的平衡因子是什么没有关系,只要把r两次转上去就可以了。

总结一下删除的过程:找到真正被删除的节点,然后从它一直向上走。

如果遇到了0,则把它变成+1-1(向右向上是+1向左向上是-1),且不用再向上走了。

如果遇到了+1-1并且把它变成了0(向左遇到+1,向右遇到-1),继续向上走。

如果遇到了+1-1并且把它(设为p)变成了+2-2(向右遇到+1,向左遇到-1),则分三种情况(我们只讨论了+1,-1类似)。a)p的孩子q+1,把q转上去,继续往上走;b)p的孩子q0,把q转上去,不用上走了;c)p的孩子q-1,把q的孩子r两次转上去,继续往上走。


文章整理:站长天空 网址:http://www.z6688.com/
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

文章页数:[1] 


放大字体显示 缩小字体显示 打印文章 推荐给朋友
热门文章
·学习java需要知道的一些问题-JSP教程,Java技巧及代码
·vs.net中web services入门-.NET教程,Web Service开发
·C#中Base64之编码,解码方法-.NET教程,C#语言
·关于程序加载错误的处理-ASP教程,ASP应用
·.Net应用程序发布问题的最新解决方案,感觉比较爽(可桌面、程序中加自己的ICO及卸载等)-.NET教程,评论及其它
·设计模式-简单工厂模式(SimpleFactory-C#)-.NET教程,C#语言
·用photoshop制作logo-网页设计,Photoshop
·用jsp实现直接下载文件而不是在浏览器中打开的功能-JSP教程,Jsp/Servlet
·利用数据集实现对数据库的操作-.NET教程,数据库应用
·JAVA与数据库连接方法(二)-JSP教程,数据库相关
最新文章
·当windows vista系统提示“内存不足”怎么办?_windows vista
·王通:个人如何利用网络赚钱(1)_网赚技巧
·关于flash中注册点与中心点的区别_flash教程
·个人网站发展初期如何节省资金_站长心得
·如何写好“帮助中心”的内容_站长心得
·中国个人网站——新经济中的非主流2_站长心得
·backpack - 体验可读写的web服务_站长心得
·中文搜索引擎的研究_站长心得
·域名选取十技巧_站长心得
·用javascript 转换外部链接样式_javascript教程
相关主题
西部数码虚拟主机

友情链接
CNNIC 西部数码
万网 自助建站
虚拟主机 asp空间
域名注册 域名
域名申请 主页空间
论坛空间 网站空间
国际域名 虚拟空间
空间租用 DDOS防火墙
成都主机托管 四川主机托管
主机租用 服务器租用
网站目录 自助建站
虚拟主机 网址大全
软件下载
自助链接
虚拟主机资讯 特价虚拟主机
<
版权申明:本站文章均来自网络,如有侵权,请联系我们,我们收到后立即删除,谢谢!
关于我们:站长天空:专业提供最新的站长资讯、在线教程、虚拟主机权威评测、虚拟主机性能对比、网站制作教程,开发教程,站长工具。包括网页制作教程、冲浪宝典、编程参考、操作系统、软件教学、行业动态等。
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。
发表评论 打印  刷新     关闭