2011-10-26 59 views
9

Tôi sử dụng TList/TObjectList và TStringList (với các đối tượng liên quan) cho nhiều nhiệm vụ, hoặc là, hoặc làm cơ sở cho các cấu trúc phức tạp hơn. Mặc dù chức năng sắp xếp thường đủ tốt, đôi khi tôi cần phải thực hiện loại phân loại stable và cả hai danh sách đều sử dụng quicksort.Cách dễ dàng để thêm phân loại ổn định vào TList và TStringList

Cách dễ nhất để triển khai phân loại ổn định cho TList và/hoặc TStringList là gì? Tôi có phải viết thói quen phân loại của riêng tôi, hoặc nó có thể được thực hiện bằng cách sử dụng một số thủ thuật thông minh với TStringListSortCompare/TListSortCompare?

+1

Xem thêm: http://stackoverflow.com/questions/9303488/how-can-i-replace-stringlist-sort-with-a-stable-sort-in-delphi – lkessler

Trả lời

5

Bạn sẽ phải viết thường trình sắp xếp của riêng mình.

Bạn có thể đọc triển khai QuickSort hiện tại và viết phiên bản ổn định của riêng bạn (ví dụ: sắp xếp Hợp nhất hoặc any other stable variant).

Một số thủ thuật:

  • Nếu bạn chắc chắn rằng một chỉ số là < Count, bạn có thể sử dụng các mảng con trỏ nhanh (TList.List[]) thay vì chậm Items[] hoặc GetItem(): tiểu phương pháp gọi điện thoại và dao động kiểm tra chậm việc thi hành;
  • Chức năng so sánh là phần lớn thời gian tắc nghẽn tốc độ của tìm kiếm - vì vậy hãy quan tâm đến phần này;
  • Nếu bạn cần tốc độ, hãy sử dụng hồ sơ thực sự trên dữ liệu thực (ví dụ: ngẫu nhiên) - nhưng hãy thực hiện ngay trước khi thực hiện nhanh;
  • Bắt đầu từ việc triển khai sắp xếp hiện tại;
  • Để giảm thiểu không gian ngăn xếp, bạn có thể sử dụng một bản ghi tạm thời để lưu trữ và chia sẻ các biến trong số các cuộc gọi đệ quy.
+0

Tôi nghĩ mình phải viết của riêng mình , nhưng phải hỏi. Tôi đã hy vọng cho một số "ma thuật" lừa :-) Hãy đến để suy nghĩ về nó, không phải là nó lạ Borland/Embarcadero đã không làm cho TList.Sort ổn định? Tôi không có chuyên gia, nhưng tôi tin rằng có những thuật toán phân loại với hiệu suất tương tự như quicksort và vẫn còn sử dụng bộ nhớ khá khiêm tốn. Ah, tốt. –

+0

Theo như tất cả các cuốn sách nói, QuickSort là một thuật toán sắp xếp nổi tiếng cùng một lúc nhanh chóng, dễ dàng để mã và gỡ lỗi, và sử dụng bộ nhớ thấp. Các biến thể ổn định (như loại hợp nhất hoặc chèn) phức tạp hơn và không cung cấp hiệu suất tốt hơn. Việc sắp xếp trong VCL không đòi hỏi phải ổn định, do đó QuickSort là ứng cử viên tốt nhất cho việc thực hiện phân loại mục đích chung. –

3

Câu hỏi này là khá cũ, nhưng ở đây đi câu trả lời của tôi cho độc giả trong tương lai: tôi cũng cần này thời gian gần đây và điều chỉnh việc thực hiện tìm thấy trong cuốn sách "The Tomes của Delphi thuật toán và cấu trúc dữ liệu" bởi Julian Bucknall. Thực hiện cho TList, TObjectList và các lớp hậu duệ. Nó hoạt động với Delphi 2009 đến XE7 và các phiên bản khác có lẽ cũng như: http://alexandrecmachado.blogspot.com.br/2015/02/merge-sort-for-delphi.html

+0

Tuyệt vời! Cảm ơn, người đàn ông. Tuy nhiên, tôi lưu ý rằng không có bài kiểm tra đơn vị nào. Bạn tự tin rằng mã đó vững chắc đến mức nào? Bạn có sử dụng nó trong mã sản xuất không? –

+0

