通过将二维数组视为“环形缓冲区”或“循环缓冲区”高效地向上旋转
不要复制或移动二维数组中的数据。这样不高效。相反,我们可以通过移动一个i_start
行索引来旋转这个二维数组,将整个数组视为{{link1:“环形缓冲区”或“循环缓冲区”}},这是一种常见的架构风格,特别适用于嵌入式系统中的高效FIFO缓冲区。
@Dave在此处的答案中提到了这个概念。
将数组复制和/或重写以旋转它的时间复杂度等于O(n),其中n
是此情况下行数的数量。我下面的方法的时间复杂度非常短,为O(1),无论数组有多大或有多少行,因为我们所做的只是将其“旋转”上去:array2d->i_start = (array2d->i_start + 1) % NUM_ROWS;
,这是非常高效的!
这是使用C++中的C语言风格数组对此概念的完整演示。请注意,如果您仅仅去掉下面结构体中的=0;
部分并且还 typedef
它(我个人偏好)或者 在需要的地方添加struct
单词,这也将成为一个完全有效的C程序。
来自我的eRCaGuy_hello_world 仓库的 cpp/ring_buffer_rotate_2d_array_up.cpp:
#include <cstdio>
#include <iostream>
#define ARRAY_LEN(array) (sizeof(array) / sizeof((array)[0]))
#define NUM_ROWS(array_2d) ARRAY_LEN(array_2d)
#define NUM_COLS(array_2d) ARRAY_LEN((array_2d)[0])
struct Array2d
{
int array[4][4];
size_t i_start = 0;
};
void array2d_print(const Array2d& array2d)
{
const size_t NUM_ROWS = NUM_ROWS(array2d.array);
const size_t NUM_COLS = NUM_COLS(array2d.array);
size_t i_row = array2d.i_start;
for (size_t row = 0; row < NUM_ROWS; row++)
{
for (size_t i_col = 0; i_col < NUM_COLS; i_col++)
{
printf("%3i", (array2d.array)[i_row][i_col]);
if (i_col < NUM_COLS - 1)
{
printf(",");
}
else
{
printf("\n");
}
}
i_row = (i_row + 1) % NUM_ROWS;
}
printf("\n");
}
void array2d_rotateup(Array2d* array2d)
{
const size_t NUM_ROWS = NUM_ROWS(array2d->array);
array2d->i_start = (array2d->i_start + 1) % NUM_ROWS;
}
int main()
{
Array2d array2d =
{
.array =
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16},
}
};
array2d_print(array2d);
for (size_t i = 0; i < NUM_ROWS(array2d.array); i++)
{
array2d_rotateup(&array2d);
array2d_print(array2d);
}
return 0;
}
运行命令和输出:
eRCaGuy_hello_world$ cpp/ring_buffer_rotate_2d_array_up.cpp
1, 2, 3, 4
5, 6, 7, 8
9, 10, 11, 12
13, 14, 15, 16
5, 6, 7, 8
9, 10, 11, 12
13, 14, 15, 16
1, 2, 3, 4
9, 10, 11, 12
13, 14, 15, 16
1, 2, 3, 4
5, 6, 7, 8
13, 14, 15, 16
1, 2, 3, 4
5, 6, 7, 8
9, 10, 11, 12
1, 2, 3, 4
5, 6, 7, 8
9, 10, 11, 12
13, 14, 15, 16
参考文献
- [我的关于二维数组的回答] 如何在C和C ++中将多维数组(例如2D数组)及其指针作为函数参数使用
另请参阅
- 有关环形缓冲区的更多信息,包括完整的演示/库模块,请查看我在eRCaGuy_hello_world存储库中的containers_ring_buffer_FIFO.c文件。
cycleup()
函数非常简单,就像这样:array2d->i_start = (array2d->i_start + 1) % NUM_ROWS;
。看看这里。 这是一种高效的环形缓冲区方法。 - Gabriel Staples