2016-09-07 2 views
2

저는 TStack으로 작업하여 내 프로그램에서 간단한 실행 취소/다시 실행 기능을 구현했습니다. 이것의 뒤에있는 생각은 액션이 수행 될 때 프로그램의 현재 상태가 저장된다는 것입니다. 즉, 스택으로 푸시됩니다. 사용자가 실행 취소를 클릭하면 프로그램의 마지막 상태가 다시로드됩니다. 즉 스택에서 팝됩니다.Delphi - TStack 용량 혼동

이 아이디어의 결함은 스택이 계속 증가 할 수 없다는 것입니다. 용량 값에 도달하면 가장 오래된 항목 (스택 맨 아래에있는 항목)이 새 항목이 맨 위에 푸시 될 때 제거되어야한다는 것을 의미합니다.

Delphi의 TStack 객체에는이 '정리'를 자동으로 수행한다고 가정하는 Capacity 속성이 있지만 스택에 과부하 (예 : 11 개 항목을 capcity 10으로 푸시)하면 용량이 더 많은 항목을 수용하도록 업데이트됩니다. .

누군가이 인스턴스에서 TStack을보다 효과적으로 사용하는 방법에 대한 조언을 해 줄 수 있습니까? 대안으로 배열 구조를 사용하는 것이지만 스택을 사용하는 것이 쉽다는 것을 알고 있습니다. 현실에서는 TStack

안부

+0

대기열에 마지막으로 추가 된 항목이있는 표시기와 대기열을 사용하는 것이 더 쉽습니다. 그렇게하면 다시 할 수있는 옵션이 생깁니다. –

+0

스택이 작동하지 않습니다. 포기하다. 잘못된 데이터 구조입니다. 당신은 아마도 deque를 찾고 있습니다. 또는 고정 길이 배열을 사용하여 직접 만들 수도 있습니다. 배열이 가득 차게되면 순환 색인을 사용하십시오. –

+0

유감스럽게도, 'Capacity'속성은 알게 되듯이 자동으로 증가합니다. 그의 모든 TOrderedList 파생 컬렉션 객체들과 동일하다. 또한 성장하지 않도록 강제하는 설정도 없습니다. 'OnNotify' 이벤트를 사용하여 자신의 한도에 도달했는지 확인하고, 그렇다면 필요에 따라 내용을 변경할 수 있습니다. –

답변

3

은 동적 배열에 의해 강화된다.
정말로이 사실을 악용하여 스택이 아래쪽에서 항목을 제거하도록 만들 수 있지만 이제는 스택과 싸우게 될 것입니다.

원형 목록을 사용하는 것이 좋습니다.

간단한 디자인이 이와 같이 작동 할 수 있습니다.

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 단계를 수행 한 것을 정확히 기억해야합니다.
한계가 있어야하는 이유를 이해하지 못합니다. 왜 메모리/디스크 공간 허가만큼 실행 취소/스냅 샷을 허용하지 않습니까?