用怎样的数据结构记录这样的信息比较合适?(20分)

  • 主题发起人 主题发起人 TENTODBV
  • 开始时间 开始时间
T

TENTODBV

Unregistered / Unconfirmed
GUEST, unregistred user!
我的程序中需要生成一个很大的保存标记信息的数组,标记值很简单,不是0就是1。其实整个标记数组就相当于一个很大的二进制数。程序中对标记信息数组的操作要求很简单,能够快速得到指定下标的元素的值是0还是1,能够直接修改某个元素的值为0或1。我是用array of byte实现的。这个标记数组很大,可能有2000万个元素,为了表示它要用2000万个字节差不多20M内存,而实际上保存0或1值用1个bit就够了,用一个字节来表示太浪费了。我不知道PASCAL中有没有位操作的函数。请问我要求的这个功能怎样实现比较好?
 
可以位操作啊。lsh rsh ,and 等。
用一个bit表示标记信息就行了。可以减少8倍的存储空间。
 
能否给出代码示例
 
LSH 左移xx位,rsh,右移xx位
delphi里面看看help不就行了,这种怎么给代码示例?

asm
lsh eax;1
end;
行不行?
 
我正好做了一个类可以实现你要的功能,可以参考一下。我是二维的,你只要把RowCount设成1就是你要的。
unit BitsArrayClass;
interface
uses Classes, SysUtils, Types, windows;
type

TByteArrayOfArray = array of array of Byte;

TBitsArray = class(TObject)
private
function GetByteValue(Row, Col: Integer): Byte;
procedure SetByteValue(Row, Col: Integer
const Value: Byte);
procedure SetColCount(const Value: Word);
procedure SetRowCount(const Value: Word);
procedure ResizeArray;
protected
FColCount: Word;
FRowCount: Word;
function LoadFromStream(Stream: TStream): Boolean;
function SaveToStream(Stream: TStream): Boolean;
public
BitsArray: TByteArrayOfArray;

constructor Create
virtual;
destructor Destroy
override;

procedure Assign(AObject: TBitsArray);
procedure SetArraySize(RowCount, ColCount: Integer);virtual;

property ByteValue[Row, Col: Integer]: Byte read GetByteValue
write SetByteValue;
property ColCount: Word read FColCount write SetColCount;
property RowCount: Word read FRowCount write SetRowCount;
end;

function BitsArrayLoadFromStream(Stream: TStream;
var BitsArray: TByteArrayOfArray): Boolean;
function BitsArraySaveToStream(Stream: TStream;
const BitsArray: TByteArrayOfArray): Boolean;
function SetBitsArraySize(var BitsArray: TByteArrayOfArray;
RowCount, ColCount: Integer): Boolean;
implementation


{ TBitsArray }
//提取指定字节得某位的值
function ConvertBitsToByte(const AByte: Byte
BitsPos: Byte): Byte;
begin
Result := (AByte shr BitsPos) and 1;
end;

//使得字节指定位的值为1其他为0
function MoveOneByBitsPos(BitsPos: Word): Byte;
begin
Result := (1 shl BitsPos) xor $FF;
end;

function ConvertByteToBits(const AByte: Byte
BitsPos: Integer): Byte;
begin
Result := AByte shl BitsPos;
end;

function SetBitsArraySize(var BitsArray: TByteArrayOfArray;
RowCount, ColCount: Integer): Boolean;
begin
Result := True;
try
SetLength(BitsArray, RowCount, (ColCount - 1) div 8 + 1);
except
Result := False;
end;
end;

function BitsArrayLoadFromStream(Stream: TStream;
var BitsArray: TByteArrayOfArray): Boolean;
var
Row, RowCount, ColCount: Integer;
begin
Result := BitsArray <> nil;
with Stream do
try
RowCount := Length(BitsArray);
ColCount := Length(BitsArray[0]);
for Row := 0 to RowCount - 1 do
Read(BitsArray[Row][0], ColCount);
except
Result := False;
end;
end;

function BitsArraySaveToStream(Stream: TStream;
const BitsArray: TByteArrayOfArray): Boolean;
var
Row, RowCount: Integer;
begin
Result := BitsArray <> nil;
if Result then
with Stream do
try
RowCount := Length(BitsArray);
for Row := 0 to RowCount - 1 do
Write(BitsArray[Row][0], Length(BitsArray[0]));
except
Result := False;
end;
end;

constructor TBitsArray.Create;
begin
FRowCount := 8;
ColCount := 8;
end;

destructor TBitsArray.Destroy;
begin
BitsArray := nil;
inherited;
end;

