Существует ряд проблем с рекурсивным решением, в том числе:
- Вы не передаете значение поиска в рекурсивную функцию, поэтому разные рекурсивные вызовы могут в конечном итоге искать разные значения.
- Вы не проверяете, посещали ли вы уже данную ячейку, поэтому рекурсия не прекращается.
Вот две версии кода, которые не вылетают.
conn29.c
- минимально фиксированный
Этот код исправляет точку 2, а результат демонстрирует точку 1.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
enum { SIZE = 13 };
static
void connectedvals(char array[SIZE][SIZE], char newarray[SIZE][SIZE], int x, int y)
{
if (newarray[x][y] != 0)
return;
int height = array[x][y];
newarray[x][y] = array[x][y];
int up = y + 1;
int down = y - 1;
int left = x - 1;
int right = x + 1;
if (up < SIZE)
{
if (array[x][up] == height)
{
newarray[x][up] = height;
up++;
connectedvals(array, newarray, x, up);
}
}
if (down >= 0)
{
if (array[x][down] == height)
{
newarray[x][down] = height;
down--;
connectedvals(array, newarray, x, down);
}
}
if (right < SIZE)
{
if (array[right][y] == height)
{
newarray[right][y] = height;
right++;
connectedvals(array, newarray, right, y);
}
}
if (left >= 0)
{
if (array[left][y] == height)
{
newarray[left][y] = height;
left--;
connectedvals(array, newarray, left, y);
}
}
}
static void dump_array(const char *tag, int rows, int cols, char array[rows][cols])
{
printf("%s (%dx%d):\n", tag, rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
putchar(' ');
if (array[i][j] == 0)
putchar('.');
else
printf("%d", array[i][j]);
}
putchar('\n');
}
}
int main(void)
{
char base[SIZE][SIZE] = { 0 };
char trace[SIZE][SIZE] = { 0 };
// srand(time(0));
for (int i = 0; i < SIZE; i++)
{
for (int j = 0; j < SIZE; j++)
{
base[i][j] = (rand() % 12);
if (base[i][j] > 9)
base[i][j] = 0;
if ((rand() % 4) == 0)
base[i][j] = 5;
}
}
dump_array("Base array", SIZE, SIZE, base);
int i0 = rand() % SIZE;
int j0 = rand() % SIZE;
while (base[i0][j0] != 5)
{
i0 = rand() % SIZE;
j0 = rand() % SIZE;
}
printf("i0 = %2d, j0 = %2d, base[%2d][%2d] = %d\n", i0, j0, i0, j0, base[i0][j0]);
connectedvals(base, trace, i0, j0);
dump_array("Connected region", SIZE, SIZE, trace);
return 0;
}
выход
Base array (13x13):
7 5 5 . . . . 3 7 5 3 9 4
3 8 1 8 2 7 3 5 5 5 8 6 5
5 4 5 6 . 5 5 5 . . 7 9 5
5 3 9 5 5 3 . 5 . 4 5 9 5
5 1 5 5 5 3 . 5 . 5 5 5 .
. 5 7 5 3 2 2 4 8 . 8 3 6
5 1 3 5 6 5 . 2 7 4 2 7 1
8 . 4 5 5 7 9 . 5 . 5 . 7
5 9 5 2 . 1 5 5 3 . . 5 5
. 7 1 8 3 3 5 9 . . 3 3 3
. 5 1 5 9 9 5 8 5 2 5 . 8
4 2 9 9 . 5 5 5 . 5 2 4 3
5 2 5 2 3 5 4 1 5 9 5 5 5
i0 = 5, j0 = 3, base[ 5][ 3] = 5
Connected region (13x13):
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . 5 5 3 . . . . . . .
. . . 5 . 3 . . . . . . .
. . . 5 . 2 2 4 . . . . .
. . . 5 . . . . . . . . .
. . . 5 5 7 . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
conn11.c
- исправлено полностью
Возможно, еще есть место для совершенствования, но это работает.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
enum { SIZE = 13 };
extern void connectedvals(char array[SIZE][SIZE], char newarray[SIZE][SIZE], int x, int y, int value);
void connectedvals(char array[SIZE][SIZE], char newarray[SIZE][SIZE], int x, int y, int value)
{
/*printf("a[%2d][%2d] = %d\n", x, y, array[x][y]);*/
if (array[x][y] != value || newarray[x][y] != 0)
return;
newarray[x][y] = value;
if (y + 1 < SIZE)
connectedvals(array, newarray, x + 0, y + 1, value);
if (y - 1 >= 0)
connectedvals(array, newarray, x + 0, y - 1, value);
if (x + 1 < SIZE)
connectedvals(array, newarray, x + 1, y + 0, value);
if (x - 1 >= 0)
connectedvals(array, newarray, x - 1, y + 0, value);
}
static void dump_array(const char *tag, int rows, int cols, char array[rows][cols])
{
printf("%s (%dx%d):\n", tag, rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
putchar(' ');
if (array[i][j] == 0)
putchar('.');
else
printf("%d", array[i][j]);
}
putchar('\n');
}
}
int main(void)
{
char base[SIZE][SIZE] = { 0 };
char trace[SIZE][SIZE] = { 0 };
// srand(time(0));
for (int i = 0; i < SIZE; i++)
{
for (int j = 0; j < SIZE; j++)
{
base[i][j] = (rand() % 12);
if (base[i][j] > 9)
base[i][j] = 0;
if ((rand() % 4) == 0)
base[i][j] = 5;
}
}
dump_array("Base array", SIZE, SIZE, base);
int i0 = rand() % SIZE;
int j0 = rand() % SIZE;
while (base[i0][j0] != 5)
{
i0 = rand() % SIZE;
j0 = rand() % SIZE;
}
printf("i0 = %2d, j0 = %2d, base[%2d][%2d] = %d\n", i0, j0, i0, j0, base[i0][j0]);
connectedvals(base, trace, i0, j0, base[i0][j0]);
dump_array("Connected region", SIZE, SIZE, trace);
return 0;
}
выход
Base array (13x13):
7 5 5 . . . . 3 7 5 3 9 4
3 8 1 8 2 7 3 5 5 5 8 6 5
5 4 5 6 . 5 5 5 . . 7 9 5
5 3 9 5 5 3 . 5 . 4 5 9 5
5 1 5 5 5 3 . 5 . 5 5 5 .
. 5 7 5 3 2 2 4 8 . 8 3 6
5 1 3 5 6 5 . 2 7 4 2 7 1
8 . 4 5 5 7 9 . 5 . 5 . 7
5 9 5 2 . 1 5 5 3 . . 5 5
. 7 1 8 3 3 5 9 . . 3 3 3
. 5 1 5 9 9 5 8 5 2 5 . 8
4 2 9 9 . 5 5 5 . 5 2 4 3
5 2 5 2 3 5 4 1 5 9 5 5 5
i0 = 5, j0 = 3, base[ 5][ 3] = 5
Connected region (13x13):
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . 5 5 . . . . . . . .
. . 5 5 5 . . . . . . . .
. . . 5 . . . . . . . . .
. . . 5 . . . . . . . . .
. . . 5 5 . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
Испытательный жгут практически идентичен между двумя программами. Разница заключается в списке аргументов для начального вызова connectedvals()
, потому что две реализации имеют разное количество аргументов.
Выбор размера 13
не случаен; это приводит к аккуратному результату с генератором случайных чисел. Матрица генерируется «в случайном порядке», за исключением того, что результат намеренно отклоняется в сторону чисел 0 и 5. Вы вполне можете получить другой результат от функции rand()
на вашем компьютере; Я тестировал MacBook Pro с MacOS 10.14.5 Mojave, используя GCC 9.1.0 для компиляции.
Предусмотрено использование времени в качестве начального числа - раскомментирование одной строки. Однако для начального тестирования определенность (повторяемость) более выгодна, чем случайность. Есть много лучших способов посева rand()
, чем использование времени; это довольно предсказуемо. Однако такие уточнения выходят за рамки вопроса.
Обратите внимание на использование enum { SIZE = 13 };
. Изменяя только один номер, вся программа адаптируется к новым размерам.