Tlist刪除技巧

2022-08-22 09:15:08 字數 2673 閱讀 2470

二、    從tlist開始分析……

為了寫乙個更好的效能isapi filter,我需要更快速地從tlist中刪除部分連續的item。比如這樣的一段**:

var p : pchar = 'abcdefgh';
procedure testdelfromtlist;
var t1 : tlist;
i  : integer;
maxi : integer;
begin
t1 := tlist.create;
t1.count := 100000;
for i:=0 to t1.count-1 do t1[i] := p;
maxi := t1.count-10-1; //最後乙個結點
for i:= maxi downto 10 do t1.delete(i);
//正向刪除
//for i:=10 to t2.count-10-1 do t2.delete(10);
end;

這段**是初始化乙個100000個結點的list,然後刪除其中的第10個到倒數第10個。這段**是逆向的,這樣的刪除速度比較快。如果換成正向刪除(已經注釋掉),則速度就慢得非常多了。

這樣的刪除是正常的演算法。用測效率的程式測試:逆向刪除演算法的耗時是21.66個毫秒,則正向刪除的耗時卻能達到58099.02個毫秒。速度慢了2680倍!!!

但這樣就很快了麼?不是!我認為就算是逆向刪除的速度也並不是快的。

分析tlist這個類的原始碼,我們可以看到,它是這樣寫的(我加入了注釋):

procedure tlist.delete(index: integer);
var
temp: pointer;
begin
if (index < 0) or (index >= fcount) then //判定index值是否超界
error(@slistindexerror, index);
temp := items[index];                        //取待刪除結點
dec(fcount);                                   //count減一
if index < fcount then                       //將待刪除結點後的buffer提前
system.move(flist^[index + 1], flist^[index],(fcount - index) *
sizeof(pointer));
if temp <> nil then                           //發通告
notify(temp, lndeleted);
end;

由於在tlist類是將全部的結點指標存放在flist這個動態陣列的指標中,所以只需要將index+1之後的記憶體塊向前移4個位元組,即sizeof(pointer),即可實現index結點的刪除。

但是,如果使用這樣來刪除成批連續的(n個)結點,則要實現n次system.move()操作,操作的記憶體塊的大小決定了system.move()操作的耗時,而index值越小的的結點在flist中越靠前,則system.move()要操作的記憶體塊也就越大。這就是我認為上述成批刪除效率不高的原因,也是正向刪除比逆向刪除的耗時慢了慢了2680倍的原因。

對於成批刪除,理想的演算法是從index+len結點開始位置,向前移動count-index-len個結點,這樣,就能夠一次完成全部的結點移動,實現刪除操作。這個思路非常好,至少我認為是這樣。為此,我實現了下面的**:

procedure cutlist(alist:tlist; left,len:integer);
begin
with alist do begin
system.move(list^[left+len], list^[left], (count-left-len) *
sizeof(pointer));
count := count-len;
end;
end;

這段**的功能是在tlist.list這個buffer中,將刪除後的剩餘結點直接移動到left這個位置上,從而完成全部的移動操作。

然後,我們再設count := count-len;來使用個數減少,從而完成了成批量的刪除。

好的,如果一切正常,演算法的速度將大幅度提公升!ohhh,美妙的想法!

但是,真的是這樣麼?我再用效率測試程式來測試了一輪,結果是這樣的:

1.測試資料為10萬個結點,則逆向刪除演算法耗時為20.56毫秒,cutlist()函式耗時9.69毫秒;

2.測試資料為100萬個結點,則逆向刪除演算法耗時為209.13毫秒,cutlist()函式耗時98.01毫秒。

速度比逆向演算法提高了一倍,而且應該注意到,cutlist()的耗時仍然隨資料量的增大而等比例的增大!!!而從cutlist()函式的實現來看,資料量增大,演算法耗時應該只增加極少才對。

要知道,只加快一倍速度的cutlist(),並不是我所想要的!!!但為什麼cutlist()函式得不到更高的效能呢???

Delphi中TList類應用

在delphi中指標最常見的就是和類tlist結合起來使用。下面是乙個很簡單的例子,希望對這個例子的分析能讓大家對使用tlist類有乙個簡單的認識。的功能是使用指標和tlist來生成乙個牌串,並將牌串儲存在t cardinfo中。procedure tform1.button1click sende...

Delphi中TList類應用

在delphi中指標最常見的就是和類tlist結合起來使用。下面是乙個很簡單的例子,希望對這個例子的分析能讓大家對使用tlist類有乙個簡單的認識。的功能是使用指標和tlist來生成乙個牌串,並將牌串儲存在t cardinfo中。procedure tform1.button1click sende...

學習 TList 類的實現 2

我原來以為 tlist 可能是乙個鍊錶,其實只是乙個陣列而已.你知道它包含著多大乙個陣列嗎?maxlistsize 個 maxlistsize 是 delphi 在 classes 單元定義的乙個常量 maxlistsize maxint div 16 也就是 134217727 這也是 tlist...