簡単なリンクリストを作ろう

リンクリストには、単方向リンクリスト、双方向リンクリストなどがあります。ここでは、単方向リンクリストについてやってみます。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    btnAdd: TButton;
    btnShow: TButton;
    ListBox1: TListBox;
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure btnAddClick(Sender: TObject);
    procedure btnShowClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

  pMyRecord = ^TMyRecord;
  TMyRecord = record
    Name: string;
    Age: Integer;
    Next: pMyRecord;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  Start: pMyRecord;
  CurrentPosition: pMyRecord;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // 基点を生成。
  New(Start);
  Start^.Name := '基点です。';
  Start^.Age := 0;
  Start^.Next := nil;

  CurrentPosition := Start;
end;

procedure TForm1.btnAddClick(Sender: TObject);
var
  Current: pMyRecord;
begin
  New(Current);
  Current^.Name := Edit1.Text;

  if not TryStrToInt(Edit2.Text, Current^.Age) then
  begin
    ShowMessage('変換できません。');
    Dispose(Current);
    exit;
  end;

  Current^.Next := CurrentPosition;
  CurrentPosition := Current;

  ShowMessage('追加しました。');
end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  temp: pMyRecord;
begin
  ListBox1.Clear;

  temp := CurrentPosition;
  while temp^.Next <> nil do
  begin
    ListBox1.Items.Add(temp^.Name + ' ' +
                       IntToStr(temp^.Age));
    temp := temp^.Next;
  end;
  ListBox1.Items.Add(temp^.Name + ' ' +
                     IntToStr(temp^.Age));
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  temp: pMyRecord;
begin
  while CurrentPosition^.Next <> nil do
  begin
    temp := CurrentPosition^.Next;
    Dispose(CurrentPosition);
    CurrentPosition := temp;
  end;
  Dispose(CurrentPosition);
end;

end.

TMyRecord の中にそれ自身を指すポインタを持つ事で、レコードを次々に結び付けていっています。図にしますと以下のようになります。

基点となるレコードの Next には nil を指すようにしておくことがポイントです。

実行すると上記のようになります。

リストの挿入

つながっているリストの任意の間に、新たなリストを挿入してみましょう。サンプルは、以下のようになります。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    btnInsert: TButton;
    btnShow: TButton;
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure btnShowClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnInsertClick(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

  pMyRecord = ^TMyRecord;
  TMyRecord = record
    Name: string;
    Age: Integer;
    Next: pMyRecord;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  Start,
  CurrentPosition: pMyRecord;

procedure Init;
begin
  New(Start);
  Start^.Name := 'Hello0';
  Start^.Age := 0;
  Start^.Next := nil;

  CurrentPosition := Start;
end;

procedure SetUp;
var
  Current: pMyRecord;
  i: Integer;
begin
  for i := 0 to 3 do
  begin
    New(Current);
    Current^.Name := 'Hello' + IntToStr(i+1);
    Current^.Age := 2 * (i);
    Current^.Next := CurrentPosition;

    CurrentPosition := Current;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Init;
  SetUp;
end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  temp: pMyRecord;
begin
  ListBox1.Clear;

  temp := CurrentPosition;
  while temp^.Next <> do
  begin
    ListBox1.Items.Add(temp^.Name + ' ' +
                       IntToStr(temp^.Age));
    temp := temp^.Next;
  end;
  ListBox1.Items.Add(temp^.Name + ' ' +
                     IntToStr(temp^.Age));
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  temp: pMyRecord;
begin
  while CurrentPosition^.Next <> nil do
  begin
    temp := CurrentPosition^.Next;
    Dispose(CurrentPosition);
    CurrentPosition := temp;
  end;
  Dispose(CurrentPosition);
end;

procedure TForm1.btnInsertClick(Sender: TObject);
var
  insert: pMyRecord;
  temp: pMyRecord;
begin
  New(insert);
  insert^.Name := 'world';
  insert^.Age := 11;

  temp := CurrentPosition;

  insert^.Next := temp^.Next.Next;
  temp^.Next.Next := insert;
end;

end.

図で表しますと、以下のようになります。

リストの間に挟みこむような感じになっています。

ちゃんと挿入されているようです。

リストの削除

リストの削除のサンプルです。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    btnDelete: TButton;
    btnShow: TButton;
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure btnShowClick(Sender: TObject);
    procedure btnDeleteClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

  pMyRecord = ^TMyRecord;
  TMyRecord = record
    Name: string;
    Age: Integer;
    Next: pMyRecord;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  Start,
  CurrentPosition: pMyRecord;

procedure Init;
begin
  New(Start);
  Start^.Name := 'Hello0';
  Start^.Age := 0;
  Start^.Next := nil;

  CurrentPosition := Start;
end;

procedure SetUp;
var
  Current: pMyRecord;
  i: Integer;
begin
  for i := 0 to 3 do
  begin
    New(Current);
    Current^.Name := 'Hello'+IntToStr(i+1);
    Current^.Age := 2*i;
    Current^.Next := CurrentPosition;

    CurrentPosition := Current;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  init;
  SetUp;
end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  temp: pMyRecord;
begin
  ListBox1.Clear;

  temp := CurrentPosition;
  while temp^.Next <> do
  begin
    ListBox1.Items.Add(temp^.Name + ' ' +
                       IntToStr(temp^.Age));
    temp := temp^.Next;
  end;
  ListBox1.Items.Add(temp^.Name + ' ' +
                     IntToStr(temp^.Age));
end;

procedure TForm1.btnDeleteClick(Sender: TObject);
var
  delete: pMyRecord;
begin
  delete := CurrentPosition^.Next;

  CurrentPosition^.Next := CurrentPosition^.Next.Next;
  Dispose(delete);
  
  btnDelete.Enabled := false; // 複数回押されるのを防ぐ
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  temp: pMyRecord;
begin
  while CurrentPosition^.Next <> nil do
  begin
    temp := CurrentPosition^.Next;
    Dispose(CurrentPosition);
    CurrentPosition := temp;
  end;
  Dispose(CurrentPosition);
end;

end.

リストの挿入の場合と同様な考え方で、削除を行います。

btnDelete ボタンを押してから、btnShow ボタンを押すと上記のようになります。


up next
Last update: 2002/11/1