2009-05-06 13 views
2

セット内で最高(または最低)の値を抽出する方法はありますか?たとえば、次の「バイトのセット」がある場合:デルファイセットから最高の価値を得るには?

[0, 1, 2, 4, 5, 28, 199] 

私はそれを実行して結果として199を返すことができますか?

EDIT:for..inループを含む明白な強硬な解決策があります。可能であれば、私はそれより良い方法を見つけたいと思っています。

答えて

13

ループは実際には正式に正しい方法です。

type 
    TSetType = set of TEnumType; 

function HighestMember(const s: TSetType): TEnumType; 
begin 
    for Result := High(Result) downto Low(Result) do 
    if Result in s then 
     exit; 
    raise Exception.Create('empty sets have no highest member'); 
end; 

ソリューションの他の種類は、型の安全性を失うことを強制どちらも、タイプキャストやアセンブラが必要になります - 彼らは行く「言語の外に、」いわば。

あなたのセットが32個以下の要素を持つことが保証できるならば、そのセットは通常の整数でオーバレイでき、あなたの質問は32ビットで設定された最高ビットの位置を求めるのと同じです整数。あなたがセットタイプの32の要素の制限を持っていない場合、あなたはDelphiの256要素に制限されてい

、および任意のビット:それはかなり、前にここで質問されています-twiddlingソリューションは、32- バイトの入力を処理する必要があります。

+3

256-MAX-カウントループは、ブルートフォースではありません。国防総省への攻撃やRSAの解読を試みることは無頓着です。これが最適なソリューションです。読みやすさのためにコードを書いてください。スピードは秒です(実際のボトルネックを発見した場合のみ)。 – paxdiablo

+0

そのようなものは、ビットセットとしてセットの内部実装に依存していますか?それ以外の場合、可能なすべての値をループするのではなく、要素の要素をループすることをお勧めします。 – jpfollenius

+0

もっとスマッシュで、可能なすべての値をチェックする以外はセットの内容を列挙する方法はありません。内部的には、これが "for-in"ループの仕組みです。私がコードで実演した方法は、内部表現に依存せず、集合は有限である。どんなビットレートの解決策も内部表現に依存していますが、これは非常に安全な前提です。彼らはTurbo Pascalに戻ったのと同じです。 –

6

セットは順不同なので、ループよりもはるかに良くなりません。常に最小値/最大値を調べる場合は、heap data structureを使用します。これはO(1)ルックアップを使用して最小/最大値を取得し、O(log n)ルックアップを他の値に適用します。

2

ここでは、バイトセットの内部構造の知識を使用した少し速いバージョンです。

type 
    TByteSet = set of Byte; 

function HighestElement(const ByteSet: TByteSet): Byte; 
type 
    TSetBytes = array[0..SizeOf(TByteSet) - 1] of Byte; 
var 
    I, J: Integer; 
    B: Byte; 
    SetBytes: TSetBytes; 
begin 
    if ByteSet <> [] then 
    begin 
    SetBytes := TSetBytes(ByteSet); 
    // Start at the top and work down, one byte at a time 
    for I := SizeOf(TByteSet) - 1 downto 0 do 
    begin 
     // Any bits set here 
     B := SetBytes[I]; 
     if B <> 0 then 
     begin 
     Result := I * 8; 
     for J := 0 to 7 do 
      if (B shr J) and 1 <> 0 then 
      begin 
      Result := Result + J; 
      Exit; 
      end; 
     end; 
    end; 
    end else 
    // No elements set 
end; 

セットのタイプ(TByteSet)をほぼすべてのセットタイプに変更できますが、この機能は引き続き有効です。関数declとbodyの中のTByteSetをあなたのセットの型に置き換えてください。また、AnsiCharのセットを使用している場合は実際の要素タイプを返すように、また一部の列挙型のセットを返すように変更することもできます。最低値を取得するには、 "I"ループを "0〜SizeOf(TByteSet)-1"に変更し、 "J"ループのifテストを "if(B shl J)および$ 80 <> 0"に変更します。

+1

ええと、 "platform"と "deprecated"以外にも、 "endianunsafe"指示が時間内に必要になります:-) –

1

ほぼ同じですが、短い:

type 
    TByteSet = set of Byte; 

function MaxSet(S: TByteSet): Byte; 
var 
    CardArr: Array [0..7] of Cardinal absolute S; 
    i: Byte; 
begin 
    i := 7; 
    while (i > 0) AND (CardArr[i] = 0) do 
    Dec(i); 
    Result := i + Floor(Log2(CardArr[i])); 
end; 
1

最高と最低、数学ユニットを使用しない:最高のビットセットを見つけるため

type 
    TCharSet = set of Char; 

function MaxOfSet(aSet: TCharSet):Char; 
var 
    Data:array[0..SizeOf(TCharSet)-1] of Byte absolute aSet; 
    i,r:Byte; 
begin 
    if aSet<>[] then begin 
    i:=SizeOf(TCharSet)-1; 
    while (i>0) and (Data[i]=0) do 
     Dec(i); 
    r:=i*8; 
    i:=Data[i]; 
    while (i and $80)=0 do begin 
     i:=i shl 1; 
     Dec(r) 
    end; 
    Result:=Chr(r+7) 
    end 
    else 
    raise Exception.Create('Unable to extract max value from an empty set'); 
end; 

function MinOfSet(aSet: TCharSet):Char; 
var 
    Data:array[0..SizeOf(TCharSet)-1] of Byte absolute aSet; 
    i,r:Byte; 
begin 
    if aSet<>[] then begin 
    i:=0; 
    while (i<SizeOf(TCharSet)-1) and (Data[i]=0) do 
     Inc(i); 
    r:=i*8; 
    i:=Data[i]; 
    while (i and 1)=0 do begin 
     i:=i shr 1; 
     Inc(r) 
    end; 
    Result:=Chr(r) 
    end 
    else 
    raise Exception.Create('Unable to extract min value from an empty set'); 
end; 
+1

答えにいくつかの説明を追加してください。ほんの一片のコードよりも役に立ちます。 – Billa

関連する問題