2016-09-07 31 views
2

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

这个想法的缺陷是,堆栈无法继续增长,这意味着在达到容量值后,最旧的项目(堆栈底部的项目)应该被删除,因为新项目被推到最上面。

Delphi中的TStack对象包含一个Capacity属性,我认为它会自动执行此“清理”,但当我重载堆栈时(例如,将11个项目推送到一个具有capcity 10的项目)容量更新以适应更多项目。

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

问候

+0

也许更容易使用队列和队列中最后一个添加项目的指示器。这样你会有重做选项。 –

+0

堆栈不会为你工作。放弃。这是错误的数据结构。也许你正在寻找一个deque。或者只是使用固定长度的数组创建自己的。数组变满时使用循环索引。 –

+0

对不起,但是'Capacity'属性,正如您发现的那样,会自动增加。他与所有'TOrderedList'派生的集合对象相同。也没有设定强迫它不成长。您可以使用'OnNotify'事件来检查是否已达到您的限制,如果有必要,请根据需要更改内容。 –

回答

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; 

显然,你需要一些更多的方法,如最后和删除的方法,但我留给你的,你应该能够从这里推断。

可用性言论
我不得不说,从UX角度来看,我认为撤销/重做功能的想法很烂。
为什么不能有一个快照列表,你可以及时往回转移,就像在磁盘上保存了大量备份文件一样。
撤消功能要求您准确记住您所做的最后x个步骤,这些步骤不能很好地缩放。
我也不明白为什么必须有一个限制,为什么不允许尽可能多的撤消/快照内存/磁盘空间允许?