Вывод последовательности/массива "ёлочкой", "пирамидой" -- пример решения (вложенные циклы)

Пусть у нас есть задача:

Выведите его на экран "ёлочкой" последовательности чисел до $N$.
Например для $N=12$ вы должны получить:

1
2 3
4 5 6
7 8 9 10
11 12 ......

Эту задачу можно решить используя два подхода:

  1. Просто перебрать (обойти) массив (а в данном случае просто последовательность) так как мы это делаем для вывода элементов в строчку, но в определённые моменты выводить между элементами знак переноса строки и таким образом получить ёлочку.
  2. Рассмотреть ёлочку как таблицу из нескольких строк (их может быть и очень много) в которой каждая следующая строка длиннее предыдущей на $1$, а первая по своей длине $=1$.

Решение с циклом одного уровня

В этом подходе мы просто перебираем все числа до $n$ в цикле for, в каждом витке выводя очередное значение + иногда перенося строку:

var n, i, j, k:integer;
begin
  writeln('vvedite chislo N:');
  readln(n); // получаем число, до которого будем выводить ёлочку

  k:=1; // число символов которые можно вывести не перенося строку
  j:=0; // сколько мы вывели с последего переноса строки

  for i:=1 to N do
  begin

    write(i, ' ');   // просто выводим в ждом витке
    j := j + 1; // учтём, что мы вывели ещё один символ (для будущего переноса)

    if (j>=k) then // не пора ли переносить строку?
     begin
       writeln(); // перенос строки
       j:=0; // в новой строке ёлочки мы ещё ничего не вывели (сбрасываем счетчик)
       k:=k+1; // следубщий раз выведем на 1 символ больше до переноса строки
     end;

  end;

  readln();
end.  

Решение через вложенные циклы

Здесь мы рассмотрим код, иллюстрирующий второй подход:

Рассмотреть ёлочку как таблицу из нескольких строк (их может быть и очень много) в которой каждая следующая строка длиннее предыдущей на $1$, на первая по своей длине $=1$.

Ясно, что в таблице может быть сколько угодно строк (внешний цикл) + нам потребуется выводить каждую строку посимвольно (внутренний цикл).

При этом внешний цикл просто запускает вывод очередной строки и ничего не знает о том как именно эти строки выводятся -- его задача состоит просто в том, чтобы контролировать диапазон значений и заново запускать цикл вывода строки.

Очередной внутренний цикл вывода строки начинает свою работу с того значения $i$, на котором он остановился предыдущий раз. Поэтому мы инкрементируем $i$ в единственном месте -- а именно сразу после вывода на экран очередного значения.

Итак, решение №2:

var n, i, j, k:integer;
begin
  writeln('vvedite chislo N:');
  readln(n); // получаем число, до которого будем выводить ёлочку
  i:=1;
  k:=1;

  while (i<=n) do // просто контролируем диапазон
  begin
<h2></h2>
    for j:=1 to k do  // вывод очередной строки
      begin
        if (i<=n) then // если мы всё ещё в диапазоне
        begin
           write(i, ' '); // выводим очередное значение (с пробелом)
           i:=i+1; // готовим следующее
        end else
           break; // досрочный выход из цикла
      end;

    writeln(); // переносим строку
    k:=k+1; // следующая строка будет длиннее на 1 символ

  end;

  readln();
end.
     

Массив как источник данных

Безусловно, мы можем использовать в качестве источника данных для ёлочки и одномерный массив (в программе для инициализации его случайными числами используется процедура -- решим задачу первым способом без вложенных циклов с одним источником данных):


var n, i, j, k:integer;
  a: array [1..17] of integer;

// процедура заполнит массив случайными числами
procedure initRandArray(var a: array of integer);
var min, max, i: integer;
begin
   randomize(); // инициал. датчик случайных чисел (вызов стандартной процедуры)

   min := -5; // левая граница
   max := 10; // правая граница

   { обходим переданный массив
     и инициализируем массив случайными числами}
   for i:=low(a) to high(a) do
     a[i] := random(max + abs(min)) + min;
end;


begin  // начало тела программы

  N := 17; // число элементов массива

  initRandArray(a); // передаём по ссылке для заполнения случаными числами

  k:=1; // число символов которые можно вывести не перенося строку
  j:=0; // сколько мы вывели с последего переноса строки

  for i:=1 to N do
  begin

    write(a[i], ' ');   // выводим очередной элемент массива
    j := j + 1; // учтём, что мы вывели ещё один символ (для будущего переноса строки)

    if (j>=k) then // не пора ли переносить строку?
     begin
       writeln(); // перенос строки
       j:=0; // в новой строке ёлочки мы ещё ничего не вывели (сбрасываем счетчик)
       k:=k+1; // следубщий раз выведем на 1 символ больше до переноса строки
     end;

  end;


  readln();

end.