Tôi đã viết một số bài kiểm tra đơn vị, và tiếc là sắp xếp không có vẻ hoàn toàn ổn định: (Tôi sẽ đăng bài kiểm tra lên blog của bạn. –

+1

Có lỗi trong mã gốc. Cảm ơn bạn đã tìm kiếm và thông báo. cố định và có, tôi sẽ sử dụng nó trong sản xuất Đây là thông tin về vấn đề và sửa lỗi: http://alexandrecmachado.blogspot.com.br/2015/03/merge-sort-for-delphi-revisited. html – Alexandre

0

Từ câu hỏi tương tự How Can I Replace StringList.Sort with a Stable Sort in Delphi?, liên kết ở đây trong bình luận của lkessler tôi cần phải sao chép vào đây thực sự dễ lừa như đã đề cập trong câu hỏi.

Bạn có thể dễ dàng sắp xếp nhanh chóng hoạt động ổn định bằng cách thêm số thứ tự ban đầu vào dữ liệu để sắp xếp và thêm điều kiện so sánh cuối cùng trong hàm so sánh CustomSort để so sánh số thứ tự ban đầu này.

Dễ dàng, nhanh chóng và thông minh. Chi phí chỉ thêm một số nguyên (hoặc byte, hoặc sử dụng một số lưu trữ dành riêng như TComponent.Tag nếu bạn sắp xếp TComponents) trên mỗi mục có thể sắp xếp và một vòng lặp khởi tạo trên chúng.

TObjectToSort = class 
    ... 
    Index: Integer; 
end; 

function MyStableSortComparer(List: TStringList; Index1, Index2: Integer): Integer; 
var 
    o1, o2: TObjectToSort; 
begin 
    o1 := TObjectToSort(List.Objects[Index1]); 
    o2 := TObjectToSort(List.Objects[Index2]); 
    ... 
    if Result = 0 then 
    Result := o1.Index - o2.Index; 
end; 


for i := 0 to MyStrtingList.Count - 1 do 
    TObjectToSort(MyStrtingList.Objects[i]).Index := i; 
MyStrtingList.CustomSort(MyStableSortComparer); 
0

Đối với bất kỳ ai sử dụng generics ở đây là việc triển khai sẵn sàng chèn và sắp xếp hợp nhất, cả hai thuật toán phân loại ổn định.

uses Generics.Defaults, Generics.Collections; 

type 
    TMySort = class 
    public 
    class procedure InsertionSort<T>(AArray: TArray<T>; FirstIndex, LastIndex: Integer; const AComparer: IComparer<T>); static; 
    class procedure MergeSort<T>(AArray: TArray<T>; FirstIndex, LastIndex: Integer; const AComparer: IComparer<T>); static; 
    end; 

implementation 

class procedure TMySort.InsertionSort<T>(AArray: TArray<T>; FirstIndex, LastIndex: Integer; const AComparer: IComparer<T>); 
var 
    UnsortedIdx, CompareIdx: Integer; 
    AItem: T; 
begin 
    for UnsortedIdx := Succ(FirstIndex) to LastIndex do begin 
    AItem := AArray[UnsortedIdx]; 
    CompareIdx := UnsortedIdx - 1; 
    while (CompareIdx >= FirstIndex) and (AComparer.Compare(AItem, AArray[CompareIdx]) < 0) do begin 
     AArray[CompareIdx + 1] := AArray[CompareIdx]; { shift the compared (bigger) item to the right } 
     Dec(CompareIdx); 
    end; 
    AArray[CompareIdx + 1] := AItem; 
    end; 
end; 

class procedure TMySort.MergeSort<T>(AArray: TArray<T>; FirstIndex, LastIndex: Integer; const AComparer: IComparer<T>); 
const 
    MinMergeSortLimit = 16; 
var 
    LeftLast, RightFirst: Integer; 
    LeftIdx, RightIdx, SortedIdx: Integer; 
    LeftCount: Integer; 
    TmpLeftArray: TArray<T>; 
begin 
    if (LastIndex - FirstIndex) < MinMergeSortLimit then 
    { sort small chunks with insertion sort (recursion ends here)} 
    TMySort.InsertionSort<T>(AArray, FirstIndex, LastIndex, AComparer) 
    else begin 
    { MERGE SORT } 
    { calculate the index for splitting the array in left and right halves } 
    LeftLast := (FirstIndex + LastIndex) div 2; 
    RightFirst := LeftLast + 1; 
    { sort both halves of the array recursively } 
    TMySort.MergeSort<T>(AArray, FirstIndex, LeftLast, AComparer); 
    TMySort.MergeSort<T>(AArray, RightFirst, LastIndex, AComparer); 
    { copy the first half of the array to a temporary array } 
    LeftCount := LeftLast - FirstIndex + 1; 
    TmpLeftArray := System.Copy(AArray, FirstIndex, LeftCount); 
    { setup the loop variables } 
    LeftIdx := 0; { left array to merge -> moved to TmpLeftArray, starts at index 0 } 
    RightIdx := RightFirst; { right array to merge -> second half of AArray } 
    SortedIdx := FirstIndex - 1; { range of merged items } 
    { merge item by item until one of the arrays is empty } 
    while (LeftIdx < LeftCount) and (RightIdx <= LastIndex) do begin 
     { get the smaller item from the next items in both arrays and move it 
     each step will increase the sorted range by 1 and decrease the items still to merge by 1} 
     Inc(SortedIdx); 
     if AComparer.Compare(TmpLeftArray[LeftIdx], AArray[RightIdx]) <= 0 then begin 
     AArray[SortedIdx] := TmpLeftArray[LeftIdx]; 
     Inc(LeftIdx); 
     end else begin 
     AArray[SortedIdx] := AArray[RightIdx]; 
     Inc(RightIdx); 
     end; 
    end; 
    { copy the rest of the left array, if there is any} 
    while (LeftIdx < LeftCount) do begin 
     Inc(SortedIdx); 
     AArray[SortedIdx] := TmpLeftArray[LeftIdx]; 
     Inc(LeftIdx); 
    end; 
    { any rest of the right array is already in place } 
    end; 
end; 

Việc triển khai cũng được thực hiện cho các mảng và áp dụng cho TList/TObjectList (vì thuộc tính Hạng mục của chúng là một mảng).

var 
    AList: TList<T>; 
    AComparer: IComparer<T>; 
begin 
    ... 
    TMySort.MergeSort<T>(AList.List, 0, AList.Count-1, AComparer); 
    ... 
end; 

Bên cạnh việc ổn định, theo kinh nghiệm của tôi, sắp xếp hợp nhất thực hiện điều này cho thấy hiệu suất tốt hơn so với xây dựng trong sắp xếp nhanh chóng (mặc dù nó sử dụng bộ nhớ nhiều hơn).

Các vấn đề liên quan