精品一区二区三区影院在线午夜_天天躁日日躁狠狠躁AV麻豆_国产午夜福利短视频_中文字幕乱偷无码AV先锋蜜桃_久久精品一二区东京热_国产成人亚洲日韩欧美久久久,国产成人精品久久一区二区三区

Delphi : TStringList的Find,IndexOf和Sort

關鍵:Find要事先Sort排序,Indexof不用排序。

TStringList內部查找相關的數據。待調試代碼時才知道痛苦,浪費無數時間后,只得一步步跟蹤,才發

現Find方法返回的Index總是錯誤的,當時一陣郁悶,隨手按下F1鍵,Find的Help文檔展現眼前,對于該

函數是這樣描述的:

Locates the index for a string in a sorted list and indicates whether a string with that

value already exists in the list.

在Note部分又再次強調:

Only use Find with sorted lists. For unsorted lists, use the IndexOf method instead.

只怪自己一時懶惰,在不了解的情況下便拋棄習慣了的IndexOf,輕易使用新函數。但同時我也來了興趣,為什么Find只能在使用TStringList.Sort方法后才能正常返回數據呢?

老辦法,直接跳到Classes文件中查看源代碼:

function TStringList.Find(const S: string; var Index: Integer): Boolean;

var

L, H, I, C: Integer;

begin

Result := False;

L := 0;

H := FCount - 1;

while L <= H do

begin

I := (L + H) shr 1;

C := CompareStrings(FList^[I].FString, S);

if C < 0 then L := I + 1

else begin

H := I - 1;

if C = 0 then

begin

Result := True;

if Duplicates <> dupAccept then L := I;

end;

end;

end;

Index := L;

end;

還是被嚇了一跳,怎么感覺這么復雜,仔細一看才明白,原來是個折半查找算法。呵呵。

L,H變量分別代表Low和High,(L + H) shr 1就是求中間值的,完全等于(L + H) div 2,對于二進制,

右移一位就相當于整除2。其中CompareStrings是用來對比兩個字符串大小的:

function TStringList.CompareStrings(const S1, S2: string): Integer;

begin

if CaseSensitive then

Result := AnsiCompareStr(S1, S2)

else

Result := AnsiCompareText(S1, S2);

end;

這里的CaseSensitive用來標記是否大小寫敏感,AnsiCompareStr是大小寫敏感的,AnsiCompareText則

反之。另外在Help文檔中還特地說明了兩個函數進行判斷時,小寫字符是小于大寫字符的,比如'a'<'A'

。請注意,這一點是與ASCII不相同的地方(如果再跟下去,你可以發現這兩個函數是對API的一個封裝,

而且封裝了Linux和Windows的兩個版本)。

此時我們返回到Find函數本身,又會發現在判斷條件中只有C<0和C=0的情況,也就是說它只能搜索升序

排列的StringList。

忍不住,再看了看Sort方法。

procedure TStringList.Sort;

begin

CustomSort(StringListCompareStrings);

end;

簡單的不能再簡單,一行語句。CustomSort是一個公共方法,供用戶使用自定義的比較規則進行排序。

StringListCompareStrings參數中放置的就是自定義比較規則的函數:

TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer;

CustomSort的代碼如下:

procedure TStringList.CustomSort(Compare: TStringListSortCompare);

begin

if not Sorted and (FCount > 1) then

begin

Changing;

QuickSort(0, FCount - 1, Compare);

Changed;

end;

end;

Changing和Changed主要是用來觸發FOnChanging和FOnChanged的,具體內容可以自己看代碼。而

QuickSort則是使用快速排序算法和用戶自定義的比較規則進行排序了,再跟入到QuickSort代碼中:

procedure TStringList.QuickSort(L, R: Integer; SCompare: TStringListSortCompare);

var

I, J, P: Integer;

begin

repeat

I := L;

J := R;

P := (L + R) shr 1;

repeat

while SCompare(Self, I, P) < 0 do Inc(I);

while SCompare(Self, J, P) > 0 do Dec(J);

if I <= J then

begin

ExchangeItems(I, J);

if P = I then

P := J

else if P = J then

P := I;

Inc(I);

Dec(J);

end;

until I > J;

if L < J then QuickSort(L, J, SCompare);

L := I;

until I >= R;

end;

哈哈,正是這一段

while SCompare(Self, I, P) < 0 do Inc(I);

while SCompare(Self, J, P) > 0 do Dec(J);

使得TStringList是按照升序排列。至此,大致原因弄明白了。

再看看IndexOf是如何實現搜索的,剛開始我認為它肯定是使用For循環遍歷每個Item,遇到相同的內容

則跳出循環,結果發現它確實也是這么做的,只是中間做了一些優化,假如StringList已經排序過,它

會自動使用效率更高的Find方法進行查找,另外它使用Result作為循環變量,對資源的利用極其充分。

代碼如下:

function TStringList.IndexOf(const S: string): Integer;

begin

if not Sorted then Result := inherited IndexOf(S) else

if not Find(S, Result) then Result := -1;

end;

其中繼承使用了父類TStrings中的IndexOf方法

function TStrings.IndexOf(const S: string): Integer;

begin

for Result := 0 to GetCount - 1 do

if CompareStrings(Get(Result), S) = 0 then Exit;

Result := -1;

end;

這段代碼中的Get方法在TStrings中則是純虛函數。

function Get(Index: Integer): string; virtual; abstract;

純虛函數怎么能用,倒。那既然能用,只有一個可能,就是子類TStringList中實現了Get方法。返回到

TStringList中,在果然看到以下代碼:

function TStringList.Get(Index: Integer): string;

begin

if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index);

Result := FList^[Index].FString;

end;

他用來取得指定行的字符串。分析也就此結束。

》》》》》》》》》》》》》》》》》》》》》》》》》》》》

Find是折半查找,速度應當是最快了,而indexof默認是 for 輪回所有item了。 但find應用前必須先排序 sort 不然返回 index錯誤。

示例如下:

var lst:TStringList ;

i:Integer ;

begin

lst:=TStringList.Create ;

try

lst:=TStringList.Create ;

lst.CaseSensitive :=true;

lst.Delimiter :="","";

lst.DelimitedText :=Edit1.Text ;

ShowMessage(IntToStr(lst.IndexOf(Edit2.Text) ));

lst.Sort ;

if lst.Find(Edit2.Text ,i) then

ShowMessage(IntToStr(i));

finally

lst.Free ;

end;

eidt2 內容 如下字符串 010a,010A,200a,200b,905a

红桥区| 宜黄县| 清苑县| 云和县| 西畴县| 灵寿县| 芜湖县| 乳源| 大方县| 资中县| 嘉鱼县| 昭平县| 邯郸市| 涞源县| 正宁县| 白山市| 青铜峡市| 团风县| 海口市| 金昌市| 临泽县| 固安县| 武清区| 揭西县| 海丰县| 十堰市| 土默特右旗| 庆安县| 嘉黎县| 九台市| 桃园县| 周宁县| 鄱阳县| 于田县| 民丰县| 威远县| 连平县| 昌平区| 齐河县| 汕头市| 三台县|