如何检索?循环存储的问题? 算法高手请进!(200分)

  • 主题发起人 主题发起人 escaper
  • 开始时间 开始时间
E

escaper

Unregistered / Unconfirmed
GUEST, unregistred user!
如何检索?循环存储的问题? 算法高手请进!
现在我的问题是这样我在040芯片上开辟一块区域用来存储数据(发票数据)
比如从地址1000到10000 ,每一条数据有如下几个字段 号码,日期,金额,
操作员
检索时要求,按号码检索,和按日期检索, 比如检索从号码234 到号码500
的发票总额, 或者从2003年3月一日到2003年5月2日的所有发票。
在不要求循环存储的情况下,我设想的方案是这样的。 因为存储的时候发票号码
是相对连续的,就是说 存储的情况一般是 NO500,NO501,NO502。。。NO520,NO300,NO301。。。NO330
每当发票号不连续时添加一条索引, 索引由三个字段组成 起始地址 ,开始发票号码,中止发票号码。(索引区的大小也不可能是无限大的)
现在要求循环存储,就是说当存储到了10000这个地址时,把地址为0的那条记录覆盖掉接着写。
请各位大侠出手,小弟感激不尽。
 
不会吧,一万条记录!
 
出手吧,等着呢
 
大富翁真没高手吗?
 
不就是一个循环队列吗?如果没看错
好好看看书吧,打好基础,总不能每次都找别人
 
循环链表能解决问题吗?
给出你的解决方案?

1: 开票时,每本内的发票号码是连续的,但各本发票之间号码无任何联系
2: 索引中其实就是记录每本发票的起始号码的存储地址(每本发票的张数不一)
3: 开票时必须开完一本发票才能开下一本,所以存储时发票是相对连续的
TO ALL :
能否再详细点, 讨论的重点是优与检索,因为检索区也不能无限大,所以好象有些复杂
 
下面的TCycleTable类已经可以实现在有限大小的空间内进行数据的循环存放(请注意—
—索引不是循环的——它只是自动重排而已)。
type
TDataRec=record
ID:Integer;
Day:TDate;
Money:Integer;
end;
TIndexRec=record
Offset:Integer;
StartNo,EndNo:Integer;
end;
TCycleTable=class
private
FData:array of TDataRec;
FIndex:array of TIndexRec;
FMaxIndexCount,FMaxRecCount:Integer;
FIndexHead,FIndexTail:Integer;
function GetRecTail:Integer;
procedure ResetIndex;
procedure ClearHeadRec;
function GetRecHead: Integer;
function GetData(Index: Integer): TDataRec;
function GetDataCount: Integer;
function GetIndex(Index: Integer): TIndexRec;
function GetIndexCount: Integer;
public
property Data[Index:Integer]:TDataRec read GetData;
default;
property DataCount:Integer read GetDataCount;
property Index[Index:Integer]:TIndexRec read GetIndex;
property IndexCount:Integer read GetIndexCount;
function AddRec(AData:TDataRec):Boolean;
constructor Create(MaxRecCount,MaxIndexCount:Integer);
destructor Destroy;
override;
end;

{ TCycleTable }
function TCycleTable.AddRec(AData: TDataRec): Boolean;
var
SavePos:Integer;
begin
Result:=false;
if FIndexHead=-1 then
//first node
begin
FIndexHead:=0;
FIndexTail:=0;
SavePos:=0;
FIndex[FIndexTail].Offset:=0;
FIndex[FIndexTail].StartNo:=AData.ID;
end
else
begin
if GetRecTail<FMaxRecCount-1 then
//记录没有到末尾
begin
SavePos:=GetRecTail+1;
if SavePos=FIndex[FIndexHead].Offset then
//发生了覆盖
ClearHeadRec;
if AData.ID<>FIndex[FIndexTail].EndNo+1 then
//不是连续追加的记录
begin
if FIndexTail-FIndexHead=FMaxIndexCount-1 then
//索引已用罄
exit;
if FIndexTail=FMaxIndexCount-1 then
//FIndex数组的后面已经没有空位
ResetIndex;
FIndexTail:=FIndexTail+1;
//在末尾新增索引
FIndex[FIndexTail].Offset:=SavePos;
FIndex[FIndexTail].StartNo:=AData.ID;
end;
end
else
begin
SavePos:=0;
ClearHeadRec;
//因为肯定发生了覆盖...
if FIndexTail-FIndexHead=FMaxIndexCount-1 then
//...
exit;
if FIndexTail=FMaxIndexCount-1 then
//...
ResetIndex;
FIndexTail:=FIndexTail+1;
//...
FIndex[FIndexTail].Offset:=SavePos;
FIndex[FIndexTail].StartNo:=AData.ID;
end;
end;
FIndex[FIndexTail].EndNo:=AData.ID;
with FData[SavePos]do
begin
ID:=AData.ID;
Day:=AData.Day;
Money:=AData.Money;
end;
Result:=true;
end;

