列表视图中包含大约10000个已排序的项目(用于搜索):
aa cd
aa ef
..
..
ab cd // want to get all ab item(s), may be there is only ONE ab item,
(ab ef) // may be there is more than one ab item, the number of ab item is unknown.
..
..
ac cd
ac ef
..
ak cd
ak ef
ak gh
..
..
下一个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?
我不知道我上面说的是否清楚? 用简单的英语这是一个明确的问题吗?
答案 0 :(得分:4)
我没有看过你的整个代码,但二进制搜索部分完全错了。您需要一个二进制搜索算法,找到满足搜索条件的第一个条目:
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
答案 1 :(得分:4)
为什么previous answer不行?
您的版本使用二进制搜索,这是一个好主意。但是它适用于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;
此过程应用于TStringList(而不是TListView.Items),将比TListView.Items上的任何二进制搜索快得多。