我有一个固定大小的循环缓冲区(实现为数组):在初始化时,缓冲区被填充指定的最大元素数,允许使用单个位置索引以跟踪我们当前的位置圈子。
访问循环缓冲区中元素的有效方法是什么?这是我目前的解决方案:
int GetElement(int index)
{
if (index >= buffer_size || index < 0)
{
// some code to handle the case
}
else
{
// wrap the index
index = end_index + index >= buffer_size ? (index + end_index) - buffer_size : end_index + index;
}
return buffer[index];
}
一些定义:
end_index
是紧跟在圆圈中最后一个元素之后的元素的索引(它也将被视为与start_index或圆的第一个元素相同)。
buffer_size
是缓冲区的最大大小。
答案 0 :(得分:12)
我想出的最好的是:
public static int Wrap(int index, int n)
{
return ((index % n) + n) % n;
}
(假设你需要使用负数)
答案 1 :(得分:10)
确保缓冲区始终为2的幂,并掩盖顶部位。
答案 2 :(得分:5)
它在某种程度上取决于处理器,但它至少值得尝试像return (end_index + index) % buffer_size;
答案 3 :(得分:4)
// plain wrap
public static int WrapIndex(int index, int endIndex, int maxSize)
{
return (endIndex + index) > maxSize ? (endIndex + index) - maxSize : endIndex + index;
}
// wrap using mod
public static int WrapIndexMod(int index, int endIndex, int maxSize)
{
return (endIndex + index) % maxSize;
}
// wrap by masking out the top bits
public static int WrapIndexMask(int index, int endIndex, int maxSize)
{
return (endIndex + index) & (maxSize - 1);
}
表现结果(滴答声):
Plain: 25 Mod: 16 Mask: 16 (maxSize = 512)
Plain: 25 Mod: 17 Mask: 17 (maxSize = 1024)
Plain: 25 Mod: 17 Mask: 17 (maxSize = 4096)
所以似乎模数是更好的选择,因为它不需要对缓冲区的大小进行任何限制。
答案 4 :(得分:3)
int GetElement(int index)
{
return buffer[(end_index + index) % buffer_size];
}
有关modulo operation的详细信息,请参阅modulus operator (%
)。
答案 5 :(得分:0)
FWIW,你总是可以做一个并行数组:i = next[i];
但是,真的,我一直都是这样做的:i++; if (i >= n) i = 0;
或i = (i+1) % n;
无论如何,如果这是一个重大的性能问题,我会非常惊讶。