Delphi - TStack容量混乱
Delphi - TStack Capacity confusion
我一直在使用 TStack 尝试在我的程序中实现一个简单的 Undo/Redo 功能。这背后的想法是,当一个动作被执行时,程序的当前状态被保存——即被推入堆栈。当用户点击撤消时,程序的最后状态被重新加载——即从堆栈中弹出。
这个想法的缺陷是堆栈不能永远增长,这意味着在达到容量值后,最旧的项目(位于堆栈底部的项目)应该被删除,因为新项目被推到顶部.
Delphi 中的 TStack 对象包含一个容量 属性,我认为它会自动执行此 'clean-up' 但是当我使堆栈过载时(例如,将 11 个项目推入容量为 10 的项目) 容量更新以容纳更多物品。
任何人都可以就如何在这种情况下更有效地使用 TStack 向我提供任何建议吗?我知道另一种方法是使用数组结构,但我喜欢使用堆栈的预期易用性。
此致
实际上 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 方法,但我将其留给您,您应该能够从此处进行推断。
可用性评论
我不得不说,从用户体验的角度来看,我认为 undo/redo 函数的想法很糟糕。
为什么没有快照列表,你可以及时倒退和前进,就像你在磁盘上保存了一些备份文件的情况一样。
撤消功能要求您准确记住您在最后 x 个步骤中所做的操作,这并不能很好地扩展。
我也不明白为什么必须有一个限制,为什么不允许 undo/snapshots 与 memory/disk space 允许的一样多?
我一直在使用 TStack 尝试在我的程序中实现一个简单的 Undo/Redo 功能。这背后的想法是,当一个动作被执行时,程序的当前状态被保存——即被推入堆栈。当用户点击撤消时,程序的最后状态被重新加载——即从堆栈中弹出。
这个想法的缺陷是堆栈不能永远增长,这意味着在达到容量值后,最旧的项目(位于堆栈底部的项目)应该被删除,因为新项目被推到顶部.
Delphi 中的 TStack 对象包含一个容量 属性,我认为它会自动执行此 'clean-up' 但是当我使堆栈过载时(例如,将 11 个项目推入容量为 10 的项目) 容量更新以容纳更多物品。
任何人都可以就如何在这种情况下更有效地使用 TStack 向我提供任何建议吗?我知道另一种方法是使用数组结构,但我喜欢使用堆栈的预期易用性。
此致
实际上 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 方法,但我将其留给您,您应该能够从此处进行推断。
可用性评论
我不得不说,从用户体验的角度来看,我认为 undo/redo 函数的想法很糟糕。
为什么没有快照列表,你可以及时倒退和前进,就像你在磁盘上保存了一些备份文件的情况一样。
撤消功能要求您准确记住您在最后 x 个步骤中所做的操作,这并不能很好地扩展。
我也不明白为什么必须有一个限制,为什么不允许 undo/snapshots 与 memory/disk space 允许的一样多?