【问题标题】:Quicksort algorithm without data type无数据类型的快速排序算法
【发布时间】:2020-02-25 06:46:08
【问题描述】:

快速排序的大多数实现都处理 整数 数组的排序。因此,在具有固定数据类型的语言(例如 Pascal)中,需要修改算法才能对其他数组进行排序,例如 strings 数组。

这当然是一项简单的任务,除了在我们的数组应该采用的一组值上实现顺序关系之外,只需要稍作修改。然而,最好有一个万能的实现。

我的问题是:

问题:是否可以编写一个“快速排序帕斯卡单元”来对任何数组进行排序,无论是整数、字符串还是其他数组?

需要解决的主要困难是该单元将无法访问矩阵条目的数据类型。

【问题讨论】:

  • 没有。 Pascal 是强类型的。在不提前知道类型的情况下做到这一点的唯一方法是使用变体(需要大量开销)或泛型(同样涉及相当大的开销)。这些替代方案中的任何一个都会增加内存占用并减慢排序速度,这会破坏快速排序的整个目的。 Modern Pascal 允许您重载函数,这将允许您将每个数据类型的 QS 的实现放在同一个单元中,使用相同的名称,并让编译器根据参数确定使用哪个,但仅此而已。跨度>
  • @KenWhite 我不了解 Pascal 泛型,但我认为开销对于大多数应用程序来说应该不会那么糟糕。
  • @Phil1970:至少在 Delphi 中,无论是在生成的代码量还是在执行速度方面都是如此。 FreePascal 的泛型实现似乎比 Delphi 的差,所以我怀疑那里也存在额外的开销。
  • 如果您在 Google 上搜索 fpc generic "quicksort",您会发现排名前几位的搜索结果包括通用快速排序。如果您担心执行速度,我认为您需要自己进行基准测试。
  • 感谢@KenWhite 提到变体和泛型,我确信它们可以完成这项工作,但我的问题更多是在理论方面,关于是否可以用强类型语言实现快速排序(不一定只是 Pascal),同时不知道矩阵条目的类型。我想我找到了一个很好的答案,我将在下面发布。

标签: algorithm quicksort pascal


【解决方案1】:

提出问题通常会引发一个快速得出答案的心理过程,这是我刚刚发现的一个问题,我对此感到非常满意。

主要是要认识到快速排序算法只需要知道矩阵条目的类型即可:

  • 比较和
  • 交换

他们。因此,如果您为这些任务的执行提供替代方法,快速排序就足够了。

为了做到这一点,声明了一个“函数类型”orderRel,它接受两个整数(被认为是要比较的矩阵条目的索引)和一个“过程类型”copierProc(也接受两个索引, 并且意味着将一个矩阵条目复制到另一个。请参见下面的代码。

然后根据这些子例程专门实现快速排序单元,而调用程序则负责在数据类型的完整视图中实现orderRelcopierProc,这显然是知道的。然后这两个子例程作为参数传递给快速排序。

这是快速排序单元的完整实现,您将在下面找到完整的测试程序。两者都在“Free Pascal Compiler version 3.0.4+dfsg-18ubuntu2 [2018/08/29] for x86_64”中进行了测试。

{$R+}

unit Quicksort;

interface

type
  orderRel = function(i, j: longint): boolean;                (* Order relation for sorting *)
  copierProc = procedure(i, j: longint);                      (* Used to copy matrix entry i to entry j *)

procedure qsort(n: longint; less: orderRel; cp: copierProc);  (* Quicksort takes two functions as arguments *)

implementation

procedure qsort(n: longint; less: orderRel; cp: copierProc);

  var left, rght: longint;

  procedure qsort1(a, b: longint);
  begin
  cp((a+b) div 2, n+1); (* Position n+1 of the matrix used as pivot *)
  left:= a; rght:= b;
  while left <= rght do begin
    while less(left, n+1) do inc(left);
    while less(n+1, rght) do dec(rght);
    if left <= rght then begin
      cp(left, n+2); cp(rght, left); cp(n+2, rght); (* Position n+2 used as auxiliar variable for swapping *)
      inc(left); dec(rght);
      end;
    end;
  if left < b then qsort1(left, b);
  if a < rght then qsort1(a, rght);
  end;

begin
qsort1(1,n);
end;

end.

这是测试程序:

program Test; (* For testing unit quicksort *)

uses quicksort;

const
  N = 9;

(* Matrices to be sorted.  One of integers, the other of strings *)

var
  int_arr:  array[1..N+2] of integer; (* Quicksort needs two extra working slots, hence N+2 *)
  st_arr:   array[1..N+2] of string;

(* Next two subroutines to be fed to Quicksort when sorting integer matrices *)

function int_comparisson (i, j: longint): boolean;
begin
int_comparisson:= int_arr[i] < int_arr[j];
end;

procedure int_copy(i, j: longint);
begin
int_arr[j]:= int_arr[i];
end;

(* Next two subroutines to be fed to Quicksort when sorting matrices of strings *)

function st_comparisson(i, j: longint): boolean;
begin
st_comparisson:= st_arr[i] < st_arr[j];
end;

procedure st_copy(i, j: longint);
begin
st_arr[j]:= st_arr[i];
end;

var
  i: integer;

begin

(* Initialize integer matrix *)
for i:= 1 to N do int_arr[i]:= random(100);

qsort(N, @int_comparisson, @int_copy); (* Quicksort takes two functions as arguments *)

for i:= 1 to N do write(int_arr[i]:5);
writeln;

(* Initialize matrix of strings *)
st_arr[1]:= 'the';
st_arr[2]:= 'quick';
st_arr[3]:= 'brown';
st_arr[4]:= 'fox';
st_arr[5]:= 'jumps';
st_arr[6]:= 'over';
st_arr[7]:= 'the';
st_arr[8]:= 'lazy';
st_arr[9]:= 'dog';

qsort(N, @st_comparisson, @st_copy);

for i:= 1 to N do write(st_arr[i], ' '); writeln;

end.

PS:除了比较和交换,快速排序其实还需要 存储一个枢轴,它显然必须具有与另一个相同的类型 矩阵条目。而不是提供额外的变量来扮演角色 的枢轴,这将不可避免地需要矩阵类型 揭示,解决方案是允许快速排序访问一个未使用的矩阵 条目,例如条目 n+1。然后再使用一个条目,即 n+2,作为 交换的辅助变量。

【讨论】:

    最近更新 更多