我试图在C中写下John Conway的生命游戏,但我在向棋盘添加活细胞时遇到了麻烦。我写的处理它的功能非常慢。
思考过程:我想随机添加n个活细胞到板上,所以当细胞留下来活着时,得到一个随机(x,y)对,如果它死了,就让它活着。这样我可以保证n个细胞活着。
我对这个问题的理解不正确,还是我效率低下?为什么这么慢,我怎样才能让它更快?
void add_cells( int board[BOARD_WIDTH][BOARD_HEIGHT], int n )
{
// Randomly set n dead cells to live state.
while ( n )
{
int randX = rand() % BOARD_WIDTH;
int randY = rand() % BOARD_HEIGHT;
if( board[randX][randY] == 0 )
{
board[randX][randY] = 1;
n--;
}
}
}
答案 0 :(得分:2)
如果让我们说70%的细胞还活着,那就意味着你的程序必须在10次中找到7次其他细胞,这样就不必重复了。
您可以从剩余的单元格中弹出选定的单元格"将它设置为活动时的数组,并在此数组中随机选择单元格。我建议使用动态可调整大小的容器,这样你就不必操纵整个剩余的细胞了。每次弹出单元格时都会生成数组。这应该有助于节省更多时间。
答案 1 :(得分:0)
如果您的电路板在内存中是连续的,则无需再拨打rand()
两次。您可以使用rand() % (BOARD_WIDTH * BOARD_HEIGHT)
。
void add_cells(uint8_t board[BOARD_WIDTH][BOARD_HEIGHT], int n)
{
std::mt19937 eng;
uniform_int_distribution<int> dist(0, BOARD_WIDTH * BOARD_HEIGHT - 1);
while(n)
{
int index = dist(eng);
uint8_t* cell = (uint8_t*)board + index;
if(*cell == 0)
{
*cell = 1;
--n;
}
}
}
答案 2 :(得分:0)
有几个问题可能会解释您的问题有些缓慢:
在致电add_cells()
之前,电路板是否已初始化为0?如果电路板具有随机内容,找到死细胞可能需要很长时间,或者如果少于n
个细胞死亡则可能需要永久。
您确定board
是否已正确定义? 2D数组似乎更自然,y
是第一维,x
是第二维:使用int board[BOARD_HEIGHT][BOARD_WIDTH]
并交换randX
和randY
的索引值。< / p>
如果(n > 0)
使用否定add_cells()
进行调用,n
的测试可以防止无限循环。
如果n
很大,找到死细胞需要很长时间,因为随机拍摄的几率很小。
如果n
大于BOARD_WIDTH * BOARD_HEIGHT
或者死区数少于n
,则循环将永远迭代。
如果n
很大或者电路板只有几个死细胞,那么枚举死细胞并从死细胞中随机选择目标细胞会更有效。缺点是如果n
很小并且电路板有很多死区,这种方法会慢一些。
n
小的时间复杂度与死区的数量相比是 O(n),这很难被击败,并且在当前的硬件上应该非常快,但它会趋于朝 O(n * BOARD_WIDTH * BOARD_HEIGHT)如果n
很大或接近死区的数量, 效率低,且函数从不如果n
大于死细胞数,则结束。
如果在调用add_cells()
时已知该电路板为空,如果n
大于BOARD_WIDTH * BOARD_HEIGHT / 2
,则将所有单元设置为活动并选择更高效n
要杀死的细胞。
如果电路板不一定是空的,通过此功能,活动单元的数量将有助于确定哪种方法更好,以及是否至少有n
个死区,而不需要冗长的循环列举死细胞。
答案 3 :(得分:-2)
模数函数非常慢,请尝试(float)rand()/RAND_MAX*BOARD_WIDTH + 0.5
您也可以使用更快的兰特,请参阅here