分级定位排序和分级定位查找的动态查找表的算法的制作方法

文档序号:6420308阅读:216来源:国知局
专利名称:分级定位排序和分级定位查找的动态查找表的算法的制作方法
一种计算机对数据进行排序和进行查找的算法。
目前时间复杂度较好的算法有快速排序、堆排序、希尔排序、归并排序等,除希尔排序外,其它几种都是借助“比较”进行排序的算法,根据斯特林公式,有[log2(nl)]=O(nlogn),上述结论从数量级上告诉我们,借助“比较”进行排序的算法在最坏情况下能达到的最好时间复杂度为O(nlogn)。基数排序不是借助“比较”进行排序的算法,时间复杂度为O(d*n),其中d为关键字从最高位到最低位的位数。这就是说,以上都是多趟排序。而且前三种是不稳定排序。目前还没有好的动态查找表算法。
有没有一种理想化的排序方法呢?对于完全无序的n个数进行排序,理想化的方法应该是每取出一个数,可以通过计算直接找到其所应该排在的位置,当n个数全部经过一趟计算后,全部找到其所应该排在的位置,这样就完成了排序。显然,理想化排序应该只要进行一趟排序即可完成排序,这大概不可能。
本发明的目的是提供一种分级定位排序和查找的动态查找表的算法,该算法可以实现以下功能1、只需一趟或少数趟即可完成稳定的分级定位排序,从而建立一个有序且分级的动态查找表;2、在此基础上,可以实现分级定位的动态查找,其优势是①、对于待查找的某个数,不需要进行“比较”,而只要进行“计算”,就可以直接在该查找表中确定一个数据“级”作为查找目标;②、可以在该“级”范围内使用折半查找等高效查找;③、适用于任意数据且数据量很大的查找表;④在避免了全程查找的同时也避免了“冲突”现象;⑤、可以对该动态查找表进行链表式删除和插入操作;⑥、改造插入算法,可使归并排序在保持稳定和高效的前提下,降低其附加存储空间并进一步提高排序速度。
先于原理描述给出附

