《树型软件工程方法》之系列博文4

       底2分化查找程序的作业树

 

               

 

  

 

                        TREESOFT

 

目  录

4 底2分化查找程序的作业树. 1

4.1 问题需求.... 1

4.2 算法设计.... 1

4.2.1 整数的底2分化.... 1

4.2.2 查找算法.... 2

4.3 作业树.... 3

4.3 遍历编程.... 5

4.4 结束语.... 6

中国人为什么不可以有自己的软件工程方法及其开发工具平台!

这是介绍《树型软件工程方法》的系列博文,请按文章标题所带的编号顺序阅读,否则你会看不懂本文。

 

4 底2分化查找程序的作业树

在有序序列中查找一个已知元素的方法有多种,此前介绍过“常用二分查找”,还有“斐波拉契查找”。本文将介绍另一种查找方法,称为“底2分化查找”。底2分化查找不但具有最优的查找性能,而且算优美而富于艺术。本文将详细介绍该算法,并以作业树来表示之,以进一步实践作业树的设计方法。作业树的相关概念,仍请参看博文“冒泡排序程序的结构化设计”。

4.1 问题需求

已知有序元素序列V=[v(1), v(2), …, v(n)],该序列中的元素以升序排列,即总有:

v(j)<v(j+1)。

现在有已知元素u,要求在V中找出u,或告知u不在V中。

4.2 算法设计

4.2.1 整数的底2分化

我们知道,对于任意一个正整数N,总可以用二进制表示如下:

这里m=1+(㏒2(N))的整数部,xi的确定是同N有关的。辟如N=10=23+21=(1010)2则m=1+(㏒2(10))的整数部=1+3=4。现在,我们来将N表示成所谓“底2分划”的形式。

    在N的二进制表示中,凡xi为0的位都向高位借取一半的数,这样形成的和式就是N的底2分划形式。

z=i-(xi-1)的非,yi=2z

上式就是N的底2分划形式,这里恒有yi+1≥yi≥1。式“z=i-(xi-1)的非”体现了“凡xi为0的位都向高位借取一半的数”这句话:如果xi-1=0,说明N的二进制表达式中的第i-1项为0,需向第i项借取一半的数,0取非等于1,z=i-(xi-1)的非=i-1就实现了借位;如果xi-1=1,说明N的二进制表达式中的第i-1项为1,无需向第i项借位,1取非等于0,z=i-(xi-1)的非=i-0=i就实现了不借位。例如N=10=23+21=22+22+20+20就是正整数10的底2分化式。

与N的二进制表示相比,N的底2分化中各项都不为0。式中的yi都是2的整数次幂,视其为yi个节点,则可生成一棵如图4.1所示(含23个节点)的二叉树。因为该二叉树根节点的左边总是一棵完全二叉树,根节点的右边为空,故称之为左满右空二叉树,简称左满树。将所有属于N的m棵左满树的根节点连接后,就得到含N个节点的二叉树,称之为N的底2分化树,简称底2树。如图4.2就是一棵含10个节点的底2树。可以证明,底2树是一类平衡二叉树。

                              

图4.1 含23个节点的左满树                           图4.2 含22+22+20+20个节点的底2树

将N的底2树的节点按其投影顺序编号,或说按自下而上,先左后根再右,子树递归地遍历底2树。则含有10个节点的底2树的节点编号为:1,2,3,4,5,6,7,8,9,10,如图4.2所示。令每个节点对应于有序序列V中相同序号的元素,则对已知元素u的查找就可以在底2树中进行。我们知道,N个节点的二叉树至少有m层,最多有N层(一条线性链)。平衡二叉树是只有m层的二叉树,具有最短的平均路径。底2树是平衡二叉树,以底2树为查找模型就具有最短的平均查找路径,意味着查找的时间复杂度最优。

4.2.2 查找算法

