【发布时间】:2011-11-04 23:57:04
【问题描述】:
我在一次采访中被问到以下问题。
int countSetBits(void *ptr, int start, int end);
简介:
假设ptr 指向一大块内存。将此内存视为连续的位序列,start 和end 是位位置。假设start 和end
有正确的值,ptr 指向一个初始化的内存块。
问题:
编写一个 C 代码来计算从start 到end [包括] 设置的位数并返回计数。
只是为了更清楚
ptr---->+-------------------------------+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+-------------------------------+
| 8 | 9 | |15 |
+-------------------------------+
| |
+-------------------------------+
...
...
+-------------------------------+
| | S | |
+-------------------------------+
...
...
+-------------------------------+
| | E | |
+-------------------------------+
...
...
我的解决方案:
int countSetBits(void *ptr, int start, int end )
{
int count = 0, idx;
char *ch;
for (idx = start; idx <= end; idx++)
{ ch = ptr + (idx/8);
if((128 >> (idx%8)) & (*ch))
{
count++;
}
}
return count;
}
我在面试中给出了一个非常冗长且效率低下的代码。我后来研究它并提出了上述解决方案。
我很确定 SO 社区可以提供更优雅的解决方案。我只是好奇地想看看他们的反应。
PS:以上代码未编译。它更像是一个伪代码,可能包含错误。
【问题讨论】:
-
我想你可能没有抓住重点。如果您的主循环以字节而不是位工作,那么效率会更高,所以您有
for (int i = ...; ...; ++i) count += bits_per_byte[((unsigned char*)ptr)[i]]。其中 bits_per_byte 是一个包含 256 个值的预计算数组,其中包含每个可能的字节值的设置位数。在循环的开始和结束时,你有一些事情要做,你没有一个完整的字节可以玩。 -
我认为他们希望您演示查找表的用法。假设 8 位字符,您将创建一个 256 长的数组,将字符映射到其中的位数。 1当然,您可以对 16 位数量执行相同操作,或者对任何不太大且有效处理的数量进行处理。
-
我不确定开始/结束值。它们是指位偏移量还是字节偏移量还是什么?
-
开始和结束索引是从字节内的 MSB 到 LSB 计数还是相反?
-
@harold:这没有明确说明,我希望这个问题必须在采访中提出。问题中的示例
countSetBits()函数从MSB计数到LSB。
标签: c++ c algorithm bit-manipulation