有没有办法提取集合中的最高(或最低)值?例如,如果我有以下“字节集”:
[0, 1, 2, 4, 5, 28, 199]
我可以运行任何功能并返回199作为结果吗?
编辑:有一个明显的暴力解决方案涉及for..in循环。如果可能的话,我想找到比这更好的方法。
答案 0 :(得分:14)
循环确实是正式的方法。
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个元素限制,并且任何bit-twiddling解决方案都需要处理32- 字节输入
答案 1 :(得分:6)
集合是无序的,因此您不会比循环更好。如果你经常查找集合的最小值/最大值,那么使用heap data structure,它提供O(1)查找以获取最小/最大值和O(log n)查找任何其他值
答案 2 :(得分: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”for循环更改为“0到SizeOf(TByteSet) - 1”,并将“J”循环中的if测试更改为“if(B shl J)和$ 80&lt;&gt; 0”
答案 3 :(得分: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;
答案 4 :(得分: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;