底2分化查找实际类似于二分查找,也是以近似拆半的步长向左或向右前进,只不过底2分化查找的步长总是2的整数次幂。由于底2树中的节点都对应着V中相同序号的元素,所以v(j)既是V的元素,也是树的节点。一开始,查找总是沿底2树的根节点链(如图4.2中的蓝色节点链)自上而下进行。一旦有u<v(j),查找就会进入以v(j)为根的左满树,直至得出结果:成功找到或告知u不在V中。现在我们来设计底2分化查找算法,首先要确定查找过程中前进或后退的步长。

先确定查找沿左满树根节点链(简称根链)前进的步长,这类步长总等于相应左满树的节点数,也就是底2分化表达式中的ym-i项。我们不打算预先生成N的底2分化式,而是在前一步查找步长的基础上生成本步的查找步长。

令d为查找步长,其总等于2的整数次幂,且以二进制表示。显然,d的初值为d=(2m-1)2=(xm-1000…00)2=(100…0)2。令c为一位的二进制变量,每当N的二进制串X左移一位时,被移出的数(0或1)就进入c。令di表示第i次的查找步长,则根链上的di=ym-i;令ci表示第i次左移X后c的值,则ci=xm-i。根据N的底2分化的定义,在di的基础上决定di+1=ym-i-1需要分两步进行:

(1) 求取ym-i-1的最大值

由底2分化的定义可知,ym-i的值有两种可能:ym-i=2m-i或ym-i=2m-i-1,称前者为最大值,后者为借后值。由于di=ym-i,ci+1=xm-i-1

1.1) 如果ci+1=1,说明ym-i-1并未向ym-i借位,di是ym-i的最大值,应有di=ym-i=2m-i。此时,将di右移一位就得到了ym-i-1的最大值,相当于做“将di右移ci+1位”即得到了ym-i-1的最大值。

1.2) 如果ci+1=0,说明ym-i-1已从ym-i借位,di是ym-i的借后值,应有di=ym-i=2m-i-1。此时的di就等于ym-i=1的最大值,做“将di右移ci+1位”并不改变di的值。

(2) 确定ym-i-1的真实值,以求得di+1= ym-i-1

执行完步骤1后的d是ym-i=1的最大值,它还不一定就是真实的ym-i-1,还要看xm-i-2的值。先做“左移X一位入c”,这个c相当ci+2=xm-i-2

2.1) 如果ci+2=1,说明ym-i=2不必向ym-i=1借位,当前的d就是真实的ym-i=1,亦即第i+1步的查找步长。执行“将d右移c非位”后并未改变d的值。

2.2) 如果ci+2=0,说明ym-i=2要向ym-i=1借位,执行“将d右移c非位”后,就得到了真实的ym-i=1,亦即第i+1步的查找步长。

我们看到,上述算法中的c与d不同步,当判断di的时候,用到的是ci+1与ci+2。为此,我们事先将X串循环左移一位,然后再做“左移X一位入c”就可以解决这个问题。显然c的初值c1=xm-2,正好用来判断ym-1是否被借位。顺便指出,上述算法中c与d的下标是为了叙述的方便,程序中并不需要。

上面的算法是为了求得查找沿根链前进的步长,一旦有u<v(j),查找就会进入以v(j)为根的左满树。而在左满树中查找步长的求解算式是固定的,第i+1步的步长总等于第i步步长的一半,即只要做“将d右移一位”即可。

设f为标志变量,f=0说明查找沿根链前进,f=1说明查找已进入某左满树。j指向V的元素v(j)变量w=“y”标志查找成功,w=“n”标志查找失败。

[底2分化查找算法]

(1) 输入N和u。m=1+(㏒2(N))的整数部,X=(N)2=(xm-1xm-2…x1x0)2,d=(2m-1)2=(xm-1000…00)2=(1000…00)2,f=0,w=“n”。X=(将X循环左移一位),左移X一位入c。d=(d右移c非位),j=d。

(2) 如果d<1或w=“y”则打印d和w后结束,否则转3。

(3) 如果f=0则转4否则转5。

(4) <查找沿根链前进>。

