2009-11-15 2 views
6

Я пытаюсь выяснить простой способ обработки динамического уровня вложенных петель. Рассмотрим следующую функцию, которая принимает 2 параметра: #num циклов и максимальное значение.Динамический уровень вложенных петель

void PrintLoop(int maxloop, int maxvalue) 

PrintLoop(1,2); 
// output 
0 
1 

PrintLoop(2,2); 
// output 
0, 0 
0, 1 
1, 0 
1, 1 

PrintLoop(3,2); 
// output 
0, 0, 0 
0, 0, 1 
0, 1, 0 
0, 1, 1 
1, 0, 0 
1, 0, 1 
1, 1, 0 
1, 1, 1 

Etc ...

Есть ли способ, чтобы написать функцию, которая может генерировать это «динамические вложенные циклы» поведение?

Спасибо за любую помощь

+3

С учетом функции 'PrintLoop (m, n)', обратите внимание, что все, что вы делаете, составляет от 0 до 'n^m' в базе' n'. –

+0

Это выглядит очень много, как домашнее задание, какой код вы пробовали до сих пор и на что вы застряли? – mlibby

ответ

9

Да, это возможно, и для реализации этой концепции «recursion» часто используется:

void PrintLoop(int maxloop, int maxvalue) 
{ 
    if (maxloop<=0) return ; 
    // print something here... 
    for (int i=0;i<maxmalue;i++){ 
     PrintLoop(maxloop-1, maxvalue); 
    } 
} 
+1

Ну, рекурсия - это * означает *, чтобы реализовать это, а не название концепции. –

+0

Рекурсия - путь, да. Но я пропустил любые заявления о печати ... – Stephan202

+1

@ Stephan202, конечно, я * мог * писать заявления, но мне что-то говорит, что это домашнее задание, поэтому лучше придерживаться общих советов ... –

0

В Ada вы могли бы сделать DECLARE блок после получения вход пользователя; затем установите для вашего цикла значение 1 .. Read_In_Loop_Control_Value, а затем вложенный цикл для печати целых чисел из 1 .. Read_In_Number_Per_Line.

5

Pavel's answer показывает, как выполнить рекурсию. Однако функция, которая принимает только два аргумента (число циклов и максимальное значение), не имеет достаточного контекста для фактической печати чисел, как в вашем примере. Для этого вам нужно будет отслеживать дополнительную информацию. Один из способов сделать это, является следующие:

void _print_loop(int *values, int width, int cur_col, int max) { 
    if (cur_col == width) { 
    for (int i = 0; i < width; i++) { 
     printf("%d%c", values[i], (i < width - 1) ? ' ' : '\n'); 
    } 
    } else { 
    for (int i = 0; i < max; i++) { 
     values[cur_col] = i; 
     _print_loop(values, width, cur_col + 1, max); 
    } 
    } 
} 

void print_loop(int width, int max) { 
    int values[width]; 
    memset(values, 0, width * sizeof(int)); 
    _print_loop(values, width, 0, max); 
} 

Теперь print_loop(3, 2) ведет себя, как и ожидалось.

Edit: на самом деле, один может написать функцию с двумя аргументами, чтобы сделать это, за счет использования static переменных, которые инициализируются при получении положительного width аргумента. После этого этапа инициализации функция выполняет свою рекурсию с использованием отрицательных значений. Очевидно, что полученный код ужасен, но я выложу его в любом случае, для полноты картины:

void print_loop(int width, int max) { 
    static int max_width; 
    static int *values; 

    if (width > 0) { 
    max_width = width; 
    if ((values = calloc(width, sizeof(int))) == NULL) { 
     perror("calloc"); 
     exit(EXIT_FAILURE); 
    } 
    print_loop(-width, max); 
    free(values); 
    } 
    else if (width == 0) { 
    for (int i = 0; i < max_width; i++) { 
     printf("%d%c", values[i], (i < max_width - 1) ? ' ' : '\n'); 
    } 
    } 
    else { 
    for (int i = 0; i < max; i++) { 
     values[-width - 1] = i; 
     print_loop(width + 1, max); 
    } 
    } 
} 
+0

Спасибо за подробный ответ. Я ожидал, что эта проблема должна быть решена с помощью рекурсий. Хотя, я надеялся, что может быть механизм, чтобы сделать это исключительно с использованием итераций.Языки программирования нуждаются в обновлении :) –

+0

Там * есть * довольно простой способ сделать это, не используя рекурсию. См. Мой комментарий к исходному вопросу. –

3

Вы можете использовать рекурсию или вы можете явно сохранять состояние каждого контура и управление состояниями в одном цикле.

В этом случае это означает хранение массива счетчиков. Каждое исполнение основного цикла продвигает самый внутренний счетчик и все внешние счетчики, чьи внутренние соседи «переносятся». Самый высокий счетчик действует как охранник.

void printloop(int maxloop, int maxvalue) { 
    unsigned int counters[maxloop+1]; // C99 for the win 
    memset(counters, 0, sizeof(counters)); 

    while(!counters[maxloop]) { 
     int i; 
     char *sep=""; 
     for(i=maxloop; i-->0;) { 
      printf("%s%d",sep,counters[i]); 
      sep=","; 
     }; 
     printf("\n"); 
     for(i=0; counters[i]==maxvalue; i++) // inner loops that are at maxval restart at zero 
      counters[i]=0; 
     ++counters[i]; // the innermost loop that isn't yet at maxval, advances by 1 
    } 
} 
Смежные вопросы