Delphi 如何在tlistview中获取已排序的项目?
有一个列表视图,其中包含大约10000个已排序的项目(用于搜索): 下一个binsearch函数的目的是查找以st开头的所有项目(此处例如ab),然后将以st开头的所有项目输出到另一个文件。首先,我们使用二进制搜索并快速查找其中一个ab项,然后使用线性搜索尝试查找二进制搜索找到的ab项之前和之后的所有ab项。我们测试了二进制搜索的部分,效果很好。以下函数中的二进制搜索将返回ab项之一。 如果有多个ab项,binsearch函数将返回所有ab项并正确输出。 如果只有一个ab项,则以下函数中的二进制搜索部分可以找到它(已插入断点和提示符以进行跟踪),但输出未找到该项。问题可能在这个函数的线性搜索部分,不知道为什么Delphi 如何在tlistview中获取已排序的项目?,delphi,Delphi,有一个列表视图,其中包含大约10000个已排序的项目(用于搜索): 下一个binsearch函数的目的是查找以st开头的所有项目(此处例如ab),然后将以st开头的所有项目输出到另一个文件。首先,我们使用二进制搜索并快速查找其中一个ab项,然后使用线性搜索尝试查找二进制搜索找到的ab项之前和之后的所有ab项。我们测试了二进制搜索的部分,效果很好。以下函数中的二进制搜索将返回ab项之一。 如果有多个ab项,binsearch函数将返回所有ab项并正确输出。 如果只有一个ab项,则以下函数中的二进制
function TForm1.binsearch(lv: tlistview; st: string): integer;
var
L, R, M: Integer;
p: integer;
cap, wholecap: string;
CompareResult: Integer;
alist, newlist: tlistitem;
fresult: integer;
newresult: integer;
found: boolean;
begin
Result := -1;
cap := '';
wholecap := '';
L := 0;
R := lv.items.Count - 1;
M := (L + R) div 2;
wholecap := lv.Items[m].caption;
p := pos(' ', wholecap);
cap := trim(copy(wholecap, 0, p));
CompareResult := Comparestr(cap, st);
while (compareresult <> 0) and (l <= r) do begin
if CompareResult > 0 then begin
R := M - 1;
end;
if CompareResult < 0
then begin
L := M + 1;
end;
M := (L + R) div 2;
wholecap := lv.Items[m].caption;
if pos(' ', wholecap) > 0 then
p := pos(' ', wholecap);
cap := trim(copy(wholecap, 0, p));
CompareResult := Comparestr(cap, st);
end;
fresult := m;
result := m;
newresult := m;
// Above is ok, we can find that item starting with st(here, e.g. ab),
// The above binary search can find the item starting with ab regardless of the
// number of ab items.
// That is to say: ab item maybe one or maybe more than one.
// hmmtemplistview below is another listview.
// *** Below is linear search part, trying to find the one(s) that precedes or
// follows the one that binary search found.
alist := lv.Items[fresult];
wholecap := alist.caption;
if pos(' ', wholecap) > 0 then
p := pos(' ', wholecap);
cap := trim(copy(wholecap, 0, p));
if cap = st then
found := true;
while (fresult >= 0) and found = true do begin
newlist := hmmtemplistview.Items.Insert(0);
newlist.Caption := wholecap;
hmmtemplistview.items.Item[0] := alist;
dec(fresult);
if fresult < 0 then begin
break;
end;
alist := lv.Items[fresult];
wholecap := alist.caption;
p := pos(' ', wholecap);
cap := trim(copy(wholecap, 0, p));
if cap <> st then
begin
found := false;
end;
end;
if result <> -1 then
newresult := result + 1;
alist := lv.Items[newresult];
wholecap := alist.caption;
if pos(' ', wholecap) > 0 then
p := pos(' ', wholecap);
cap := trim(copy(wholecap, 0, p));
if cap = st then
found := true;
while (newresult >= 0) and found = true do begin
newlist := hmmtemplistview.Items.Insert(0);
newlist.Caption := wholecap;
hmmtemplistview.items.Item[0] := alist;
inc(newresult);
if newresult > lv.Items.Count then begin
break;
end;
alist := lv.Items[newresult];
wholecap := alist.caption;
p := pos(' ', wholecap);
cap := trim(copy(wholecap, 0, p));
if cap <> st then
begin
found := false;
end;
end;
end;
// Output result is:
// if there is more than one ab items (2 or 3 or 4 items starting with ab), the
// function output all ab items correctly.
// If there is only one ab item (an item starting with ab), the function output NONE.
// Why is it?
函数TForm1.bin搜索(lv:tlistview;st:string):整数;
变量
五十、 R,M:整数;
p:整数;
帽,全帽:弦;
比较结果:整数;
列表,新列表:tlistitem;
结果:整数;
新结果:整数;
发现:布尔型;
开始
结果:=-1;
上限:='';
全图:='';
L:=0;
R:=lv.items.Count-1;
M:=(左+右)第二分区;
全图:=lv.Items[m]。标题;
p:=位置('',整体图);
封顶:=修剪(复制(整体封顶,0,p));
比较结果:=比较结果(cap,st);
而(比较结果0)和(l 0)则开始
R:=M-1;
结束;
如果比较结果<0
然后开始
L:=M+1;
结束;
M:=(左+右)第二分区;
全图:=lv.Items[m]。标题;
如果pos('',全图)>0,则
p:=位置('',整体图);
封顶:=修剪(复制(整体封顶,0,p));
比较结果:=比较结果(cap,st);
结束;
结果:=m;
结果:=m;
新结果:=m;
//以上是确定的,我们可以找到以st开头的项目(这里,例如ab),
//上述二进制搜索可以找到以ab开头的项,而不考虑
//ab项目的数量。
//也就是说:ab项可能是一个或多个。
//下面的hmmtemplistview是另一个列表视图。
//***下面是线性搜索部分,尝试查找在或之前的部分
//跟随二进制搜索找到的一个。
列表:=lv.项目[fresult];
wholecap:=alist.caption;
如果pos('',全图)>0,则
p:=位置('',整体图);
封顶:=修剪(复制(整体封顶,0,p));
如果cap=st,则
发现:=真;
而(fresult>=0)和found=true则开始
newlist:=hmmtemplistview.Items.Insert(0);
newlist.Caption:=wholecap;
hmmtemplistview.items.Item[0]:=alist;
dec(fresult);
如果fresult<0,则开始
打破
结束;
列表:=lv.项目[fresult];
wholecap:=alist.caption;
p:=位置('',整体图);
封顶:=修剪(复制(整体封顶,0,p));
如果是圣
开始
发现:=假;
结束;
结束;
如果结果为-1,则
newresult:=结果+1;
列表:=lv.Items[newresult];
wholecap:=alist.caption;
如果pos('',全图)>0,则
p:=位置('',整体图);
封顶:=修剪(复制(整体封顶,0,p));
如果cap=st,则
发现:=真;
而(newresult>=0)和found=true则开始
newlist:=hmmtemplistview.Items.Insert(0);
newlist.Caption:=wholecap;
hmmtemplistview.items.Item[0]:=alist;
公司(newresult);
如果newresult>lv.Items.Count,则开始
打破
结束;
列表:=lv.Items[newresult];
wholecap:=alist.caption;
p:=位置('',整体图);
封顶:=修剪(复制(整体封顶,0,p));
如果是圣
开始
发现:=假;
结束;
结束;
结束;
//输出结果为:
//如果有多个ab项目(2个或3个或4个以ab开头的项目),则
//函数正确输出所有ab项。
//如果只有一个ab项(以ab开头的项),则函数输出NONE。
//为什么?
我不知道我上面说的是否清楚?
用简单的英语来说,这是一个明确的问题吗?我没有看过你的全部代码,但二进制搜索部分完全错了。你需要一个二进制搜索算法来找到满足搜索条件的第一个条目:
L := 0;
R := lv.items.Count-1;
while L < R do begin
M := (L + R) div 2;
wholecap:=lv.Items[m].caption;
p:=pos(' ',wholecap);
cap:=copy(wholecap, 1, p - 1);
if Comparestr(cap, st) < 0
then L := M + 1
else R:= M;
end;
// now you must check that L contains st because
// it is possible that the search condition is never satisfied
L:=0;
R:=lv.items.Count-1;
当L
为什么不正常
您的版本使用二进制搜索,这是一个好主意。但它在TListView上工作,因此每次Items[]调用都会非常慢
建议是:
procedure Extract(List, Dest: TStrings; Char1, Char2: char);
var i,j: integer;
V: cardinal;
type PC = {$ifdef UNICODE}PCardinal{$else}PWord{$endif};
begin
V := ord(Char1)+ord(Char2) shl (8*sizeof(char));
Dest.BeginUpdate;
Dest.Clear;
for i := 0 to List.Count-1 do begin
if PC(pointer(List[i]))^=V then begin
for j := i to List.Count-1 do begin
Dest.Add(List[j]);
if PC(pointer(List[j]))^<>V then
break; // end the for j := loop
end;
break; // end the for i := loop
end;
Dest.EndUpdate;
end;
过程提取(List,Dest:TStrings;Char1,Char2:char);
var i,j:整数;
五:红衣主教;
键入PC={$ifdef UNICODE}PCardinal{$else}PWord{$endif};
开始
V:=ord(Char1)+ord(Char2)shl(8*sizeof(char));
Dest.BeginUpdate;
目标明确;
对于i:=0的列表。计数-1是否开始
如果PC(指针(列表[i])^=V,则开始
对于j:=i to List.Count-1 do begin
目的地添加(列表[j]);
如果PC(指针(列表[j])^V,则
break;//结束for j:=循环
结束;
break;//结束for i:=循环
结束;
Dest.EndUpdate;
结束;
应用于TStringList(而不是TListView.Items)的此过程将比TListView.Items上的任何二进制搜索快得多。我认为我们现在(超过-)给巨魔喂食这段代码真的应该试着最终保护开始/结束更新对谢谢你a.Bouchez.你真的很有帮助,至少提供了可能的答案,并且没有发布修饰语。这是
procedure Extract(List, Dest: TStrings; Char1, Char2: char);
var i,j: integer;
V: cardinal;
type PC = {$ifdef UNICODE}PCardinal{$else}PWord{$endif};
begin
V := ord(Char1)+ord(Char2) shl (8*sizeof(char));
Dest.BeginUpdate;
Dest.Clear;
for i := 0 to List.Count-1 do begin
if PC(pointer(List[i]))^=V then begin
for j := i to List.Count-1 do begin
Dest.Add(List[j]);
if PC(pointer(List[j]))^<>V then
break; // end the for j := loop
end;
break; // end the for i := loop
end;
Dest.EndUpdate;
end;