4.1) 如果u=v(j)则置w=“y”,转2;

4.2) 如果u<v(j)则置f=1,d=(d右移一位),j=j-d,转2;

4.3) 如果u>v(j)则d=(d右移c位),左移X一位入c,d=(d右移c非位),j=j+d。转2。

(5) <查找在左满树中进行>。

5.1) 如果u=v(j)则置w=“y”,转2;

5.2) 如果u<v(j)则d=(d右移一位),j=j-d,转2;

5.3) 如果u>v(j)则d=(d右移一位),j=j+d,转2。

4.3 作业树

有了上述算法,现在就可以设计出相应的作业树了,如图4.3所示。我们看到,这棵作业树比较复杂,程序量也比较大。子细观察就可以看出,这棵作业树是可以进一步优化的。当u=v(j)时,无论f等于0或1,都是置查找成功标志w=“y”;当u<v(j)时,无论f等于0或1,都要做d=(d右移一位),j=j-d,而重复做f=1也不影响算法逻辑;只有当u=v(j)时,f等于0或1所做的操作有所不同。优化后的作业树如图4.4所示。

图4.3 底2分化查找的作业树

图4.4 优化后的底2分化查找的作业树

4.4 遍历编程

遍历图4.4的作业树,就可编出底2分化查找的程序,图4.5就是相应的伪代码程序。在此,我们再一次重述作业树的遍历编程规则:

    从根节点开始,自上而下、先左子树、后右子树、再中子树,子树递归地遍历作业树,每进入一个节点就对其编程。

下面自左向右的节点排列就是对图4.4作业树节点的遍历顺序。

C0 C1 C2 L1 C3 L2 C4 L3 L4 L5

在遍历至每一个节点的同时,“每进入一个节点就对其编程”。所谓对节点编程,就是将每个节点中各部分的内容写出来。对于每一个作业节点,其各部分的编程顺序为:

    注释部  顺序部  逻辑表达式部和控制类型部

[底2分化查找的伪代码程序]

//C0底2分化查找//

Bsearch(N,u)

{//C1//

f=0,w=“n”;

X=(N)2=(xm-1xm-2…x1x0)2;

d=(2m-1)2

X=(X循环左移一位);

左移X一位入c;

d=(d右移c非位),j=d;

while (d≥1且w=“n”)

{//C2//

if (u=v(j))

{// L1:成功找到//

w=“y”;

}

else

{//C3//

if (u<v(j))

{//L2:在左满树中向后查找//

f=1;

d=(d右移一位);

j=j-d;

}

else

{//C4:生成不同的向前步长//

If (f=0)

{// L3:沿根链向前查找//

d=(d右移c位);

左移X一位入c;

d=(d右移c非位);

j=j+d;

}

else

{//L4:在左满树中向前查找//

d=(d右移一位);

j=j+d;

}

}//节点C4的程序结尾//

}//节点C3的程序结尾//

}//节点C2的程序结尾//

}//节点C1的程序结尾//

return (w,j);

}//节点C0的程序结尾//

图4.5 底2分化查找的伪代码程序

4.5 结束语

本文介绍的底2分化查找算法的确具有最优的查找性能,且以移位替代了除法,但程序量相对大了一点。当然,图4.4的作业树还可以进一步优化。辟如,可以将L3和L4中的“j=j+d”操作放在C4的中儿子中,以免重复写这条语句。还有,再做稍大点的调整后,操作“d=(d右移一位),j=j-d”亦可以放入控制节点的中儿子中,减少重复编写这两条语句。感兴趣的读者可以试着做上述两项修改。一眼就能看出优化处也是用作业树表示算法的一大好处,在用叙述或程序表示的算法中找出并优化程序就不太直观。

世界上有数不清的函数级求解的问题,但写文章找例子却不容易。一是要多数能都相对熟悉,二是要能说明论题。早年有“子程序汇编”之类的书,有时间的话也可编写一本“作业树汇编”,这当然需要众人拾柴火焰高,不是那一个人或几个人能完成的。

