链表2

一、链表

链表是这样的一种线性表,它的元素由数据和指针两部分组成,数据部分存放结点的有关信息,指针部分存放下一个结点的位置。

二、单链表及其基本操作

在链式存储结构的线性表中,数据元素的存储空间一般是不连续的。链式存储结构懂得线性表由若干个结点组成,每个结点组成,每个结点有两个域:一个是数据域;另一个是指针域。单链表的定义如下:

type

  pointer=^nodetype;

nodetype=record

   data:datatype;

   next:pointer;

end;

var head:pointer;

head为表的首指针,指向链表的第一个结点。有时在链表的第一个结点前附设一个结点,该结点称为“哨兵”,head指向“哨兵”。整个链表的存取必须从head指针出发,沿着每个结点的next指针顺序进行,最后一个结点的next指针为“空”(nil)。如下图所示:

                            存储地址                数据域                指针域

                              1                       li                      29

                              5                       sun                     9

                              9                       qian                     1

                              13                      wu                      nil

                              17                      wang                    25

                              21                      zhou                     5

                              25                      zhao                     13

                              29                      zheng                    17

 

 

 

 

 

 

 

 

 

 

 

 

在单链表中每个结点的存储地址是可以任意分配,即表中元素的存储位置可以不连续且是无序的,而它们的逻辑顺序由链表中的next指针确定;假设线性表a1a2,…,an采用单链表的存储结构,其中p指针指向ai的结点,则p^.next指针指向值为ai+1的结点。也就是说,p^.data=ai,p^.next^.data=ai+1

单链表操作

1)动态建立单链表

设线性表a1a2,…,an。试建立其单链表存储结构,其中head指向单链表的“哨兵”。

procedure creatlink(var head:pointer);

  begin

head:=nil;

for i:=n downto 1 do

  begin

     new(p);

     p^.data=a[i];

     p^.next:=head;

     head:=p;

end;

new(p);

p^.next:=head;

head:=p;

  end;

(2)插入操作

在单链表的第i个结点前插入元素x0head为指向哨兵的首指针。

procedure insertlink(x:datatype;i:integer;var head:pointer);

  begin

new(s);

s^.data:=x;

p:=head;j:=0;

while (p<>nil) and (j<i-1) do

  begin

    p:=p^.next;

    j:=j+1;

  end;{while}

if p<>nil

  then begin

        s^.next:=p^.next;

        p^.next:=s;

      end{then}

  else writeln(‘without’);

  end;

(3)删除操作

head为指向“哨兵”的首指针。删除单链表的第i个结点。

procedure delelink(i:integer;var head:pointer);

  begin

p:=head;j:=0;

while (p^.next<>nil) and (j<i-1) do

  begin

    p:=p^.next;

    j:=j+1;

  end;{while}

if p^.next=nil

  then writeln(‘without’)

    else begin

         q:=p^.next;

         p^.next:=p^.next^.next;

         dispose(q);

        end;{else}

 end;

(4)读取单链表元素

head为指向“哨兵”的首指针。读取单链表中的第i个数据元素。

function getlink(i:integer;var head:pointer):datatype;

  begin

p:=head^.next;j:=1;

while (p<>nil) and (j<i) do

  begin

    p:=p^.next;

    j:=j+1;

  end;{while}

if p=nil

  then writeln(‘without’)

  else geglink:=p^.data;

  end;

二、双向循环链表及其基本操作

以上讨论的单链表的结点中,只有一个指示后继结点的指针域next。因此,从某个结点出发,只能顺着next指针往后寻找其他结点。若要寻找某结点的直接前趋,则需从“哨兵”head出发。另外,对于空表与第一个结点的处理必须单独考虑,使得空表与非空表的运行不统一。为了克服这些缺点,引入了双向循环链表。

所谓双向循环链表,就是链表的结点中有两个指针域,一个指向直接后继(next),另一个指向直接前趋(priou);并且在双向循环链表中,“哨兵”的data为任意或者根据需要设置,next域指向线性表的第一个结点,priou域指向线性表的最后一个结点,哨兵指针指向“哨兵”;双向循环链表中最后一个结点的next域指向“哨兵”,即在双向循环链表中,所有结点的指针构造了一个环状链。如下图所示:

 

 

 

 

 

 

 

双向循环链表的基本操作:

1)构造双向循环链表L

假设线性表中有n个数据元素a1a2,…,an。试建立一个双向循环链表存储结构,L为双向循环链表的哨兵:

procedure creat_list(var L:dupointer);

  begin

    new(L);L^.next:=L;L^.priou:=L;q:=L;

    for i:=1 to n do

      begin

        new(p);p^.data:=a[i];

        q^.next:=p;

        p^.priou:=q;q:=p;

      end;{for}

    q^.next:=L;L^.priou:=q;

  end;

(2)读取双向循环链表中第i个结点的地址

L “哨兵”的双向循环链表中,确定第i个结点的地址。若i>表长,返回nil;若i=表长+1,则返回哨兵指针L

function geg_list(i,L):dupoiniter;

  begin

    p:=L^.next;j:=1;

    while (p<>L) and (j<i) do

      begin

        p:=p^.next;j:=j+1;

      end;{while}

    if j=i then get_list:=p

        else get_list:=nil;

  end;

(3)插入操作

在双向循环链表L的位置p处插入一个新元素x的过程insert可实现如下 :

procedure insert(x:datatype;p:dupointer;var L:tlist);

  var

    q:dupointer;

  begin

    new(q);

    q^.data:=x;

    q^.priou:=p^.priou;

    q^.next:=p;

    p^.priou^.next:=q;

    p^.priou:=q;

 end;

上述算法对链表指针的修改情况如下图所示:

 

 

 

 

 

 

 

 

 

 

 

算法insert中没有检查位置p的合法性,因此在调用insert之前应保证位置p的合法性。 由于插入通常是在表的头尾两 端进行的,所以容易检查位置p的合法性。

4)删除操作

在双向循环链表中,删除位置p处的元素操作可实现如下:

procedure delete(p:dupointer;var L:tlist);

  begin

if (p<>nil) and (p<>L) then

  begin

    p^.priou^.next:=p^.next;

    p^.next^.priou:=p^.priou;

    dispose(p);

  end;

  end;

上述算法对链表指针的修改情况如下图所示:

 

 

 

 

 

 

 

与单链表中的删除算法类似,上述算法是在已知要删除元素在链表中的位置p时,将该位置所指的单元删去。若要从一个表中删除一个元素x但不知道它在表中的位置,则应先用定位函数Locate(x,L)找出要删除元素的位置,然后再用delete删除之。

5)定位函数

在双向循环链表中,定位函数Locate可实现如下:

function Locate(x:datatype;L:tlist):dupointer;

  var

p:dupointer;

  begin

p:=L^.next;

while p<>L do

  if p^.data=x then return(p)

            else p:=p^.next;

return(nil);

  end;

 

 

posted @ 2010-10-11 20:55  lj_cherish  阅读(273)  评论(0编辑  收藏  举报