所谓游标就是指示数组单元地址的下标值,它属整数类型。我们可以用游标来模拟指针,将TElement类型的元素所组成的表用一个数组来实现,数组单元是记录类型,记录中包含一个表元素和一个作为游标的整数;具体说明如下:
Var SPACE: array[1..maxlength] of record element:TElement; next:integer; end;
对于一个表L,我们用一个整型变量Lhead作为L的表头游标。SPACE[Lhead]就是L的表头单元,其中的elemnt域是空的,next域中的游标指示L的第一个元素在数组SPACE中的存储地址(数组下标值)。这样,我们就可以用游标来模拟指针,实现单链表中的各种运算。照此,我们虽然是用数组来存储表中的元素,但在作表的插人和删除运算时,不需要移动元素,只要修改游标,从而保持了用指针实现表的优点。因此,有时也将这种用游标实现的表称为静态链表。
下面我们介绍用游标实现表的另一种方式。这种方式不用表头单元,因此在表的第一个位置进行插入或删除时,需要进行特殊处理。这与在单链表中不用表头单元的情形类似。设L是一个表。我们用Lhead指示L的第一个元素,即L的第一个元素存放于SPACE[Lhead].element中,而SPACE[Lhead].next为L的第二个元素所在单元的下标值。其后每个元素的后继元素所在单元以类似的方式给出。如果Lhead或者某单元中next域的值为0,则表示这是一个空指针,即该游标不指示任何单元。表L可以用它的表头变量Lhead来代表。由于表头变量是整型变量,所以表的类型为整型。位置变量类型TPosition也是整型。与单链表中位置变量的意义相类似。我们约定,当i>1时,表示第i个位置的位置变量pi的值是数组SPACE中存储表L的第i-1个元素的单元的下标值,即SPACE[pi].next是指示第i个元素在SPACE中的下标。当i=1时,pi=O。
类型定义如下:
Type TList=integer; TPosition=integer;
SPACE | |||||||||||||||||||||
|
图4 用游标实现表
在图4中,两个表L(包含元素依次为a,b,c)和M(包含元素依次为d,e)存放于同一数组SPACE中,其中的maxlength=10。数组SPACE中末被占用的所有单元组成了另一个表available,由这个表提供L和M的备用单元。当我们要在表L或M中插入一个元素时,所用的新单元就取自表available。反之,从两个表中删除的单元要回收(插入)到表available中备用。
初始时,我们将数组SPACE中所有单元链接成表available备用。这个过程可实现如下。
procedure Initialize; Var i:Integer; begin for i:=maxlength-l downto 1 do SPACE[i].next:=i+l; available:=1; {表available的第一个可用单元即表头在SPACE中的下标为1} SPACE[maxlength].next:=0; end; |
要在表L中插入一个元素x,可将表available的第一个单元摘除,并将这个备用单元插入L的适当位置,再将这个新单元的element域赋值为x。
procedure Insert(x:TElement;p:TPosition;var L:TLIST); begin if p=O then (在第一个位置插入) begin if move(available,L) then SPACE[L].element:=x else error; end else {不在第一个位置插入} if move(available,SPACE[p].next) then SPACE[SPACE[p].next].element:=x else error end; |
由于我们没有使用表头单元,所以必须单独处理在第一个位置插入的情形。另外,上述过程中用到了一个函数move(p,q),其功能是从某一链表中将游标p所指的单元C摘除,并将这个单元C插入到另一链表中游标q所指的单元之前,成功则返回true。我们可以先将q改为指向单元C,然后再将p改为指向单元C的下一单元,最后再将C中的游标改为指向q原来所指的单元即可。这个游标的修改过程如图5所示。
图5 两个链表之间的单元转移
图5中的实线和虚线分别表示单元转移前后的游标。当单元C存在时,函数move取值为true,并施行单元C的转移;当单元C不存在时,函数move取值为false。
function move(var p,q;integer):boolean; var temp:integer; begin if p=0 then return(false) e1se begin temp:=q; q:=p; p:=SPACE[p].next; SPACE[q].next:=temp; return(true); end end; |
要从表中删除位置p的元素,可以将L中位置p所指示的那个单元摘除,并将它插入表available的头一个位置备用。
procedrue Delete(p:TPosition;var L:TList); begin if p=O then move(L,available) else move(SPACE[p]^.next,available) end; |
与单链表中的情形类似,为要删除表L中的一个元素x,先要找到x在表L中的位置。这可以用下面的函数Locate来实现。在表L中找到第一个与x相同的元素时,Locate返回x所在单元的位置,否则返回表尾位置。
function Locate (x:TElement;L:TList):TPosition; Var p:TPosition; begin p:=L; if p=0 then error('List is empty.'); if SPACE[p].element=x then return(0); while SPACE[P].next<>0 do if SPACE[SPACE[P].next].element=x then return(p) else p:=SPACE[P].next; return(p); end; |
由于我们是用游标来模拟指针的,上述各运算的复杂性分析与单链表中的情形是类似的。另外,上述程序中都省略了检查错误的语句。
<script src="../../../lib/footer.js" type="text/javascript"> </script>