转载于:https://my.oschina.net/treesoft/blog/73261

4底2分化查找程序的作业树相关推荐

  1. 【懒癌发作】收集各种懒癌发作时用程序写作业的程序

    updata:20170621 好的,已经是准高一了,现在看起来太蠢了... ------------------------------------------------------------- ...

  2. 下列python语言、返回结果不是uc_MKAN1-UC 5103作业代写、代做Analytics作业、Java,Python,c/c++程序语言作业代做...

    MKAN1-UC 5103作业代写.代做Analytics作业.Java,Python,c/c++程序语言作业代做 日期:2020-05-21 11:08 Marketing Analytics Sp ...

  3. python二分法查找程序_Python程序查找最大EVEN数

    python二分法查找程序 Input N integer numbers and we have to find the maximum even number. 输入N个整数,我们必须找到最大的偶 ...

  4. python二分法查找程序_查找Python程序的输出| 套装2(基础)

    python二分法查找程序 Program 1: 程序1: a = 10 b = 3 res = a/b print "a/b: ", res res = float(a/b) p ...

  5. python二分法查找程序_Python程序查找地板划分

    python二分法查找程序 When we divide a number by another number – division operator (/) return quotient it m ...

  6. python实验报告代写_TensorFlow作业代写、代做Python程序语言作业、代写github课程作业、Python实验作业代写...

    TensorFlow作业代写.代做Python程序语言作业.代写github课程作业.Python实验作业代写 日期:2019-07-10 10:34 Python Practical Examine ...

  7. (105)FPGA面试题-查找程序中的代码错误

    1.1 FPGA面试题-查找程序中的代码错误 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-查找程序中的代码错误: 5)结束语. 1.1.2 本节引言 ...

  8. c语言程序二进制代码,二进制搜索/查找程序(C语言)

    二进制搜索/查找程序(C语言),如下代码所示: #include #define MAX 20 // array of items on which linear search will be con ...

  9. LoadRunner 是要保存此文件,还是要联机查找程序来打开此文件

    软件 1.LoadRunner:LoadRunner12.0.2 LoadRunner12.55(两个版本我都用过,都会出现这种情况) 2.浏览器:IE11 火狐29(两个浏览器都试过,记得要用Loa ...

最新文章

  1. android小程序案例_小程序案例赏析:高质量的小程序怎么做
  2. ubuntu 配置samba
  3. 2018java多线程面试题_2018JAVA面试题附答案
  4. java虚拟机学习-JVM调优总结-新一代的垃圾回收算法(11)
  5. linux参考文献_linux常用指令
  6. 800名员工被隔离,韩国半导体巨头紧急回应:工厂运营不受影响
  7. NET USE 命令用法
  8. [No000083]文件与文件夹操作
  9. 细说GIT分布式版本控制器
  10. x11 matlab仿真,基于MATLABSimulink的弹道仿真方法.pdf
  11. 松散四叉树+网格法实现
  12. 编制现金流量表3个步骤!
  13. ftp上传工具 6款用了就会爱上的ftp上传工具良心推荐
  14. logo设计的基础知识
  15. 计算机工资管理软件是,计件工资管理软件
  16. 监控工具普罗米修斯(Prometheus)的介绍与安装
  17. 解决 WPS 输入文字颜色无法改变并自带下划线的问题
  18. configure报错
  19. jsp实现简单的购物车系统
  20. 关于系统之间的单点登陆对接

热门文章

  1. 同城信息发布小程序开发制作
  2. MongoDB+模板引擎 项目学习 ---学生档案管理
  3. Certbot的使用
  4. CentOS安装NETCDF
  5. Vue, App与我(十三)
  6. 中间件-RabbitMQ学习笔记
  7. 各种加速卡 异构计算
  8. 成人高考计算机专业,成人高考计算机专业难吗?
  9. Fedora 20 的 r8168 与 rtl8723be 驱动
  10. 《中国人史纲》读书笔记:第八章、第九章 公元前第六、五世纪