【问题标题】:Why is this MergeSort implementation not stable?为什么这个 MergeSort 实现不稳定?
【发布时间】:2012-09-13 16:49:56
【问题描述】:

我在网上找了几个归并排序算法,把这个贴在一起。它携带索引以保留元素之前所在的信息。但事实证明,当我输入一个在每个元素处具有相同值的数组时,索引会被打乱。我需要使用其他合并方法吗?

procedure TMSortNode.MergeSort(values, indices: TMValueArrayPtr; L, R: Integer);
var
  i, j, k, m : Integer;

begin
If (l < r) Then
begin
m:= (r+l) div 2;

MergeSort(values, indices, l, m );
MergeSort(values, indices, m+1, r );

For i:= l To m Do
begin
  FValueBuffer[i]:= values^[i];
  FIndexBuffer[i]:= indices^[i];
end;
i:= l;

For j:= m+1 To r Do
begin
  FValueBuffer[r+m+1-j]:= values^[j];
  FIndexBuffer[r+m+1-j]:= indices^[j];
end;
j:= r;

For k:= l To r Do
begin
  If (FValueBuffer[i] <= FValueBuffer[j]) Then
  begin
    values^[k]:= FValueBuffer[i];
    indices^[k]:= FIndexBuffer[i];
    inc(i);
  end
  else
  begin
    values^[k]:= FValueBuffer[j];
    indices^[k]:= FIndexBuffer[j];
    dec(j);
     end;
    end;
  end;
end;

编辑:

这是正确的稳定合并部分:

length := r-l+1;
For i:= 0 To length-1 Do
begin
  FValueBuffer[i]:= values^[l+i];
  FIndexBuffer[i]:= indices^[l+i];
end;

j := 0;
k := m-l+1;

for i := 0 to length-1 do
if k < length then
  begin
  if j <= m-l then
  begin
    if FValueBuffer[j] > FValueBuffer[k] then begin
      values^[l+i] := FValueBuffer[k];
      indices^[l+i] := FIndexBuffer[k];
      inc(k)
    end else begin
      values^[l+i] := FValueBuffer[j];
      indices^[l+i] := FIndexBuffer[j];
      inc(j);
    end;
  end
  else
  begin //only upper Entrys left
    values^[i+l] := FValueBuffer[k];
    indices^[i+l] := FIndexBuffer[k];
    inc(k);
  end;
end else begin //only superior Entrys left
  values^[i+l] := FValueBuffer[j];
  indices^[i+l] := FIndexBuffer[j];
  inc(j);
end;

【问题讨论】:

    标签: delphi sorting stability


    【解决方案1】:

    试试

    如果 (FValueBuffer[i] FValueBuffer[j]) 那么 ...

    (为了保持稳定,我们不能交换相等的物品)

    编辑:

    另一个问题:标准合并看起来像:

    1. 当左右部分都包含未处理的项目时,将最小的项目移动到新位置
    2. 移动未处理部分的其余部分(如果存在)

    例子:

    procedure Merge(var c, d: array of Integer; l, m, r: Integer);
     var
       i, j, k: Integer;
     begin
       i := l;
       j := m;
       k := l;
       while (i < m) and (j <= r) do
         if c[i] <= c[j] then begin
           d[k] := c[i];
           Inc(k);
           Inc(i);
         end
         else begin
           d[k] := c[j];
           Inc(k);
           Inc(j);
         end;
       while i < m do begin
         d[k] := c[i];
         Inc(k);
         Inc(i);
       end;
       while k <= r do begin
         d[k] := c[j];
         Inc(k);
         Inc(j);
       end;
      end;
    

    但是您的第一个变体超出了左右部分边界(为避免这种情况,可以使用具有额外价值的哨兵物品 - 这需要额外的努力和位置)。

    好像第二个版本考虑到了这个问题

    【讨论】:

    • 好提示!这好多了,但它仍然有一些移动的索引......有什么想法吗?
    猜你喜欢
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多