大家请进来:【300分求助字符比较的最优算法】: ( 积分: 300 )

  • 主题发起人 主题发起人 凤仙花
  • 开始时间 开始时间

凤仙花

Unregistered / Unconfirmed
GUEST, unregistred user!
【300分求助字符比较的最优算法】:

假如有两个相同结构的表: A1.db 和 A2.DB ,每个表都只有一个5字节长的字符型字段“ZD”,
并且每个表有3万条记录。比如:第一条记录为“ABCDE”、第二条记录为“CDDAE”(这些记录都是每个考生对5个考题写的不同答案啦)。
现在,我要从A1表中找出这些记录,这些记录的A1.ZD字段同时满足以下条件:
①、和A2.ZD字段同位比较只相同3~4位(同字节位置比较!比如:“ADDCC”和“ABBCC”是相同3个,即:第1、4、5位相同);
②、符合条件①的A2.ZD只有80~100条。

(注意,比较两个字段答案相同数时,是按字节位置、同位比较的,比如:“ADDCC”和“ABBCC”是相同3个(第1、4、5位相同)。


目前我发现别人的算法最快只有1秒就能实现,但是他们不告诉算法,郁闷啊!
 
如果每一题的答案限于5个(A,B,C,D,E),那么你可以穷举符合条件的sql语句,总共就10+5=15个SQL语句条件。
 
每一题最多有10个的答案:A~J,至少4个,最大有10个可选项的项。
我只是就事举例,具体答案数目不确定,但不管每题的答案有多少,检索的算法是一样的
 
大家哪里渡假去了?
 
最快的方法是不用 SQL ,直接拿出来对比(反正是统计个数而已)
对比可以这样,就五个字节,那么我们可以先对比前面四个字节(作为DWORD类型进行异或),如果结果是 0/1/5 相同的直接可以忽略掉,2/3/4相同的再对比最后一个字节,这样估计一秒里是可以搞定三万个记录的
 
建索引;
然后好好把like语法研究透了,问题也就解决了
 
是什么数据库,你是要用sql解决么?
如果是sqlserver的话,发给我表结构,部分数据.
我来试一下.deepno@163.com
 
*.DB本地数据库;
直接拿出来对比、建索引,好像速度也不是提高很多;
达不到别人的大概1秒的速度。估计别人用的不是SQL处理方法,应该是某种变换的算法来达到等效目的的。
 
const
MAX_HASHVALUE = $8000;

// 计算答案的HASH值
// 答案的字符是: A->F之间,
// Max_HashValue = 二进制: 111 111 111 111 111
// 二进制:111的值范围在0->6之间,可以表示一个答案字符的值

function GetHash(const S: string): Word;
const
Data: array ['A'..'F'] of Byte = (1, 2, 3, 4, 5, 6)
begin
Result :=
Data[S[1]] shl 12 +
Data[S[2]] shl 9 +
Data[S[3]] shl 6 +
Data[S[4]] shl 3 +
Data[SP[5]];
Result := Result and MAX_HASHVALUE
end;

type
PWordArray = ^TWordArray ;
TWordArray = array [0..0] of Word;

var
Buffer: Pointer;
P: PWord;
Hash: Cardinal;

// 保存Table2的HASH值的内容
Buffer := AllocMem(MAX_HASHVALUE * SizeOf(Word));
P := Buffer;

// 扫描一次Table2.zd的Hash
for I := 0 to Table2.ZD.Count - 1 do
begin
P^ := GetHash(Table2.ZD.Strings);
Inc(P);
end;

// 再计算一次Table1.zd中每答案的Hash,看是否存在Buffer中
// Hash定位是最快的了。
for I := 0 to Table1.ZD.Count - 1 do
begin
Hash := GetHash(Table1.ZD.Strings);
if PWordlArray(Buffer)^[Hash] <> 0 then
begin
// Table1.zd.strings Exists Table2.zd
end;
end;
 
设定:
Table1.ZD and Table2.ZD 的答案内容长度是:5,且:内容的字符是:'A'..'F'之间

大概是这样,我没试,你自个试吧。
 
太高深了,正在看算法,有些还真看不懂,
谢谢再说
 
继续啊,
还有别的答案吗
 
const
MAX_ANSWER_HASH = $FFF;
HashMapValue: array ['A'..'J'] of Byte = (1, 2, 3, 4, 5, 6, 7, 8, 9, $A);

type
TStringHashArray = array [0..MAX_ANSWER_HASH - 1] of Boolean;

function GetHashValue(C1, C2, C3: Char): Word;
begin
Result := (
((HashMapValue[C1] and $F) shl 8) +
((HashMapValue[C2] and $F) shl 4) +
((HashMapValue[C3] and $F))) and MAX_ANSWER_HASH;
end;

procedure SetStringHash(var HashArray: TStringHashArray; const S: string);

procedure SetHash(C1, C2, C3: Char); overload;
var
Hash: Word;
begin
Hash := GetHashValue(C1, C2, C3);
if not HashArray[Hash] then
HashArray[Hash] := True;
end;

var
C1, C2, C3, C4, C5: Char;
begin
C1 := S[1];
C2 := S[2];
C3 := S[3];
C4 := S[4];
C5 := S[5];

// 按顺序的情况下,只要有5种组合需要,如下:
SetHash(C1, C2, C3);
SetHash(C1, C3, C4);
SetHash(C1, C4, C5);
SetHash(C2, C3, C4);
SetHash(C2, C4, C5);
SetHash(C3, C4, C5);
end;

function GetStringHash(HashArray: TStringHashArray; const S: string): Boolean;
var
C1, C2, C3, C4, C5: Char;
begin
C1 := S[1];
C2 := S[2];
C3 := S[3];
C4 := S[4];
C5 := S[5];
// 只判断5种组合的Boolean值是否存在即可
Result :=
HashArray[GetHashValue(C1, C2, C3)] or
HashArray[GetHashValue(C1, C3, C4)] or
HashArray[GetHashValue(C1, C4, C5)] or
HashArray[GetHashValue(C2, C3, C4)] or
HashArray[GetHashValue(C2, C4, C5)] or
HashArray[GetHashValue(C3, C4, C5)];
end;

procedure GetExistsData(Exists: TStrings; Table1, Table2: TStrings); overload;
var
I: Integer;
HashArray: TStringHashArray;
begin
FillChar(HashArray, SizeOf(HashArray), 0);
Exists.Clear;
for I := 0 to Table2.Count - 1 do
SetStringHash(HashArray, Table2);

for I := 0 to Table1.Count - 1 do
begin
if GetStringHash(HashArray, Table1) then
Exists.Add(Table1);
end;
end;

type
TStringArray = array of string;

procedure GetExistsData(var Exists: TStringArray; Table1, Table2: TStringArray); overload;
var
I, Index, Count: Integer;
HashArray: TStringHashArray;
begin
FillChar(HashArray, SizeOf(HashArray), 0);

for I := 0 to Length(Table2) - 1 do
SetStringHash(HashArray, Table2);

Index := 0;
Count := Length(Table1);
SetLength(Exists, Count);
for I := 0 to Count - 1 do
begin
if GetStringHash(HashArray, Table1) then
begin
Exists[Index] := Table1;
Inc(Index);
end;
end;
SetLength(Exists, Index);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
GetExistsData(Memo3.Lines, Memo1.Lines, Memo2.Lines);
end;
 
两个数组比较,如果量大的情况下,这个解题方法是最快的。

你这个也差不多,昨天理解题错误,写了大概代码,你试试看。
如果还有速度问题,那应该是你调用的问题。

代码面前没秘密了,看看就明白怎么回事了。
 
本人最近受到Borland中國的騷擾,求有Delphi正版授權公司或個人幫助
QQ:10961560
 
谢谢,暂不封题。再等一段时间看看。
 
多人接受答案了。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
923
SUNSTONE的Delphi笔记
S
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部