图1、图2的说明,可能有助于原理的描述,而图3~图22的说明比较复杂,拟通过实施例给出。由于附图中有大量数据,为避免标号与数据混淆,特将标号统一用“G**”表示,*为任意数字。
图1——待排序数与分级排序的关系。g(x)——待排序数的实际概率密度曲线;f(x)——其理论概率密度曲线;x0~xm——分级排序的“级点”;min——待排序数中的最小数;max——待排序数中的最大数。
图2——待排序数与分级数组下标的关系。G1——例1中的待排序数,X(0)~X(18)为19个待排序数,(与x0~xm不同);G2——15个级点的头指针B(0)~B(14)和链表。
在本发明的原理描述中,为了叙述简便,以类pascal为基本语言,并作出以下约定①、将待排序关键字X(j).Key都简述为X(j);②、用X(J)表示待排序数组,默认(j=0,1,…,n);③、用x(j)表示X(J)中的一个元素;④、用b(R)表示一个分级数组,默认(r=0,1,…,m);⑤、用b(r)表示b(R)中的一个元素,b(r)同时也是第r级链表的头指针;⑥、b(r)的下标r就是数据的“级”;并用级内计数器k(r)记录第r级的数据量;⑦、用d(T)表示收集数据数组,默认(t=0,1,…,n);⑧、用d(t)表示d(T)中的一个元素;⑨、当第r级的数据收集至d(T)时,用h(r)记录第r级数据在d(T)中的起始位置。
图1中,待排序数组X(J)的实际概率密度曲线为g(x);其理论概率密度曲线f(x)与分级的关系为当x(j)∈[xr,xr+1)时,将x(j)链入(r)级。
对分级排序而言,分级映射可以是多种表达形式,较合理的有两种均布分级映射r:=trunc(m*(x(j)-min)/(max-min)) -------(1)等概分级映射r:=trunc(m*(F(x(j))-F(min))/(F(max)-F(min)))---------(2)式中的m为分级数,可以根据需要任意取值。r就是x(j)对应的级。
关于图1要注意到,xr不是x(r),xr是一个坐标,而x(r)是第r个待排序数。X(J)中的最小值为Min,对应着x0;最大值为Max,对应着xm;由m+1个坐标x0~xm将区间[x0,xm]划分为m个子区间[x0,x1)~[xm-1,xm),对应了b(0)~b(m-1)级,加上右端点xm级,将数组X(J)的n个数分为b(0)~b(m)共m+1个级。
建立分级定位排序动态查找表和分级定位查找共经历四个阶段①、分级排序阶段;②、建立动态查找表的定位排序阶段;③、分级查找阶段;④、定位查找、增加、删除阶段。
第1阶段——分级排序阶段基本原理是将n+1个待待排序数X(0)~X(n)进行分级排序,其特征是确定将待排序数的分布范围后,将其范围划分为多个级别,用一个作为分级变量的静态数组链表来表示这些级别,每个级别的大小对应着一个分级变量静态数组链表元素的下标值,当取出一个待处理数(即待排序数或待查找数)时,用一个变换关系得到该待处理数与上述静态数组链表元素的下标值的对应关系,使该待处理数根据运算得到的级别直接找到它所对应的分级变量静态数组链表元素;分级变量静态数组链表的每个元素引导着一个动态存储空间,所以该待处理数属于该动态存储空间。
分级排序基本原理。对于待排序数X(j)(j=0...n),首先确定其最大数(Max)和最小数为(Min),所以待排序数的分布范围为Max-Min,将分布范围预设为m+1个大小级别(r=0...m),,每个级别与静态数组链表B的一个数组元素b(r)对应,b(r)称为分级变量,其中的下标r用于表示级别大小(r=0...m),称为级别变量,每个分级变量b(r)都引导着一个动态存储空间;每当取出一个待排序数,对应其大小,可以直接通过变换关系换算为b(r)下标值r的大小,找到其所应该归属的级别b(r),从而无须查找就可以直接放入分级变量b(r)引导的动态存储空间之中;当待排序数全部经过一趟计算后,都直接找到其所应该归属的分级变量b(r),就完成了按级别大小的分级排序;分级变量b(r)引导的动态存储空间,可以是动态数组、链表、栈、队列;如果采用链表存储结构,当新结点要加入到分级变量b(r)引导的链表中,令新结点的指针等于b(r)指针指向链表,而后将b(r)指针指向新结点,形象点说,是将新结点“插队”在链表的第一位,可以简化算法。
实施例1(分级排序)。设有19个待排序数X(0)~X(18)见图2,令式(1)中(max-min)/m=2,分级间距刚好为整数2。算法如下(为节省版面,以后用‖表示换行)……‖[pt=↑pt1;{构造一个指针型变量}‖pt1=record‖c1:real;{可用于实数排序}link:pt;]‖……‖b:array(0..m)of pt;{将分级数组定义成静态数组链表}d:array(0..n)of pt;{将数组d(T)定义为静态数组链表,详见实施例2}bbb:pt;‖……{确定X(J)的分布范围max-min=45-17;(略)}for j:=0 to n do {对所有的x(j)进行分级排序}[r:=trunc((X(j)-min)/2);{本例设计的分级映射,令式(1)中(max-min)/m=2}if k(r)=0 then[b(r)↑.c1:=x(j);‖k(r):=k(r)+1;]else[new(bbb);{逐个将x(j)链入它所对应的b(r)链表}bbb↑.c1:=x(j); {构造一个新结点}bbb↑.link:=b(r);{令新结点的指针等于b(r)指针指向链表}b(r):=bbb;{将b(r)指针指向新结点}‖k(r):=k(r)+1;]]注(1)每个r级内都有一个级内计数器k(r)统计该“级”中数据个数,之所以要用数组变量k(r)的形式,为的是使任一级的计数器与其它级的计数器不至于相混淆。(2)处在k(r):=k(r)+1上面的四句使得新分配来的结点被直接链接在充当“头指针”的b(r)之后。
于是(图2),x(0)~x(18)都从小到大直接放入b(0)~b(14)所引导的链表中,这就完成了将x(0)~x(18)按“级”大小进行的分级排序。
第2阶段——建立动态查找表的定位排序阶段经过实施例1的分级排序之后,简单地进行级内排序和数据收集,当然可以使查找表成为顺序结构的有序表,表1 例2排序后,r、h(r)、k(r)、t、d(t)之间的对应关系
有利于类折半查找。但是这还不够,因为分级定位排序不是着眼于类折半查找,而是着眼于建立动态查找表和效率更高的分级定位查找,以求接近理想化查找、增加、删除操作。在级内排序和数据收集的同时就为分级定位查找打基础——这就是定位排序的定义。实施例2(定位排序,包括级内排序和数据收集两个步骤)。为了以后分级查找的需要,应设计一个数组变量h(r),记录第r级数据在收集到数组d(T)中的起始位置t。对照(表1),例如h(5)=8,表示第5级的数据在d(T)中的起始位置为8,配合k(5)=3,得知d(8)~d(10)三个变量中装入的是第5级数据。数据收集数组d(T)完成数据收集工作后,就成为了查找表,如果是要建立静态查找表,就将数组d(T)定义成普通的数组;如果是要建立动态查找表,就将数组d(T)中每一个元素附加一个指针,数组d(T)就被改造为静态数组链表。定位排序算法如下t:=0;{t用于记录收集数组d(T)的当前位置}for r:=0 to m do{逐级对b(r)进行数据收集和级内排序}[if k(r)>0 then {k(r)<=0意味着b(r)中没有数据需要收集,跳到下个级}[if k(r)=1 then {k(r)=1意味着b(r)链表中只有一个数据需要收集,无需先级内排序}[d(t):=b(r)↑.c1;‖h(r):=t;{解释①}‖t:=t+1;]‖else{解释②}[h(r):=t;{解释③}‖for r:=1 to k(r) do{解释④}[{调用级内排序子程序}]for r:=0 to k(r) do {数据收集}[{将排序后的当前r级的k(r)个数收集至数组d(T)之中}]]]]
解释①----当k(r)=1时,表示r级中恰好一个数据,该数据为d(t)=b(r)↑.c1,将b(r)↑.c1收集到数组d(T)之中后,可知r级在数组d(T)中有一个唯一且确定的位置t,于是,令h(r)=t,登记下r级定位于数组d(T)中的位置。
解释②----k(r)>1,意味着b(r)引导着多个数据需要收集,这些数据将在数组d(T)占据k(r)个连续的位置。
解释③----将上述k(r)个连续的位置中的基准位置(即起始位置或终了位置,为叙述方便起见,以下都以起始位置作为基准位置)t登记于h(r),确定第r级在d(T)中的起始位置为h(r),终了位置为h(r)+k(r)-1,为以后的分级查找作准备。
实际上有,h(r):=k(0)+……+k(r-1)。
解释④----当前级在收集之前要进行级内排序。分级排序后级内仍然无序,所以需进行级内排序,将b(r)链表中的k(r)个数据进行排序,然后再将这k(r)个数据收集到d(T)中。如果k(r)小,调用冒泡排序或归并排序子程序较快;k(r)很大,则可以考虑递归调用分级排序程序。全部排序是否稳定,取决于级内排序是否稳定。
级内数据量很大时,采用递归算法调用分级排序;级内数据量较大时,采用传统的排序算法(归并排序、快速排序、等等)。由于归并排序具有稳定排序和速度快的优势,同时有占用辅助存储空间较大的缺点,所以本发明后部分将改造传统的归并排序法,使之降低辅助存储空间,并且进一步提高排序速度。
第3阶段——分级查找阶段实施例3(分级查找)。采用分级排序相同的分级算法确定待查找数所在级别。设待查找数为X=27.8。首先要将X分级,在实施例1分级定位排序的基础上,采用同一个分级公式,求得r、h(r)、k(r)、第r级在d(t)中得范围,算法如下r:=trunc((X-min)/2);{已知min=17,得到r=5,应在数组d(T)中第5级中查找X}由r=5在h(r)中得到h(5)=8;{在d(T)中,第5级的起始位置为d(h(5))=d(8);}由k(5)=3;{可知第5级的查找跨度为3;}最后确定,第5级的数为d(8)、d(9)、d(10),在其中查找X。
第4阶段——动态查找表的定位查找、删除数据操作阶段实施例4(定位查找),实际上就是级内查找,鉴于名称的一致性,也以“定位”为名,故称之为定位查找。算法如下
(1)、当k(r)=0,数组d(T)中没包含r级,即x在d(T)中不存在;(2)、当k(r)=1,数组d(T)中r级的数是唯一的,确切的位置为h(r)。所以,x如果在d(T)中存在;则只可能是x=d(h(r))。
(3)、当k(r)>1,数组d(T)中包含有多个的r级的数,其起始位置为h(r),终了位置为h(r)+k(r)-1。x如果在d(T)中存在;则只可能是[d(h(r))~d(h(r)+k(r)-1)]当中的一个。由于[d(h(r))~d(h(r)+k(r)-1)]是有序的,所以可以采用类折半查找。我们知道,哈希查找也能够确定查找范围,但是无法采用类折半查找。
如果只是要建立静态查找表,就将数组d(T)定义成普通的数组即可;如果是要建立动态查找表,就要将数组d(T)定义成静态数组链表,将普通数组的每一个元素附加一个指针,数组就被改造为静态数组链表,实际上就是一个动态查找表。
动态查找表删除数据对于动态查找表,删除数据的算法,只需要在静态数组链表d(T)中跳过被删除数据即可。附图中有共性的符号有“→”——指针变量的指针;“∧”——指针域为“空”;“︽”——指针域指向充当结束标记的单元“ptMN”。“︽”表示结束单元,若指针为“︽”表示指针指向结束点ptMN,ptMN↑.link:=NIL;如果采用升序排序,则令ptMN↑.c1:=MaxNum(MaxNum为大于待处理数且机器能表示的数);当然,如果采用降序排序,则令ptMN↑.c1:=MinNum(MinNum为小于待处理数且机器能表示的数)。
实施例5,其目的是在静态数组链表d(T)中删除数据。其基础是在排序完成后,数据被收集到静态数组链表d(T)中。然后进行删除操作(图3)。
图3——(实施例5)删除数据的指针连接图。d(t)——静态数组链表,图中,由d(t)引导一组“日”字型的线框——指针型变量,(日字的上横为虚线、中横为双线、下横为单线;其中一格t为d(t)的下标,一格c1为d(t)的数据域,一格link为d(t)的指针域);由t引导的一排数据(0、1、2……)为d(t)的下标,所对应的单元分别为d(0)、d(1)、d(2)……,c1为d(t)的数据域,c1引导的一排数据(17、19.1、22.3……)分别为d(0)↑.c1、d(1)↑.c1、d(2)↑.c1……中的数据;比如,d(11)指的椭圆所圈的就是d(11)单元,由t、c1和link组成,t=11,c1=29.7(即d(11)↑.c1=29.7),link=12(即d(11)↑.link=d(12),),意思是d(11)的指针指向d(12),或箭头指向t=12(附图中的箭头指向不太好画,高t=**还有些距离,但意思是指向t=**。)。
如果要删除d(5),(c1=25.2),算法为
d(4)↑.link:=d(6); {跳过被删除数据d(5)}d(5)↑.link:=︽;{d(5)的指针脱离静态数组链表}动态查找表插入数据动态查找表增加数据本来和删除数据处于同一层次的问题,因为增加数据算法有一定的难度,所以必须详细介绍,(应该先插入后删除)。算法对于主序列待排序数组X(J),仍然进行分级定位排序(同实施例1、实施例2),必须注意的是,产生的有序主表d(T)为静态数组链表(t=0,1,…,n),而不是单纯的数组。级内计数器为k(r)。h(r):=k(0)+……+k(r-1),即h(r)=Σi=1r+1k(r-i)]]>补充定义①排序完成后,默认顺序为升序,(本文规定升序为正序,降序为逆序)。②如果要将一个节点da(ta)插入有序主表d(T)中,称da(ta)为“待插入结点”。③通过查找得知,若da(ta)应该插入在主表d(T)中的结点d(t)之后,则称结点d(t)为“插头”。用 表示应该在d(t)后面插入da(ta)。④定义pt1和pt2作为跟踪d(T)和da(Ta)当前位置的指针型变量;⑤算法要将d(T)和da(Ta)链接成汇总链表,pta作为汇总链表链接收集d(T)和da(Ta)结点的指针型变量。
对于待插入序列Xa(Ja),如果要有序地插入主表d(T)中,其算法有以下步骤①将待插入序列Xa(Ja)也进行分级定位排序(同d(T)算法相同),产生的(待插入)副表da(Ta)也为静态数组链表(ta=0,1,…,na),级内计数器为ka(r)。
②如果是逐个插入法(见实施例6、7),则根据待插入结点da(ta)↑.c1的值从大至小的顺序,依次对每个da(ta)进行查找和插入,(为节省版面,以后用‖表示换行)算法(先查找确定 然后),da(ta)↑.link:=d(t)↑.link;‖d(t)↑.link:=da(ta),以保证da(ta)插入d(T)后形成的新表d1(T1)仍然有序;如果是集团插入法(见实施例8、9、10、11、12),则顺从d(t)的正序,将da(Ta)中全部应该插入在某插头后面的若干个结点一次性集团插入,以保证da(ta)插入d(T)后形成的新表d1(T1)仍然有序。
③首先是通过分级定位查找(也可以类折半查找)确定插头d(t),然后将da(Ta)中符合条件的部分结点插入d(t)后面,逐批将da(ta)全部链结到d(T)中后合并成为d1(T1)。
④由于d1(T1)中包含着动态链表部分,所以再将d1(T1)重新进行数据收集到静态数组链表dy(Ty)中,(ty=0,1,…,ny),(ny=n+na+1)。
⑤对k(r)进行调整,令k(r):=k(r)+ka(r)。
假定Xa(Ja)(32.0、27.3、21.9、32.3、27.1、27.2、39.6)要插入d(T)中。当d(T)的数据量很大而待插入结点不多时,用逐个插入法较好。
图4——插头后只插入一个结点;图5——插头d(11)后面插入了两个结点;图6——插头d(9)后面插入了三个结点。
图4中,d(t)、t、c1、link、的含义与图3中相同,并约定(1)、da(ta)的定义与d(t)相同,ta的定义与t相同;(2)、da(5a)和da(5)表示的是同一个意思,da(5)用于程序中,下标还是用(0、1、2、3……)表示,而da(5a)用于图解中,ta引导的下标数记为(0a、1a、2a、3a……),在数字后面附加一个a是为了区别d(t)中t引导的(0、1、2、3……),以免混淆;(3)、当指针域的数据为(0、1、2、3……)时,表示其指针是指向d(t)的指针;当指针域(link)中为数据后面附加一个a(0a、1a、2a、3a……)时,表示其指针是指向da(ta)的指针,例如图4中d(11)(椭圆圈)单元中的link=5a,表示d(11)↑.link=da(5a);又如da(5a)单元中的link=12,表示da(5a)↑.link=d(12);(4)、如果da(t)↑.c1<d(t)↑.c1,则简述为da(t)<d(t)。(本文所有约定全文通用)。
实施例6正序(d(T)和da(Ta)都是升序)排序逐个插入算法。
①将Xa(Ja)按正序进行排序,并构成静态数组链表da(ta),得到图4中的da(Ta)(da(0a)↑.c1=21.9、da(1a)↑.c1=27.1、da(2a)↑.c1=27.2、da(3a)↑.c1=27.3、da(4a)↑.c1=32.0、da(5a)↑.c1=32.3、da(6a)↑.c1=39.6);②按da(6a)……da(0a)的c1从大到小逐个插入结点。
第一个是插入结点da(6a),查得应在d(15)后插入da(6a)(记为 ),所以将图4中的指针走向连接成……→d(15)→da(6a)→d(16)→;算法为da(6a)↑.link:=d(15)↑.link;‖d(15)↑.link:=da(6a)第二个是插入结点da(5a),查得插头为d(11),即 所以将图4中的指针连接成……→d(11)→da(5a)→d(12)→……;算法为da(5a)↑.link:=d(11)↑.link;‖d(11)↑.link:=da(5a)第三个是插入结点da(4a),同结点da(5a)一样,查得插头又是d(11), 指针应该连接成图5走向……→d(11)→da(4a)→da(5a)→d(12)→……;算法为da(4a)↑.link:=d(11)↑.link;‖d(11)↑.link:=da(4a)可以看出,都是采用同样的算法查得插头
‖da(ta)↑.link:=d(t)↑.link;‖d(t)↑.link:=da(ta)。
对于da(3a)、da(2a)、da(1a)三个结点的插入,都是以d(9)为插头,根据c1从大到小逐个结点插入,将大数据结点逐个挤到后面,指针连接成图6走向……→d(9)→da(1a)→da(2a)→da(3a)→d(10)→……;与da(5a)、da(4a)的插入类似。
待da(ta)全部链结到d(T)中后合并成为图6的d(t)与da(ta)的汇总链表,由于先插入的结点被后插入的结点挤到了后面,所以,只要先插入的数大于后插入的数,就可以保证新动态查找表仍然有序。又由于汇总链表中包含着静态数组链表和动态链表两部分,所以应该将其再重新进行数据收集到纯静态数组链表dy(Ty)中,(实施例6中,ty=0,1,…,25)。
实施例7逆序排序逐个插入算法。
①将Xa(Ja)按d(T)的逆序进行排序,并构成静态数组链表da(ta),得到da(Ta)(da(0a)↑.c1=39.6、da(1a)↑.c1=32.3、da(2a)↑.c1=32.0、da(3a)↑.c1=27.3、da(4a)↑.c1=27.2、da(5a)↑.c1=27.1、da(6a)↑.c1=21.9);②按da(0a)……da(6a)的顺序逐个插入结点。其它内容与实施例6相同。
实施例8单向集团插入算法(单向指只是da(Ta)中的结点往d(T)中插)。当待插入结点不多但是数据经常成团时,用单向集团插入法较好。
①将Xa(Ja)按d(T)的正序进行排序,得到da(Ta)(同实施例6)。
②插入顺序为da(0a)……da(6a),正向集团插入,比如查得有 不是立即将da(ta)插入,而是再循环判断da(ta+1)、da(ta+2)、da(ta+3)……是否也应该以d(t)为插头,如果有一批结点都以d(t)为插头,则将这批结点集团插入到d(t)之后。比如图6中(da(1a)、da(2a)、da(3a))都以d(9)为插头,则将(da(1a)→da(2a)→da(3a))集团插入d(9)之后,连接成……→d(9)→(da(1a)→da(2a)→da(3a))→d(10)→……。
查找插头d(t)的方法可以采用分档定位查找,这将比传统的类折半查找更快。
动态查找表的双向集团链接算法,这是一种大数据量的动态插入算法,实际上就是两个序列归并排序。图7——当数据量很大时的d(T),图8——当数据量也很大时的da(Ta),将d(T)和da(Ta)对称地归并排序成汇总链表(图9),然后再收集到纯静态数组链表dy(Ty)中,称之为双向集团连接算法。算法为对于将要链接成汇总链表两个有序序列d(T)和da(Ta)或(图14-19)待归并排序的所有序列,令每个序列的最后单元的指针都指向结束单元“︽”;然后d(T)和da(Ta)的数据进行比较,当循环比较得知d(t)、d(t+1)、……、d(t+h)中的数据都以da(ta)为插头时,将这些结点成批连接到插头da(ta)之后,同样,当循环比较得知da(ta)、da(ta+1)、……、da(ta+ha)中的数据都以d(t)为插头时,将这些结点成批连接到插头d(t)之后,如此往复,直至有一个序列到了“︽”,则该序列当前指针不指向“︽”而指向对面序列,使两序列链结成一条整链。此算法细分为左右交替计数式、左右交替跟踪式、上下滚动计数式、上下滚动跟踪式四种算法。
实施例9动态查找表的左右交替计数式双向集团链接算法。
附图10是其程序流程图。G3~G5是预处理部分。G3——t、ta赋初值为0;G4——判别d(0)与da(0)的大小;G5——d(0)<=da(0)则令Abc:=aa,否则令Abc:=bb,Abc用于控制链接程序的走向;G6~G12是链接程序模块。G6——如果d(t)与da(t)都没有到结束单元“︽”,则继续执行循环体(链接程序),否则循环结束;G7——根据Abc来控制链接程序是走左路(收集d(t)序列)还是走右路(收集da(ta)序列),以下假定Abc=aa,则意味着d(t)<=da(ta)而走左路;G8——循环判断是否继续为d(t)<=da(ta),是则执行G9——汇总链表继续收集d(t),d(t)的指针下移一位;G10——当da(ta)<d(t)则令Abc:=bb,为执行右路程序作准备;G11——由于d(t)>da(ta),退上去有d(t-1)<da(ta),所以用d(t-1)的指针链接da(ta);G12——da(ta)的指针下移一位,转到右路去以后可以少作一次比较操作,由于在右路经过一次比较后也会将da(ta)的指针下移一位,所以这一步仅仅是节省一次比较。
右路的执行过程完全类似,不赘述。
实施例10动态查找表的左右交替跟踪式双向集团连接算法。
附图11是其程序流程图。G13~G16是预处理部分。G13——分别对pt1和pt2赋初值,pt1为跟踪d(t)当前位置的指针,pt2为跟踪da(ta)当前位置的指针;G14——判别d(0)与da(0)的大小;G15——假定d(0)<=da(0),则令Abc:=aa,(否则令Abc:=bb);G16——对pta赋初值,指针型变量pta为汇总链表的“收集指针”,该收集哪个单元时就将pta的指针指向该单元。G17~G23是链接程序模块。G17——如果d(t)与da(t)都没有到结束单元,则继续执行循环体(链接程序),否则程序结束;G18——根据Abc来控制链接程序是走左路还是右路,假定Abc=aa,程序走左路;G19——循环判断是否继续为d(t)<=da(ta),是则执行G20——汇总链表继续收集d(t),pta的指针下移一位;G21——当da(ta)<d(t)则令Abc:=bb,为执行右路程序作准备;G22——用pt1登记d(t)刚好大于da(ta)的单元,为回到d(t)提供准确位置;G23——(因为pt2较小)pta的指针指向pt2。
右路的执行过程完全类似,不赘述。
实施例11动态查找表的上下滚动计数式双向集团连接算法。
附图12是其程序流程图。G24~G29是预处理模块,如果d(0)<=da(0),则汇总链表以d(0)为头,执行模块G30~G37;如果有一些da(ta)<d(0),则汇总链表以da(0)为头,将这些小于d(0)的da(ta)收集到汇总链表,于是,使得链接程序模块G30~G37总是以d(0)开始。G24——t、ta赋初值为0;G25——判别d(0)与da(0)的大小,当d(0)<=da(0)则执行G30,以d(0)为汇总链表的头,当da(0)<d(0),则执行G26——以da(0)为汇总链表的头,da(ta)的指针下移一位;G27——当继续是da(ta)<d(0),则G28——da(ta)的指针循环下移;G29——当d(0)<=da(ta),有d(0)>da(ta-1),所以由da(ta-1)链接d(0);G30~G37是循环链接程序模块。G30——如果d(t)与da(t)都没有到结束单元,则执行循环体(链接程序),否则程序结束;G31——当继续是d(t)<=da(ta),则G32——d(t)的指针循环下移;G33——当da(ta)<d(t),有da(ta)>=d(t-1),所以由d(t-1)链接da(ta);G30~G33是当d(t)<=da(ta)时将d(t)链接到汇总链表中的程序模块;而G34~G37是当da(ta)<d(t)时将da(ta)链接到汇总链表中的程序模块,与G30~G33完全对称。G34——如果d(t)与da(t)都没有到结束单元,则执行循环体,否则程序结束;G35——当继续是da(ta)<d(t),则G36——da(ta)的指针循环下移;G37——当d(t)<=da(ta),则由小于d(t)的da(ta-1)链接d(t)。
实施例12动态查找表的上下滚动跟踪式双向集团连接算法。
附图13是其程序流程图。G38~G43是预处理模块,如果d(0)<=da(0),则汇总链表以d(0)为头,执行模块G44~G51;如果有一些da(ta)<d(0),则汇总链表以da(0)为头,将这些小于d(0)的da(ta)收集到汇总链表,再将指针指向d(0),于是,使得链接程序模块G44~G51总是以d(0)开始。G38——分别对pt1和pt2赋初值,pt1、pt2和pta意思与实施例10相同;G39——判别d(0)与da(0)的大小,当d(0)<=da(0)则执行G44,以d(0)为汇总链表的头,当da(0)<d(0),则执行G40——以da(0)为汇总链表的头,pta:=pt2,收集da(ta);G41——当继续是da(ta)<d(0),则执行G42——pta的指针下移,直至G41判断为“N”,执行G43——pt2:=pta↑.link(登记da(ta)的脱离结点),pta↑.link:=pt1(pta转移到d(t)序列收集数据);G44~G51是循环链接程序模块。G44——如果pt1与pt2都没有到结束单元,则执行循环体,否则程序结束;G45——当继续是pta↑.link↑.c1<=pt2↑.c1,(即对应于d(t)<=da(ta)),则执行G46——pta的指针循环下移;直至当pt2↑.c1<pta↑.link↑.c1,说明应该收集da(ta)序列的数据了,所以执行G47——由pta↑.link:=pt2将汇总链表指针转向指向da(ta)序列,而为了以后pta↑.link回指到d(t)序列时能够找到正确位置,在pta转到da(ta)序列之前先用pt1:=pta↑.link登记好回d(t)序列的位置;G44~G47是当d(t)<=da(ta)时将d(t)链接到汇总链表中的程序模块;而48~51是当da(ta)<d(t)时将da(ta)链接到汇总链表中的程序模块,与G44~G47完全对称。G48——如果pt1与pt2都没有到结束单元,则执行循环体,否则程序结束;G49——当继续是pta↑.link↑.c1<pt1↑.c1,则执行G50——pta的指针循环下移;直至pt1↑.c1<=pta↑.link↑.c1,说明应该收集d(t)序列的数据了,所以执行G51——先用pt2:=pta↑.link登记好回da(ta)序列的位置,再由pta↑.link:=pt1将汇总链表指针转向指向d(t)序列。
对于上下滚动式算法而言,其总体思路是{(当两序列都没有到“︽”)循环收集d(t)序列较小的结点,直至d(t)>da(ta);然后,(当两序列都没有到“︽”)循环收集da(ta)序列较小的结点,直至da(ta)>=d(t)};重复循环{}中的程序,直至有一个序列到了“︽”,则该序列当前指针不指向“︽”而指向对面序列。
以上四种双向集团插入算法,其实是形成了对于两个序列的归并排序的算法,稍作调整即可成为“具有领头数组的链表结构的归并排序”,以下简称AS归并排序算法,可分为左右交替跟踪式AS归并排序算法(例13)和上下滚动跟踪式AS归并排序算法(例14)。
其图示有图20为第一趟排序的框图,图21为第二至末趟左右交替跟踪式排序的框图,和图22为第二至末趟上下交替跟踪式排序的框图,这三个程序框图的说明穿插在图14~图19中具体解释。对于(图14-19)待归并排序的所有序列,令每个序列的最后单元的指针都指向结束单元“︽”。对两个序列进行归并排序的算法发展成对一批数据的归并排序算法,首先是将数据赋值到一个静态数组链表d(T)中,然后数组d(T)中相邻关键字两两为一组进行比较,实现两两升序排序;每个序列由一个头指针领队,dh(Th)指针数组充当排序时的头指针。
实施例13左右交替跟踪式AS归并排序算法。
图14为用静态数组链表d(T)存放待排序数据图。为了后续编程的需要,各单元的指针link全部指向一个结束结点ptMN,用“︽”表示。算法为图20中的G52,将各单元的link循环赋值为ptMN。
图15为第一趟排序后的链接关系图,其中dh(Th)指针数组充当排序时的头指针。第一趟排序时,数组d(T)中相邻关键字两两为一组(两条粗线所夹的两个单元,如d(0)/d(1),d(2)/d(3),……)进行比较,实现两两升序排序。如d(1)↑.c1<d(0)↑.c1,所以链接成dh(0h)→d(1)→d(0)→︽,算法为dh(0h)↑.link:=d(1),d(1)↑.link:=d(0),其中dh(0h)为该组的头指针,随后几组类似。于是第一趟排序后,头指针dh(0h)~dh(11h)各自引导一个升序序列。头指针个数为d(T)元素的“trunc(n/2)”,当然也可以令头指针个数与d(T)元素个数相等,但是浪费空间太大。算法为图20中的G53~G60,注意到当n为偶数时,d(T)元素为(0~n)奇数个,配成n/2对后还要剩一个单的,所以要讨论头指针的个数nh如何取值,先讨论一下G53中的“trunc((n-1)/2)”,当d(T)元素为偶数个时(n为奇数),n-1为偶数,形成了序列dh(0)~dh(trunc((n-1)/2),全部配对了,没有成单的;当d(T)元素为奇数个时(n为偶数),除了序列dh(0)~dh(trunc((n-1)/2)外,还剩下一个d(n)成单,在执行G57句时的判断为“Y”,就意味着d(T)元素为奇数个,还剩下一个d(n)成单,于是在G59单独用一个头指针dh(nh)↑.link:=d(n)引导,其中nh的赋值由G58完成。G53——头指针dh(th)的下标th从0~trunc((n-1)/2)时,执行循环体G54~G56,将相邻(偶/奇)关键字两两为一组,升序排序,链接在对应的头指针dh(th)后面,;G54——将数据进行升序排序,判断d(2*th)↑.c1<=d(2*th+1)↑.c1,是否成立,如果是,则执行G55——完成链接dh(th)→d(2*th),G56——完成链接d(2*th)→d(2*th+1),G55和G56共同完成链接dh(th)→d(2*th)→d(2*th+1)→︽;如果否,(则执行与G55、G56对称的两句)完成链接dh(th)→d(2*th+1)→d(2*th)→︽。G57~G60为判断n的奇偶并进行的不同处理,其中G57为“Y”的情况刚才已经分析过了;G57——判断为“N”则意味着n为奇数,d(T)元素为偶数个(n+1个),没有单剩的单元;执行G60——令nh:=trunc(n/2),dh(th)的下标th=0,1,……trunc(n/2)。实际上,因为本算法的th是从0~nh,所以有nh+1个头指针。即,nh+1为头指针个数。
第二趟至末趟排序的程序框图为图21,对应的链接关系图为(图16~图19)。
图16为第二趟排序后的链接关系图,第二趟排序时,对第一趟排序后相邻(偶/奇)序列两两为一组(两条粗线所夹的四个单元,如d(0)/d(1)/d(2)/d(3),……)进行比较,归并为一组升序序列。如根据大小可知,第一组为17→26→31→96,所以链接成dh(0h)→d(2)→d(1)→d(0)→d(3)→︽,其中dh(0h)为该组的头指针;下同。
对应的程序框图为图21中,G61——对u赋初值,u是控制头指针跨度的变量,由G74对u进行调整,比如,第二趟排序的跨度等于初值20,第三趟排序的跨度调整后等于21,第四趟排序的跨度等于22,第五趟排序的跨度等于23,……。G62——头指针个数nh+1>1时继续归并,nh+1=1时表示只有一路链表了,归并排序完成。G63——对多路链表归并时,计数器qh控制循环,循环终值为trunc((nh-1)/2),为什么要采用(nh-1)的理由与53句相同。G64——q:=2*qh使得q总是偶数,有利于每次取两列排序,Abc:=aa为后续的分支赋初值,pta指向dh(u*q),第二趟排序时u=20=1,所以pta分别指向dh(0)、dh(2)、dh(4)、dh(6)、dh(8)、dh(10)、dh(12)……;(同样,第三趟排序时u=21=2,所以pta分别指向dh(0)、dh(4)、dh(8)、dh(12)、dh(16)……;第四趟排序时u=22=4,所以pta分别指向dh(0)、dh(8)、dh(16)……;)。G65——由于每次都是由偶路dh(u*q)与对应的奇路dh(u*(q-1))合并,所以用一个偶路跟踪指针pt8跟踪偶路当前单元(即正在参加对奇路数据进行比较的单元)和一个奇路跟踪指针pt9跟踪奇路当前单元。G66——当偶路和奇路都没有到结束点时执行循环体。G67——选择执行左路还是右路程序,假定Abc:=aa,执行G68——判断偶路当前单元是否不大于奇路当前单元;当G68的判断为是,则执行G69——偶路当前指针下移;当G68的判断为否,则执行G70,令Abc:=bb,这是为转移到奇路(右路)程序的准备工作之一;G71——这是为转移到奇路程序的准备工作之二,由于pta↑.link即将指向奇路dh(u*q+1),离开目前的偶路dh(u*q),所以用pt8登记此时pta↑.link指向的结点,即登记“偶路离开结点”。G72——pta↑.link指向pt9,转移到奇路收集结点,pt9和pt8类似,是“奇路离开结点”。G63引导的循环直至本趟排序完成。G73——确定新一轮头指针数,nh:=trnuc(nh/2)的解释是头指针的个数为nh+1个(因为是0~nh),等号右边的nh为nh+1=刚完成排序的头指针数,等号左边的nh为nh+1=即将进行排序的头指针数。G74——调整头指针跨度。
图17为第三趟排序后的链接关系图。其程序框图还是图21。第三趟排序时,对第二趟排序后相邻序列两两为一组(两条粗线所夹的八个单元)进行比较,归并为一组升序序列。如根据大小可知,第一组为17→25→26→31→37→49→75→96,所以链接成dh(0h)→d(2)→d(7)→d(1)→d(0)→→d(4)→d(6)→d(5)→d(3)→︽;其它组方法相同。
图18为第四趟排序后的链接关系图。第四趟排序时,对第三趟排序后相邻序列两两为一组(两条粗线所夹的16个单元)进行比较,归并为一组升序序列。如根据大小可知,第一组链接成dh(0h)→d(15)→d(2)→d(7)→d(1)→d(0)→d(9)→d(4)→d(12)→d(6)→d(8)→d(14)→d(11)→d(13)→d(5)→d(10)→d(3)→︽;下同。
图19为第五趟排序后的链接关系图。排序完成。
实施例14上下滚动跟踪式AS归并排序算法。
其中图14至图20的说明与实施例13完全相同,所不同的是图21类似于动态查找表的左右交替跟踪式双向集团连接算法,而图22类似于动态查找表的上下滚动跟踪式双向集团连接算法。
图22中与图21中相同的语句有G61~G66、G73、G74。所以这里仅需要解释G75~G81句。当G66成立时表示奇偶两路都没有到底,于是进行G75的判断,“Y”则执行G76将偶路指针下移,将偶路当前数据收集到汇总链表中,收集偶路数据直至G75的判断为“N”,进行收集奇路的准备,G77中的两个赋值分别与图21中的G71、G72对应相同,由于这时必定是奇路的数据小于偶路数据;所以执行G78~G81(分别与本图G66、G75~G77对应),将奇路当前数据收集到汇总链表中。继续循环,直至归并排序完成。
实施例15定位算法。在对d(T)的原始序列数据进行分级排序时,已经得到各级r的计数器值k(r);同样,也可以得到da(Ta)各级r的计数器值ka(r);由于da(Ta)与d(T)的分级算法相同,所以链接成汇总链表后,汇总链表各级r的计数器值ky(r)=k(r)+ka(r);汇总链表各级的起始位置hy(r)根据公式hy(r)=Σi=1r+1ky(r-i)]]>计算得出,式中ky(-1)=0。
实施例16串的分级定位查找。补充定义(1)模式串的两个相等子串如果再延长一个字符就不相等,这两个子串称为最大相等子串。(2)模式串的中部某子串与首部某子串为最大相等子串,则分别称为“中子串”和“首子串”,第1个中子串的末字符位置为jz(1)、第2个中子串的末字符位置为jz(2)、……;因为多个中子串长度不一定相等,所以与jz(1)对应的首子串的末字符位置为js(1)、与jz(2)对应的首子串的末字符位置为js(2)、……,首子串的首字符位置为ja。(3)两个子串可以有共有字符,如AAABCDEAAABCDEAAFGH,其中标记有下划线的两个AA既属于首子串AAABCDEAA,也属于中子串AAABCDEAA。(4)主串中与首子串匹配的为首匹配串,与中子串匹配的为中匹配串,(5)当模式串前部若干字符与主串的若干字符相匹配,简称“模/主前部匹配”,模式串的首字符简称“模首”。
在模式串中确定“首子串”的末位置和“中子串”,采用字符串分级定位查找算法①确定模式串中是否存在中子串,如果存在,则确定模式串中的js(1)、js(2)、……和对应的jz(1)、jz(2)、……②当模首与主串的字符不匹配时,模式串往后移动一位,再次与主串的字符比较;③当模式串前部与主串匹配,直至第jx位字符与主串对应的ix位字符不匹配时,有多种可能性(1)当jx<=jz(1)时,意味着主串的对比字符中,除与首子串对应的部分外,不会另外有与首子串相匹配的可能,所以模首可以滑行到主串的ix的位置相比较。
(2)当jx=jz(1)+1时,意味着主串的对比字符在中,与中子串对应的部分也与首子串相匹配,但是再往后面一位ix就失配了,而ix有可能与模式串的js(1)字符匹配,所以要将js(1)+1位与ix位相比较(js(1)+1滑行到jz(1)+1位)。
(3)实际上(1)和(2)中有一种特殊情况,就是当jx=中子串首字符时,模式串可以滑行到ix+1位;当然,考虑到仅仅多比较一次,将模首滑行到ix更简便。
(4)当jz(1)+1<jx<=jz(2),同(1);当jx=jz(2)+1,同(2)。jz(3)、jz(4)同理。
权利要求
1.一种分级定位排序和分级定位查找的动态查找表的算法,其特征是将待排序数的分布范围或查找表的分布范围划分为多个级别,用一个作为分级变量的数组来表示这些级别,每个级别的大小对应着一个分级变量数组元素的下标值,当取出一个待处理数(即待排序数或待查找数)时,用一个变换关系得到该待处理数与上述数组元素的下标值的对应关系,使该待处理数直接进入它所对应的级别,然后用一个静态数组链表将数据进行定位排序,形成分级定位动态查找表d(T)。
2.根据权利要求1所述的分级定位的排序和查找的方法,其进一步的特征是将排序分为分级排序阶段和定位排序阶段,所谓分级排序是,建立一个数组b(R)作为分级排序的头指针,b(R)中的每个元素引导一个等级,当待排序数经过计算后,直接分配其所应该归属的分级变量b(r),就完成了按级别大小的分级排序,b(r)引导的数据采用动态数据结构(包括链表、动态数组、动态的堆栈和队列)。
3.根据权利要求1所述的算法,其进一步的特征是定位排序时分级内排序和数据收集两步,第一步是级内排序,级内排序可以采用传统的排序方法(归并、冒泡、快速),如果某级数据量很大,可以再使用分级排序进一步分级;第二步是数据收集,用一个静态数组链表d(T)对已经完成级内排序的数据进行收集,;各个级别(r)在表d(T)中的起始位置h(r)由h(r)=Σi=1r+1k(r-i)]]>计算得出。
4.根据权利要求1所述的算法,其进一步的特征是对分级定位排序形成的d(T),进行数据插入时的算法包括逐个插入法(见实施例6、7)和集团插入法(见实施例8、9、10、11、12),如果是逐个插入法,则根据待插入结点da(ta)↑.c1的值从大至小的顺序,依次对每个da(ta)进行查找和插入;如果是集团插入法,则顺从d(t)的正序,将da(Ta)中全部应该插入在某插头后面的若干个结点一次性集团插入,以保证da(ta)插入d(T)后形成的新表仍然有序。对于待插入序列Xa(Ja),如果要有序地插入主表d(T)中,其算法有以下步骤①将待插入序列Xa(Ja)也进行分级定位排序(同d(T)算法相同),产生的(待插入)副表da(Ta)也为静态数组链表(ta=0,1,…,na),级内计数器为ka(r)。②如果是逐个插入法(见实施例6、7),则根据待插入结点da(ta)↑.c1的值从大至小的顺序,依次对每个da(ta)进行查找和插入,(为节省版面,以后用‖表示换行)算法(先查找确定 然后),da(ta)↑.link=d(t)↑.link;‖d(t)↑.link=da(ta),以保证da(ta)插入d(T)后形成的新表d1(T1)仍然有序;如果是集团插入法(见实施例8、9、10、11、12),则顺从d(t)的正序,将da(Ta)中全部应该插入在某插头后面的若干个结点一次性集团插入,以保证da(ta)插入d(T)后形成的新表d1(T1)仍然有序。③首先是通过分级定位查找(也可以类折半查找)确定插头d(t),然后将da(Ta)中符合条件的部分结点插入d(t)后面,逐批将da(ta)全部链结到d(T)中后合并成为d1(T1)。④由于d1(T1)中包含着动态链表部分,所以再将d1(T1)重新进行数据收集到静态数组链表dy(Ty)中,(ty=0,1,…,ny),(ny=n+na+1)。⑤对k(r)进行调整,令k(r)=k(r)+ka(r)。
5.根据权利要求1所述的算法,其进一步的特征是对于待归并排序的所有序列或将要链接成汇总链表两个有序序列,每个序列的最后单元的指针都指向结束单元“︽”;当正在归并的两序列都没有到结束单元“︽”,继续进行比较收集,当有一个序列到了“︽”,则指针不指向“︽”而指向对面序列。
6.根据权利要求1所述的算法,其进一步的特征是对于跟踪式算法而言,设置pt1和pt2作为跟踪d(T)和da(Ta)当前位置的指针型变量;算法要将d(T)和da(Ta)链接成汇总链表,汇总链表链接收集d(T)和da(Ta)的单元时使用了一个指针型变量pta作为“收集指针”;而计数式算法的当前指针就是d(t)和da(ta)本身。
7.根据权利要求1所述的算法,其进一步的特征是对于左右交替式算法而言,有一个变量(Abc)用于判断汇总链表应该是走左路(收集d(t)序列)还是走右路(收集da(ta)序列)。
8.根据权利要求1所述的算法,其进一步的特征是对于上下滚动式算法而言,{当两序列都没有到“︽”,循环收集完d(t)序列较小的结点;当两序列都没有到“︽”,循环收集完da(ta)序列较小的结点};重复循环{}中的程序,直至有一个序列到了“︽”,则该序列当前指针不指向“︽”而指向对面序列。
9.根据权利要求1所述的算法,其进一步的特征是对两个序列进行归并排序的算法发展成对一批数据的归并排序算法,首先是将数据赋值到一个静态数组链表d(T)中,然后数组d(T)中相邻关键字两两为一组进行比较,实现两两升序排序;每个序列由一个头指针领队,dh(Th)指针数组充当排序时的头指针。
10.根据权利要求1所述的算法,其进一步的特征是字符串的分级定位查找算法①确定模式串中是否存在中子串,如果存在,则确定模式串中的js(1)、js(2)、……和对应的jz(1)、jz(2)、……;②当模首与主串的字符不匹配时,模式串往后移动一位,再次与主串的字符比较;③当模式串前部与主串匹配,直至第jx位字符与主串对应的ix位字符不匹配时,有多种可能性(1)当jx<=jz(1)时,意味着主串的对比字符中,除与首子串对应的部分外,不会另外有与首子串相匹配的可能,所以模首可以滑行到主串的ix的位置相比较。(2)当jx=jz(1)+1时,意味着主串的对比字符在中,与中子串对应的部分也与首子串相匹配,但是再往后面一位ix就失配了,而ix有可能与模式串的js(1)字符匹配,所以要将js(1)+1位与ix位相比较(js(1)+1滑行到jz(1)+1位)。(3)实际上(1)和(2)中有一种特殊情况,就是当jx=中子串首字符时,模式串可以滑行到ix+1位;当然,考虑到仅仅多比较一次,将模首滑行到ix更简便。(4)当jz(1)+1<jx<=jz(2),同(1);当jx=jz(2)+1,同(2)。jz(3)、jz(4)同理。
全文摘要
一种分级定位排序和查找的动态查找表的算法,用分级定位排序建立一个有序且分级的动态查找表,实现分级定位的动态查找。其优势是①.对于待查找的某个数,而只要进行“计算”,就可以直接在该查找表中确定一个数据“级”作为查找目标;②.可以在该“级”范围内使用折半查找等高效查找;③.可以对该动态查找表进行链表式删除和插入操作;④.改造插入算法,可使归并排序降低其附加存储空间并进一步提高排序速度。
文档编号G06F7/06GK1612100SQ20031011045
公开日2005年5月4日 申请日期2003年10月27日 优先权日2003年10月27日
发明者陈启星 申请人:陈启星
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1