回 帖 发 新 帖 刷新版面

主题:插入排序法链接实现

期末的信息技术考砸了,原来是一道插入排序法的顺序实现忘记了,被扣掉了30分。

究其原因是插入排序法的数组实现太烂,QB是垃圾(没有指针)~~~~~~~~~~~~~~~~~~~

个人认为插入排序法用顺序实现不是很好的办法,因为插入的过程中要移动一大堆连续的数据,显然用数组实现(一个一个移动)是很费时的。若用链表则可以省下很多时间,源码如下(pascal):

一、单向链表实现:

program lian;
type
  pt=^node;
  node=record                        {记录体,有两个域:值和后继指针}
     value:integer;
     next:pt;
    end;
var
  x:integer;
  p,q,h,k,y,z:pt;
procedure create(var head:pt);             {建表}
  begin
    new(head);
    writeln('Create');
    p:=head;
    readln(x);
    while x<>0 do
    begin
      new(q);
      q^.value:=x;
      p^.next:=q;
      p:=q;
      readln(x);
    end;
    p^.next:=nil;
  end;
procedure print(head:pt);               {打印链表}
  begin
    writeln('print');
    p:=head;
    while p^.next<>nil do
    begin
      writeln(p^.next^.value);
      p:=p^.next;
    end;
    readln;
  end;
begin
  create(h);
  k:=h^.next^.next;  {k为抓起的牌,初始化k为第二个数}
  y:=h^.next;        {因为单向链表的缺陷,所以需要记录k的前趋y}
  while k<>nil do    {排序主循环体}
  begin
    p:=h^.next;      {p为要比较的数}
    z:=h;            {z为p的前趋}
    while k^.value>p^.value do   {移动前定位}
    begin
      z:=z^.next;                 {若p<k,p取后一位的值,继续定位}
      p:=p^.next;
    end;
    if p<>k then                  {若属要移动}
    begin
      y^.next:=k^.next;           {把k从原位挤出}
      z^.next:=k;                 {这两句把k插入到p的前面}
      k^.next:=p;
      k:=y^.next;                 {k取后一位,继续循环}
    end
    else                          {若不用移动}
    begin
      k:=k^.next;                 {k取后一位,继续循环}
      y:=y^.next;
    end;
  end;
  print(h);
end.

二、双向链表实现:

program lian2;
type
  pt=^node;
  node=record               {记录体,有三个域:前趋、值和后继}
        ahead:pt;
        value:integer;
        next:pt;
    end;
var
  x:integer;
  p,q,he,la,v,k:pt;
procedure create(var head,last:pt);{建表,以head为头last为尾}
  begin
    new(head);
    writeln('Create');
    p:=head;
    read(x);
    while x<>0 do
    begin
      new(q);
      q^.value:=x;
      p^.next:=q;
      q^.ahead:=p;
      p:=q;
      read(x);
    end;
    new(last);
    p^.next:=last;
    last^.ahead:=p;
  end;
procedure print(head,last:pt;flag:boolean);{打印链表flag决定顺打和逆打}
  begin
    writeln('print');
    if flag then                  {顺打,从头到尾}
    begin
      p:=head;
      while p^.next<>last do
      begin
        writeln(p^.next^.value);
        p:=p^.next;
      end;
    end
    else                          {逆打,从尾到头}
    begin
      p:=last;
      while p^.ahead<>head do
      begin
        writeln(p^.ahead^.value);
        p:=p^.ahead;
      end;
    end;
  end;

begin             {main}
  create(he,la);
  k:=he^.next^.next;             {k为抓起的牌,初始为第二个值}
  while k<>la do                 {排序主循环}
  begin
    p:=he^.next;                 {p为比较的牌,每次循环初始为第一个值}
    v:=k^.next;                  {由于k可能会移动,记下k的位置}
    while k^.value>p^.value do   {移动前定位}
      p:=p^.next;                {若p<k,p取后一位的值,继续定位}
    if p<>k then                 {若要移动}
    begin
      k^.ahead^.next:=k^.next;   {这两句把k从原位挤出}
      k^.next^.ahead:=k^.ahead;
      p^.ahead^.next:=k;         {这四句把k插入到新位置}
      k^.ahead:=p^.ahead;
      p^.ahead:=k;
      k^.next:=p;
    end;
    k:=v;                        {k取后一位的值,继续循环}
  end;
  print(he,la,true);
  {打印链表,这里是顺打,升序;你可以用false来逆打,降序}
end.

回复列表 (共7个回复)

沙发

好帖,能从多方面来考虑。顶!顶!

板凳

谢谢楼上支持~~~~~~~~~~~~~~~~

3 楼

又沉下去了~~~~~~~~~~~~~~

4 楼

我现在还看不懂,,,,,不过很快我会看懂的~~~~

5 楼

其实这很简单。楼上的只要稍微了解一点链表的操作,然后熟知插入排序法的顺序实现(用数组实现)的过程(自己看初二的信息技术书),就不难理解了~~~~~~~~~~~~~~~

6 楼

这里为了方便大家理解,把该方法的顺序实现(Pascal)也发上来,大家可以作对比,比较顺序实现和链接实现:

program shunxu;
var
  a:array[1..1000]of integer;        {要排序的静态数组}
  k,p,j,x,n:integer;               {这里的p,k与链接实现的p,k对应}
begin      {main}
  readln(n);
  for i:=1 to n do readln(a[i]);      {读入n个待排序数}
  for k:=2 to n do        {k为抓起的牌,也就是要插入到原有有序数列的数}
  begin
    p:=1;                       {p为要比较的数(插入指针)每次循环初始为1}
    x:=a[k];                    {把a[k]放到x里,以后使用}
    while a[k]>a[p] do p:=p+1;  {排序前定位,a[k]>a[p]时插入指针后移一位
            此循环结束后p就是k要插入的位置}
    for j:=k-1 downto p do a[j+1]:=a[j];{在完成定位后把p后的有序数队后移
      一位,给k腾出空间。这里就可以看出顺序实现的劣势,它需要把(k-1-p)个数
   一个一个移动,费时;而链接实现只需改变k和p的前趋和后继指针即可完成移动,
   因此省下很多时间}
    a[p]:=x;                     {在大量移动后把k的值插入}
  end;{for}
  for i:=1 to n do writeln(a[i]);    {输出排序好的数列}
  readln
end;

7 楼

链表占空间较多
不过有自己的优点啦
某些时候用链表还是不错啦
不过也不一定要移动
运用父子结点不行吗?

我来回复

您尚未登录,请登录后再回复。点此登录或注册