procedure TCycleTable.ClearHeadRec;
begin
with FIndex[FIndexHead]do
if StartNo=EndNo then
//只对应了一条记录
Inc(FIndexHead)
else
begin
//后移
Inc(Offset);
Inc(StartNo);
end;
end;

constructor TCycleTable.Create(MaxRecCount,MaxIndexCount: Integer);
begin
if MaxRecCount>0 then
FMaxRecCount:=MaxRecCount
else
FMaxRecCount:=1;
if MaxIndexCount>0 then
FMaxIndexCount:=MaxIndexCount
else
FMaxIndexCount:=1;
SetLength(FData,FMaxRecCount);
SetLength(FIndex,FMaxIndexCount);
FIndexHead:=-1;
FIndexTail:=-1;
end;

destructor TCycleTable.Destroy;
begin
inherited;
SetLength(FData,0);
SetLength(FIndex,0);
end;

function TCycleTable.GetData(Index: Integer): TDataRec;
begin
Result:=FData[(Index+GetRecHead+FMaxRecCount) mod FMaxRecCount];
end;

function TCycleTable.GetDataCount: Integer;
begin
if GetRecHead>=0 then
Result:=1+(GetRecTail-GetRecHead+FMaxRecCount) mod FMaxRecCount
else
Result:=0;
end;

function TCycleTable.GetIndex(Index: Integer): TIndexRec;
begin
Result:=FIndex[(Index+FIndexHead+FMaxIndexCount) mod FMaxIndexCount];
end;

function TCycleTable.GetIndexCount: Integer;
begin
if FIndexHead>=0 then
Result:=FIndexTail-FIndexHead+1
else
Result:=0;
end;

function TCycleTable.GetRecHead:Integer;
begin
if FIndexHead<0 then
Result:=-1
else
Result:=FIndex[FIndexHead].Offset;
end;

function TCycleTable.GetRecTail: Integer;
begin
if FIndexTail<0 then
Result:=-1
else
with FIndex[FIndexTail]do
Result:=Offset+EndNo-StartNo;
end;

procedure TCycleTable.ResetIndex;
//重排索引数组
var
i:Integer;
begin
for i:=FIndexHead to FIndexTaildo
Move(FIndex,FIndex[i-FIndexHead],SizeOf(TIndexRec));
FIndexTail:=FIndexTail-FIndexHead;
FIndexHead:=0;
end;


使用范例:
var
CycleTb:TCycleTable;
procedure TForm1.FormCreate(Sender: TObject);
begin
CycleTb:=TCycleTable.Create(10,5);
//最多10条记录,5个索引
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin

CycleTb.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
Data:TDataRec;
i:Integer;
begin
Data.Day:=Date+Random(100);
Data.ID:=SpinEdit1.Value;
Data.Money:=Random(10000);
CycleTb.AddRec(Data);
with Memo1do
begin
Text:='';
for i:=0 to CycleTb.DataCount-1do
Lines.Add(Format('[%4d] %s %6d',[CycleTb.ID,DateToStr(CycleTb.Day),CycleTb.Money]));
end;
with Memo2do
begin
Text:='';
for i:=0 to CycleTb.IndexCount-1do
Lines.Add(Format('%4d: %d - %d',[
CycleTb.Index.Offset,CycleTb.Index.StartNo,CycleTb.Index.EndNo]));
end;
SpinEdit1.Value:=SpinEdit1.Value+1;
end;

至于查询,只需要遍历CycleTb,挨个比较就可以了,在此就不示范了。

运行结果:
Index:
2: 8 - 8
3: 12 - 16
8: 21 - 22
0: 23 - 24
Data:
[ 8] 2003-10-8 6716
[ 12] 2003-10-12 1617
[ 13] 2003-10-18 4256
[ 14] 2003-9-19 4747
[ 15] 2003-9-18 8408
[ 16] 2003-9-16 2932
[ 21] 2003-12-11 3679
[ 22] 2003-11-27 3279
[ 23] 2003-11-19 8441
[ 24] 2003-11-21 3066

但愿没有误解您的意思...
 
creation_zy 谢谢您!
 
后退
顶部