【问题标题】:Invalid pointer operation; Recursive Merge Sort无效的指针操作;递归合并排序
【发布时间】:2018-01-18 23:16:58
【问题描述】:

我尝试为字符串实现合并排序,但是我无法执行递归部分,并且收到错误“无效指针操作”

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var i : Integer;
const MyArray : array[1..5]of string = ('hi', 'zebra', 'apple', 'Xylophone', 'dog');

Procedure merge(result, left, right : array of string);
var i, i1, i2 : Integer;
begin
  i1 := 0;
  i2 := 0;
  for i := 0 to Length(result) do
  begin
    if (i2 >= Length(right)) or (i1 < Length(left)) and (StrComp(PChar(left[i]), PChar(right[i2])) < 0) then
    begin
      result[i] := left[i1];
      inc(i1);
    end
    else
    begin
      result[i] := right[i2];
      inc(i2);
    end;
  end;
end;


Procedure mergeSort(OriginalList : array of string);
var left, right : array of string;
    i : Integer;
begin
  if (Length(OriginalList) >= 2) then
  begin
    setlength(left, length(OriginalList) div 2);
    setlength(right, length(OriginalList) - (length(OriginalList) div 2));
    for i := 0 to Length(left) do
    begin
      left[i] := OriginalList[i];
    end;
    for i := 0 to Length(right) do
    begin
      right[i] := OriginalList[i + Length(OriginalList) div 2];
    end;
    mergeSort(left);
    mergeSort(right);
    merge(OriginalList, left, right);
  end;
end;

begin
  writeln('The data before sorting: ');
  for i := low(MyArray) to High(MyArray) do
  begin
    write(MyArray[i]+' ');
  end;
  writeln;
  mergeSort(MyArray);
  writeln('The data before sorting: ');
  for i := low(MyArray) to High(MyArray) do
  begin
    write(MyArray[i]+' ');
  end;
  readln;
end.

在 mereSort 函数的行中,我记得数组“left”和“right”上的合并排序函数,我收到错误消息,但我不太明白为什么?

【问题讨论】:

  • 在调试器中单步执行代码时会看到什么?
  • @KenWhite 我完全忘了逐步完成我的程序......我很抱歉。我已经意识到我不认为它首先正确地设置了左右数组,因为我可以看到变量包含的内容。 youtu.be/tUC1rGFJIzk
  • 请记住,合并排序对于小集合是非常低效的,这就是为什么大多数有效的合并排序实现在元素数量较少时使用插入排序。因此,您开始递归地使用归并排序,但是当您的左/右数组变小时,您切换到插入排序来完成该过程。根据我的经验,这个“神奇”数字介于 8 到 32 个元素之间,但可能会有所不同。
  • 您忘记调试程序了?来吧。
  • @DavidHeffernan Yeh 我知道是对的.. :( 我是自学的,对此很陌生:D

标签: delphi recursion mergesort delphi-xe


【解决方案1】:

这有很多不同的地方,希望这些点能帮助你朝着正确的方向前进。

数组索引问题

您的索引超出了数组的末尾: 动态数组从零开始索引,所以行

    for i := 0 to Length(left) do

应该是

    for i := 0 to Length(left) - 1 do

或者你可以使用

   for i := Low(left) to High(left) do

正如你后来所做的那样。

我会建议你选择一个标准的形式并一致地使用它,并且除非你有充分的理由,否则你避免使用基于非零的索引声明常量数组,这样你可以一致地使用相同的形式或更改类型阵列以后不会遇到麻烦

第一次修复将阻止您的程序崩溃,但您会注意到您的排序代码没有改变任何内容...

参数传递问题

Delphi 有几种不同的方式将参数传递到过程中:

procedure doSomething(a : array of string);
procedure doSomething(var a : array of string);
procedure doSomething(out a : array of string);
procedure doSomething(const a : array of string);

这些决定了过程内部发生的事情如何影响传递的原始变量

这是您需要了解的内容,请在文档中阅读: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Parameters_(Delphi)

IMO 有一些与数组参数相关的非常令人困惑的行为和语法,而且很多看起来直观的东西是不允许的,尤其是在 XE/旧版本中,值得阅读有关标准数据类型的文档

在当前状态下,您的合并过程将不起作用,因为它只对您传入的数组的新副本进行操作,您也将其声明为常量

其他

我会避免使用result 作为过程参数,因为这是用于函数返回值的名称,这样使用它似乎是在自找麻烦。

PS:合并的逻辑我没看,只是基本的语言错误

【讨论】:

  • 哇非常感谢您的详细分析。我一定会通读一遍并回复你,但现在我在哪里已经很晚了,但我真的很感谢你的时间和帮助
  • 行为不是很混乱。您应该知道,您的所有示例都是开放数组参数,而不是动态数组。更多关于这里的信息:Open array parameters and array of const.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2021-11-06
  • 2019-01-22
相关资源
最近更新 更多