使用Pascal在链接列表中插入元素

时间:2013-11-20 04:24:05

标签: linked-list pascal freepascal

我已经看到一些算法设计用于在链接列表的末尾附加一个元素并浏览其他网站,然后我写了一个小程序,我相信它应该在列表的末尾添加一个给定元素但是它似乎不起作用。 我的问题是,为什么它不起作用?

我按如下方式定义了指针和节点:

 Pointer = ^Node;
Node = record
    about : element;
    next : Pointer;
end;

以下过程接收链接列表L和q元素,该元素应附加到L

的末尾

首先我定义我之后插入的记录

var INS : Poniter;
........
INS.about := q;

程序如下:

{temp := L}  {I'll use this for my attempt below }
if L<>NIL then
begin
  while L^.next<>NIL do
  begin 
  L:= L^.next;
  end;
  L^.next := INS;
  INS^.next := NIL; 
  {L:=temp;} {I'll explain this in my attempt below}
end
else
 begin
  L:= INS;
 end;

我还有一个小程序,可以打印链表的所有元素

 procedure displayElements(L : pointer);

 begin
  while L <> nil do
  begin
   writeln(L^.about);
   L := L^.next;
   end
 end;

问题:在我运行de program之后,它只显示列表的最后两个条目。

关于问题的猜想:我相信它只显示最后两个因为当我运行程序displayElements时,指针L已经是NIL之前的一个元素 - 因为我使用了第二个算法 - 。

尝试解决方案:好吧,我想我需要把L放回到第一个位置,这样当我使用displayElements时它会获得列表中的所有元素。但是我怎么能这样做?,我尝试了上面评论的内容,在临时保存L但是没有用。

有什么想法吗?感谢。

1 个答案:

答案 0 :(得分:4)

这是一个非常简单的程序,可以做你想要的。维护“尾部”指针意味着每次要添加值时都不必遍历列表。如果这是你的代码,那么你将错过插入中的'tail:= tmp'行:如果没有这个,Display会打印第一个和最后一个条目,但不会打印中间的条目。

type
 node = ^MyRec;
 MyRec = record
          value: integer;
          next: node
         end;

var
 head, tail: node;

Procedure Insert (v: integer);
var
 tmp: node;

begin
 new (tmp);
 tmp^.value:= v;
 tmp^.next:= nil;
 if head = nil
  then head:= tmp
  else tail^.next:= tmp;
 tail:= tmp;
end;

Procedure Display;
var
 tmp: node;

begin
 tmp:= head;
 while tmp <> nil do
  begin
   writeln (tmp^.value);
   tmp:= tmp^.next
  end;
end;

begin
 head:= nil;
 Insert (5);
 Insert (10);
 Display;
 Insert (15);
 Display;
 readln
end.

<强> [编辑]

根据您的意见判断,需要进一步解释。 [教授模式]当我三十年前开始编程时(OMSI Pascal在PDP 11/70上),链接列表和指针出现在每个自尊的程序中,但自从Delphi于1990年兴起以来,这些复杂性已被隐藏现在大多数程序员都看不到裸指针。

链接列表有不同的格式:简单和复杂。简单类型在插入和删除方面有所不同:堆栈在同一端插入和删除,一端插入队列,另一端删除,列表允许在任何地方插入和删除。更复杂的类型是树和图。您的问题是询问队列的实现 - 插入总是在后面,删除在前面。

为了正确实现这一点,我们需要两个变量:'head'指向队列的头部,'tail'指向队列的末尾。这些变量是正常的全局变量;在程序的数据段中为它们分配存储器。指针是一个简单变量,其值是另一个变量的内存地址。最初,'head'不指向任何东西,因此它的值为nil(将其视为0)。

通常在教科书中,队列的构造伴随着显示内存如何分配的小框,但我不知道如何在这里做到这一点,因此解释会有点罗嗦。

当第一次插入时,运行时系统中的内存管理器从堆中分配12个字节,并将局部变量'tmp'的值设置为第一个的地址12个字节(这是'new(tmp)')。在这12个字节中,'value'部分设置为5,'next'部分设置为nil。然后程序检查'head'的值是什么:如果它是nil,则将值(即上面分配的内存块的地址)从'tmp'复制到'head'。如果'head'已经指向某个东西,则'tmp'的值被复制到'tail ^ .next'(之前为零)。然后将'tmp'的值复制到tail变量。因此,'head'总是指向队列的开头并且不会改变,而'tail'指向队列的末尾,并且每次插入新节点时都会改变。

让我们做一些调试:

When the program starts, head = nil, tail is undefined
After 'insert (5)', head = $870874, tail = $870874
After 'insert (10)', head = $870874, tail = $870880 
After 'insert (15)', head = $870874, tail = $87088C

显示时,

tmp:= head ......... tmp = $870874  (ie head)
tmp:= tmp^.next .... tmp = $870880
tmp:= tmp^.next .... tmp = $87088C
tmp:= tmp^.next .... tmp = nil

如果您的程序有多个队列,那么每个队列需要两个变量,并且必须更改“Insert”才能接受两个参数(这将是给定队列的头部和尾部)

不需要编写'new(head)'和'new(tail)' - 这样做会导致丢失队列开头和结尾的原始指针。

[教授模式关闭]我希望这个解释有所帮助。