procedure TBitsArray.SetArraySize(RowCount, ColCount: Integer);
begin
FRowCount := RowCount;
FColCount := ColCount;
SetBitsArraySize(BitsArray, RowCount, ColCount);
end;

function TBitsArray.GetByteValue(Row, Col: Integer): Byte;
var
BytePos: Integer;
BitsPos: Byte;
begin
BytePos := Col div 8;
BitsPos := Col mod 8;
Result := ConvertBitsToByte(BitsArray[Row][BytePos], BitsPos);
end;

procedure TBitsArray.SetByteValue(Row, Col: Integer
const Value: Byte);
var
BytePos, BitsPos: Integer;
AByteValue: Byte;
begin
BytePos := Col div 8;
BitsPos := Col mod 8;
//先把要设置的那一位置成0
AByteValue := BitsArray[Row][BytePos] and MoveOneByBitsPos(BitsPos);

BitsArray[Row][BytePos] := AByteValue or ConvertByteToBits(Value, BitsPos);
end;

procedure TBitsArray.SetColCount(const Value: Word);
begin
if FColCount <> Value then
begin
FColCount := Value;
ResizeArray;
end;
end;

procedure TBitsArray.SetRowCount(const Value: Word);
begin
if FRowCount <> Value then
begin
FRowCount := Value;
ResizeArray;
end;
end;

function TBitsArray.LoadFromStream(Stream: TStream): Boolean;
begin
Result := BitsArrayLoadFromStream(Stream, BitsArray);
end;

function TBitsArray.SaveToStream(Stream: TStream): Boolean;
begin
Result := BitsArraySaveToStream(Stream, BitsArray);
end;

procedure TBitsArray.ResizeArray;
begin
SetArraySize(FRowCount, FColCount);
end;

procedure TBitsArray.Assign(AObject: TBitsArray);
begin
BitsArray := Copy(AObject.BitsArray);
SetArraySize(AObject.RowCount, AObject.ColCount);
end;

end.
 
Delphi中的TBits类就可以了
 
TBits 中的是布尔值,布尔值也是占用一个字节的,用TBits 好像不能减少内存占用。

to amerex, 以下函数中怎么没有用到AByte参数?括号里的Result 是不是应该改为AByte?
//提取指定字节得某位的值
function ConvertBitsToByte(const AByte: Byte
BitsPos: Byte): Byte;
begin
Result := (Result shr BitsPos) and 1;
end;
 
TBit也是用1bit表示一个boolean值,看Tbits.SetSize方法即可知道
procedure TBits.SetSize(Value: Integer);
var
NewMem: Pointer;
NewMemSize: Integer;
OldMemSize: Integer;

function Min(X, Y: Integer): Integer;
begin
Result := X;
if X > Y then Result := Y;
end;

begin
if Value <> Size then
begin
if Value < 0 then Error;
NewMemSize := ((Value + BitsPerInt - 1) div BitsPerInt) * SizeOf(Integer);
OldMemSize := ((Size + BitsPerInt - 1) div BitsPerInt) * SizeOf(Integer);
if NewMemSize <> OldMemSize then
begin
NewMem := nil;
if NewMemSize <> 0 then
begin
GetMem(NewMem, NewMemSize);
FillChar(NewMem^, NewMemSize, 0);
end;
if OldMemSize <> 0 then
begin
if NewMem <> nil then
Move(FBits^, NewMem^, Min(OldMemSize, NewMemSize));
FreeMem(FBits, OldMemSize);
end;
FBits := NewMem;
end;
FSize := Value;
end;
end;
 
To:TENTODBV
谢谢你得提醒,是我错了。奇怪我一直在用怎么没错呢?真怪:)
 
铁盒子说的有道理,他其实也是用位表示的,只不过他占的内存是32位即四个字节的整数倍
 
怎样才能知道某个对象占用多少内存?Bits1:=TBits.Create;我用Bits1.instancesize查看Bits1的大小得到的结果是12字节。参照amerex的方法,我自己写的一个对象也是12个字节。无论我设置Bits1.Size为多大,结果总是12字节。假设Bits1.Size:=10000000,那么Bits1究竟占用多少内存?
 
经常看一些软件测评用有内存占用的统计,请问win98下用什么工具可以查看软件的内存占用。我记得以前用系统工具中的系统监视器可以看CPU占用率等指标,可是现在不知为什么运行系统监视器看不见变化曲线了(由于避免软件冲突,我用超级兔子把启动时自动运行的一些程序禁止了,不知是不是对此有影响)。
 
用flyweight模式是不是可以!
 
我不懂什么是flyweight。能介绍一下吗?
 
后退
顶部