radixsort.pas

来自「用delphi实现的一些排序算法」· PAS 代码 · 共 206 行

PAS
206
字号
{-----------------------------------------------------------------------------



  作者:hujiping 2006.05.30
  备注:
  审核:RadixSort 基数排序

  Copyright (c) 1994-2006 GrandSoft Corporation

-----------------------------------------------------------------------------}
unit RadixSort;

interface

uses
  Classes;

type
  PNode = ^TNode;
  TNode = record
    Data: Pointer;
    Next: PNode;
  end;

  TRadixSort = class
  private
    FHead: PNode;
    FTail: PNode;
    FNodeArr: array of PNode;
    ENodeArr: array of PNode;
    procedure FreeNodes;
    procedure RadixSortA(ASequence: Integer; ARadix: Integer; ADigit: Integer);
  public
    destructor Destroy; override;
    procedure RadixSort(AList: TList; ARadix: Integer; ADigit: Integer);

  end;
implementation

uses SysUtils;

{ TRadixSort }
destructor TRadixSort.Destroy;
begin
  FreeNodes;
  inherited;
end;

{-----------------------------------------------------------------------------
  作者:hujp 2006.05.31
  参数:
  返回:
  功能:释放分配的内存
-----------------------------------------------------------------------------}
procedure TRadixSort.FreeNodes;
var
  pNext: PNode;
begin
  if FHead = nil then Exit;
  pNext := FHead.Next;
  while FHead <> nil do
  begin
    Dispose(FHead);
    FHead := pNext;
    if FHead <> nil then
      pNext := FHead.Next
  end;
end;

{-----------------------------------------------------------------------------
  作者:hujp 2006.05.31
  参数:
  返回:
  功能:基数排序
-----------------------------------------------------------------------------}
procedure TRadixSort.RadixSort(AList: TList; ARadix, ADigit: Integer);

  {-----------------------------------------------------------------------------
    作者:hujp 2006.05.31
    参数:
    返回:
    功能:根据AList建立队列
  -----------------------------------------------------------------------------}
  procedure BuildQueue;
  var
    I: Integer;
    Node, NextNode: PNode;
  begin
    if AList.Count = 0 then Exit;
    New(FHead);
    FHead.Data := AList.Items[0];
    Node := FHead;
    for I := 1 to AList.Count - 1 do
    begin
      NextNode := AllocMem(Sizeof(TNode));
      NextNode.Data := AList.Items[I];
      Node.Next := NextNode;
      Node := NextNode;
    end;
    FTail := Node;
  end;

  {-----------------------------------------------------------------------------
    作者:hujp 2006.05.31
    参数:
    返回:
    功能:根据队列返回AList
  -----------------------------------------------------------------------------}
  procedure OutputQueue;
  var
    Node: PNode;
  begin
    AList.Clear;
    Node := FHead;
    while Node <> nil do
    begin
      AList.Add(Node.Data);
      Node := Node.Next;
    end;
  end;

var
  I: Integer;
begin
  SetLength(FNodeArr, ARadix);
  SetLength(ENodeArr, ARadix);
  BuildQueue;
  for I := ADigit downto 1 do
    RadixSortA(I, ARadix, ADigit);
  OutputQueue;
end;

{-----------------------------------------------------------------------------
  作者:hujp 2006.05.31
  参数:
  返回:
  功能:对第ASequence位进行排序
-----------------------------------------------------------------------------}
procedure TRadixSort.RadixSortA(ASequence, ARadix, ADigit: Integer);

  {-----------------------------------------------------------------------------
    作者:hujiping 2006.05.30
    参数:
    返回:
    功能:得到ANode中Data的第ASequence位所对应的数字(0<= Result < Radix)
  -----------------------------------------------------------------------------}
  function GetDigitNumber(ASequence: Integer; ADigit: Integer; ANode: PNode): Integer;
  var
    I: Integer;
    sNum: string;
    sZeros: string;
  begin
    sNum := IntToStr(Integer(ANode.Data));
    //位数不足,在前面补0
    if Length(sNum) < ADigit then
    begin
      SetLength(sZeros, ADigit - Length(sNum));
      for I := 1 to ADigit - Length(sNum) do
        sZeros[I] := '0';
    end;
    sNum := sZeros + sNum;
    Result := StrToInt(sNum[ASequence]);
  end;

var
  I: Integer;
  CircleNode: PNode;
  nDigitNum: Integer;
begin
  //清除辅助数组
  for I := 0 to ARadix - 1 do
    FNodeArr[I] := nil;
  //把主队列中节点加入到辅助数组中
  CircleNode := FHead;
  while CircleNode <> nil do
  begin
    nDigitNum := GetDigitNumber(ASequence, ADigit, CircleNode);
    if FNodeArr[nDigitNum] = nil then
      FNodeArr[nDigitNum] := CircleNode
    else
      ENodeArr[nDigitNum].Next := CircleNode;
    ENodeArr[nDigitNum] := CircleNode;
    CircleNode := CircleNode.Next;
  end;
  //把辅助数组中节点按序加回到主队列中
  I := 0;
  while FNodeArr[I] = nil do
    Inc(I);
  FHead := FNodeArr[I];
  FTail := ENodeArr[I];
  FNodeArr[I] := nil;
  for nDigitNum := I + 1 to ARadix - 1 do
  begin
    if FNodeArr[nDigitNum] <> nil then
    begin
      FTail.Next := FNodeArr[nDigitNum];
      FTail := ENodeArr[nDigitNum];
      FNodeArr[nDigitNum] := nil;
    end;
  end;
  FTail.Next := nil;
end;

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?