Уровень динамических вложенных циклов - PullRequest
6 голосов
/ 15 ноября 2009

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

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 ...

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

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

Ответы [ 4 ]

9 голосов
/ 15 ноября 2009

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

void PrintLoop(int maxloop, int maxvalue)
{
   if (maxloop<=0) return ;
   // print something here...
   for (int i=0;i<maxmalue;i++){
      PrintLoop(maxloop-1, maxvalue);
   }
}
5 голосов
/ 15 ноября 2009

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

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);
    }   
  }
}
3 голосов
/ 17 ноября 2009

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

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

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
    }
}
0 голосов
/ 15 ноября 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...