Delphi - TStack容量混乱

时间:2016-09-07 10:10:45

标签: arrays delphi stack undo redo

我一直在与TStack合作,尝试在我的程序中实现一个简单的撤销/重做功能。这背后的想法是,当执行动作时,程序的当前状态被保存 - 即被推送到堆栈。当用户单击撤消时,程序的最后状态被重新加载 - 即从堆栈中弹出。

这个想法的缺陷是堆栈不能永远增长,这意味着在达到容量值之后,当新项目被推到顶部时,应该删除最旧的项目(堆栈底部的项目)。

Delphi中的TStack对象包含一个Capacity属性,我假设它会自动执行此'清理',但是当我重置堆栈时(例如,将11个项目推送到具有城市10的项目),容量会更新以容纳更多项目。

在这种情况下,有人可以提供有关如何更有效地使用TStack的任何建议吗?我知道另一种方法是使用数组结构,但我喜欢使用堆栈的前瞻性。

此致

1 个答案:

答案 0 :(得分:3)

实际上TStack由动态数组驱动 如果你真的想要你可以滥用这个事实让堆栈从底部移除物品,但现在你要对抗堆栈。

我认为使用循环列表更好。

简单的设计可能会像这样工作。

type
  TCircularList<T> = class(TObject);
  private
    FStorage: TList<T>;
    FCapacity: cardinal;  //duplication for performance reasons
    FCurrentIndex: cardinal;
  protected
    function GetItem(index: cardinal): T;
    procedure SetItem(index: cardinal; const Value: T);
  public
    constructor Create(Size: cardinal = 10);
    destructor Destroy; override;
    procedure Add(const Item: T);
    property Items[index: cardinal]: T read GetItem write SetItem; default;
  end;

constructor TCircularList<T>.Create(Size: cardinal = 10);
begin
  inherited Create;
  Assert(Size >= 2);
  FStorage:= TList<T>.Create;
  FCapacity:= Size;
  FStorage.Capacity:= Size;
end;

destructor TCircularList<T>.Destroy;
begin
  FStorage.Free;
  inherited;
end;

procedure TCircularList<T>.Add(const Item: T);
begin
  FCurrentIndex:= (FCurrentIndex + 1) mod FCapacity;
  FStorage[FCurrentIndex]:= Item;
end;

function TCircularList<T>.GetItem(index: cardinal): T;
var
  cIndex: cardinal;
begin
  cIndex:= Index mod FCapacity;
  Result:= FStorage[index]; 
end;

procedure TCircularList<T>.SetItem(index: cardinal; const Value: T);
var
  cIndex: cardinal;
begin
  cIndex:= index mod FCapacity;
  FStorage[index]:= Value;
end;

显然你需要更多的方法,比如last和delete方法,但我把它留给你,你应该能够从这里推断出来。

可用性评论
我不得不说,从用户体验的角度来看,我认为撤销/重做功能的想法很糟糕 为什么没有快照列表,您可以及时前进和后转,就像您在磁盘上保存了大量备份文件一样。 撤消功能要求您准确记住您在最后的x步骤中所做的事情,这些步骤不能很好地扩展 我也不明白为什么必须有限制,为什么不允许尽可能多的内存/磁盘空间允许的撤消/快照?