Функция циклического сдвига | Язык Паскаль

Функция циклического сдвига

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

Например, дан массив:
1 2 3 4 5 6
Кольцевой сдвиг вправо на 2 единицы:
5 6 1 2 3 4

Описание переменных:

Алгоритм решения задачи:

Если переменной p будет присвоено отрицательное значение, то пусть сдвиг будет выполняться влево. Если положительное, то вправо.

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

Далее идет описание одного шага внешнего цикла.

Если сдвиг происходит влево, то на место первого элемента становится второй, на место второго - третий и так далее. При кольцевом сдвиге на место последнего должен стать первый. Так как на место очередного элемента записывается следующий за ним, то первый элемент затрется. Поэтому его надо сохранить отдельно до выполнения внутреннего цикла. Внутренний цикл выполняется до предпоследнего элемента включительно. На предпоследнем элементе на его место записывается последний. После внутреннего цикла на место последнего элемента записывается ранее сохраненный первый элемент.

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

Программа на языке Паскаль:

const N = 10;
type
    arr = array[1..N] of integer;
var
    a: arr;
    i,j: byte;
    q: integer;
procedure shift(var m: arr; p: integer);
    var b: integer;
    begin
        if p < 0 then 
            for j:=1 to abs(p) do begin
                b := m[1];
                for i:=1 to N-1 do 
                    m[i] := m[i+1];
                m[N] := b;
            end
        else 
            for j:=1 to p do begin
                b := m[N];
                for i:=N downto 2 do 
                    m[i] := m[i-1];
                m[1] := b;
            end;
    end;
begin
    for i:=1 to N do begin
        a[i] := i;
        write(a[i],' ');
    end;
    writeln;
    readln(q);
    shift(a,q);
    for i:=1 to N do 
        write(a[i],' ');
    writeln;
end.

Примеры выполнения программы:

1 2 3 4 5 6 7 8 9 10 
-3
4 5 6 7 8 9 10 1 2 3 
1 2 3 4 5 6 7 8 9 10 
4
7 8 9 10 1 2 3 4 5 6

Описанный выше алгоритм проще для понимания, но не является оптимальным. Существуют другие алгоритмы сдвига. Например:

Надо сдвинуть влево на 3 элемента массив: 1 2 3 4 5 6 7 8
Выделяем два подсписка: (1 2 3)(4 5 6 7 8)
Переворачиваем списки: (3 2 1)(8 7 6 5 4).
Переворачиваем весь массив: 4 5 6 7 8 1 2 3