Delphi 生成不重复随机数类

本类可用来产生从MinNumber到MaxNumber之间的随机数,只要设定Unique,每个数字就只使用一次。此外还可以检查数字是否使用过。一个动态的Tbit数组用来保证数字只会返回一次,并看是否所有的数字都使用过。

 

unit REngine;
interface

uses Windows,Classes;

type
     TRandomEngine 
= class(TObject)
     
private
        FSelected : TBits;
        FArrSize,FNumbersUsed : longint;
        FMinNumber,FMaxNumber : longint;
        FUnique : boolean;
        
procedure SizeSelArray;
        
procedure SetFMinNumber(NewValue : longint);
        
procedure SetFMaxNumber(NewValue : longint);
        
function GetFNumbersFree : longint;
     
public
        
constructor Create;
        
destructor Destroy; override;
        
procedure Reset;
        
function GetRandom : longint;
        
function IsUsed(Index : longint) : boolean;
        
property MinNumber : longint read FMinNumber write SetFMinNumber;
        
property MaxNumber : longint read FMinNumber write SetFMaxNumber;
        
property Unique : boolean read FUnique write FUnique;
        
property NumbersUsed : longint read FNumbersUsed;
        
property NumbersTotal : longint read FArrSize;
        
property NumbersFree : longint read GetFNumbersFree;
     
end;


// ===================================
// 创建和释放对象
// ===================================

constructor TRandomEngine.Create;
begin
  FSelected :
= TBits.Create;
  FNumbersUsed :
= 0;
  FMinNumber :
= 0;
  FMaxNumber :
= 0;
  FArrSize :
= 0;
  FUnique :
= false;
  Randomize;
end;

destructor TRandomEngine.Destroy;
begin
  
inherited Destroy;
  FSelected.Free;
end;

// ===========================
// Get/Set方法
// ===========================

procedure TRandomEngine.SetFMinNumber(NewValue : longint);
begin
  
if (NewValue <> FMinNumber) then
  
begin
     FMinNumber :
= NewValue;
     
if FMinNumber > FMaxNumber then FMaxNumber := FMinNumber;
     SizeSelArray;
  
end;
end;

procedure TRandomEngine.SetFMaxNumber(NewValue : longint);
begin
  
if (NewValue <> FMaxNumber) then
  
begin
     FMaxNumber :
= NewValue;
     
if FMaxNumber < FMinNumber then FMinNumber := FMaxNumber;
     SizeSelArray;
  
end;
end;

function TRandomEngine.GetFNumbersFree : longint;
begin
  Result :
= FArrSize - FNumbersUsed;
end;

// =======================================
// 调整布尔数组(FSelected)的大小
// =======================================

procedure TRandomEngine.SizeSelArray;
var i : longint;
begin
  FArrSize :
= FMaxNumber - FMinNumber + 1;

  
if FArrSize > 0 then
  
begin
    FSelected.Size :
= FArrSize;
    
for i := 0 to FArrSize - 1 do FSelected[i] := false;
  
end;

  FNumbersUsed :
= 0;
end;

// =======================================
// 重置可用,已用,未用数字。
// 为IsUsed()重置Fselected数组,
// 使之为false。
// =======================================

procedure TRandomEngine.Reset;
begin
  SizeSelArray;
end;

// ===================================================
// 如果已设定Unique,数字已使用,
// 则返回true/false。
// ===================================================

function TRandomEngine.IsUsed(Index : longint) : boolean;
var Retvar : boolean;
begin
  
if (Index < FMinNumber) or (Index > FMaxNumber) then
      Retvar :
= false
  
else
      RetVar :
= FSelected[Index - FMinNumber];

  Result :
= RetVar;
end;

// ===================================================
// 根据最小和最大值返回随机数。如果
// 已设定Unique,则根据Fselected数
// 组生成(即保证数字未用过)。
// ===================================================

function TRandomEngine.GetRandom : longint;

var V : longint;
    NumSelected : boolean;
begin
  
if FUnique and (FNumbersUsed = FArrSize) then
     V :
= 0
  
else
  
begin
     
repeat
        V :
= Random(FMaxNumber - FMinNumber + 1+ FMinNumber;
        
if not FUnique then
           NumSelected :
= true
        
else begin
           
if FSelected[V - FMinNumber] then
              NumSelected :
= false
           
else begin
              NumSelected :
= true;
              FSelected[V 
- FMinNumber] := true;
              inc(FNumbersUsed);
           
end;
        
end;
     
until NumSelected;
  
end;

  Result :
= V;
end;

end.

 

 

posted @ 2010-01-27 10:47  Mr8's chaos  阅读(5781)  评论(1)    收藏  举报