Как сдвинуть массив влево c
Перейти к содержимому

Как сдвинуть массив влево c

  • автор:

Programming stuff

Есть ряд способов сдвинуть массив влево на N элементов. Можно взять и сделать N сдвигов по одному элементу, получив квадратичную сложность. Можно создать целевой массив по размеру исходного и вычислить положение каждого элемента после сдвига. Хорошо, но скорость линейна, затраты по памяти — тоже.
Если чутка подумать, то можно придумать реализацию, которая мутирует массив и дает линейную скорость и константные затраты по памяти. Но есть один очень элегантный способ – из 3-х строк на основе чудо Span of T из System.Memory:

public static void RotateLeft(int[] input, int direction) < input.AsSpan(0, direction).Reverse(); input.AsSpan(direction).Reverse(); input.AsSpan().Reverse(); >

Идея такая: чтобы сдвинуть массив из K элементов на N элементов влево, нужно перевернуть первые N элементов в массиве, затем последние K — N -1 элементов, а затем перевернуть весь массив:

// direction == 2, input.Length == 7 input.AsSpan(0, direction).Reverse(); // [2][1][3][4][5][6][7] input.AsSpan(direction).Reverse(); // [2][1][7][6][5][4][3] input.AsSpan().Reverse();// [3][4][5][6][7][1][2]

Получается два прохода по массиву, но зато с читабельностью решения все очень ОК.

26 комментариев:

Справедливости ради, хочу отметить, что это циклический сдвиг влево. Ответить Удалить

Не совсем понял мысль. Да, это одна из реализаций циклического сдвига влево. Просто, ИМХО, одна из самых кратких и выразительных. Удалить

nit: Мне показалось, что Vasya всего лишь хотел справедливо заметить, что слово «сдвиг» в заголовке и теле поста лучше бы заменить на «циклический сдвиг». Удалить

В своё время этот фокус произвёл на меня большое впечатление. минут 20 рисовал на листике пытаясь понять как этот трюк работает 🙂

Он же, но чуть с большим wow-эффектом (IMHO) используется в задачке Reverse Words: когда необходимое переставить слова в предложении в обратном порядке. Например: «Michael Jordan» => «Jordan Michael». Необходимо сделать «реверс» каждого слова и потом реверс всей строки целиком, что в конечном итоге даёт практически линейную сложность. Ответить Удалить

О! Отличный трюк.
З.Ы. Сложность-то линейная, просто коэффициент равен 2. Удалить

Фокус интересный. Но по поводу читабельности — не соглашусь. Оно же крайне не очевидно. Но элегантный, да Ответить Удалить

Ну такое. по этой теории каждый второй алгоритм можно зафукать :))) Удалить

Так гораздо понятнее, чем циклический сдвиг врукопашную.

Мне кажется, что без комментария с небольшим примером решение неочевидно. Но оно читаемо, поскольку состоит из 3 строк. После же того, как прогнан в голове/дебагере один пример, то решение садится в голове прочно. Удалить

Почему «затем последние K — N -1 элементов», если необходимо перевернуть K — N последних элементов? Ответить Удалить

Off-by-one error:) Удалить

В «Жемчужинах программирования» читал что-то подобное. я уже не помню, но там с помощью реверса решалась задача. Интуитивно восстановил алгоритм: Сложность 4N, дополнительной памяти не требуется.

Пример:
исходный массив: 1234567 сдвиг вправо на 3

Сдвиг массива

Сдвинуть элементы массива в указанном направлении (влево или вправо) и на указанное число шагов. Освободившиеся ячейки заполнить нулями. Выводить массив после каждого шага.

Если массив сдвигается на один шаг влево, то на место элемента с индексом i записывается тот элемент, который находится на месте i+1. То есть на место текущего элемента записывается следующий за ним. В последнюю ячейку массива записывать нечего. По условию задачи туда следует записать число 0.

Таким образом, сдвиг массива на один шаг влево — это цикл от первого элемента до предпоследнего включительно, в теле которого происходит запись значения из следующей ячейки в текущую ячейку ( arr[i] := arr[i+1] ). В предпоследнюю ячейку записывается последний элемент. После цикла присваивается 0 в последнюю ячейку массива.

Если массив сдвигается на один шаг вправо, то его следует «перебирать» с конца. На место элемента i присваивается стоящий перед ним (i-1). В освободившуюся первую ячейку записывается ноль.

Сдвиг массива на один шаг вправо — это цикл от последнего элемента до второго включительно, в теле которого происходит запись значения из предыдущей ячейки в текущую ( arr[i] := arr[i-1] ). После цикла в первую ячейку массива записывается ноль.

Количество шагов сдвига определяется внешним циклом.

Алгоритм решения данной задачи можно описать так:

  1. Запросить у пользователя количество шагов сдвига и направление. Условиться, что если вводится отрицательное целое, то сдвиг выполняется влево на указанное абсолютное значение, если вводится положительное число, то сдвиг вправо.
  2. Заполнить исходный массив и вывести его на экран.
  3. Выполнять внешний цикл столько раз, сколько шагов было указано.
    1. Если было введено отрицательное число, то выполнить цикл от первого элемента до предпоследнего, перезаписав в нем значение каждой очередной ячейки на значение последующей. Записать в последнюю ячейку 0.
    2. Иначе, выполнить цикл от последнего элемента до второго, записывая в каждую текущую ячейку значение предыдущей. В первую ячейку записать 0.
    3. Вывести на экран текущий массив.

    Посмотреть вариант кольцевого сдвига (когда вышедший за границу элемент массива записывается с другой его стороны) можно здесь.

    Pascal

    сдвиг массива паскаль

     
    const N = 9;
    var
    arr: array[1..N] of integer;
    qty: integer;
    i,j: byte;
    begin
    readln(qty);
    for i:=1 to N do begin
    arr[i] := i*100 + i*10 + i;
    write(arr[i]:4);
    end; writeln;
    for j:=1 to abs(qty) do begin
    if qty > 0 then begin
    for i:=N downto 2 do
    arr[i] := arr[i-1];
    arr[1] := 0;
    end
    else begin
    for i:=1 to N-1 do
    arr[i] := arr[i+1];
    arr[N] := 0;
    end;
    for i:=1 to N do
    write(arr[i]:4);
    writeln;
    end;
    end.
     

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

    Сдвиг влево:

    -4
    111 222 333 444 555 666 777 888 999
    222 333 444 555 666 777 888 999 0
    333 444 555 666 777 888 999 0 0
    444 555 666 777 888 999 0 0 0
    555 666 777 888 999 0 0 0 0
    Сдвиг вправо:

    5
    111 222 333 444 555 666 777 888 999
    0 111 222 333 444 555 666 777 888
    0 0 111 222 333 444 555 666 777
    0 0 0 111 222 333 444 555 666
    0 0 0 0 111 222 333 444 555
    0 0 0 0 0 111 222 333 444

    Язык Си

     
    #include < stdio.h>
    #define N 9
    main() int arr[N], qty, i, j;
    scanf("%d",&qty);
    for (i=0; i < N; i++) arr[i] = (i+1)*100 + (i+1)*10 + (i+1);
    printf("%4d",arr[i]);
    >
    printf("\n");
    for (j=0; j < abs(qty); j++) if (qty < 0) for (i=0; i < N-1; i++)
    arr[i] = arr[i+1];
    arr[N-1] = 0;
    > else for (i=N-1; i>0; i--)
    arr[i] = arr[i-1];
    arr[0] = 0;
    >
    for (i=0; i < N; i++)
    printf("%4d",arr[i]);
    printf("\n");
    >
    >

    Python

    сдвиг массива python (питон)

     
    qty = int(input())

    N = 9
    a = []
    for i in range(1,N+1):
    b = 100*i + 10*i + i
    a.append(b)
    print("%4d" % b, end='')
    print()

    for j in range(abs(qty)):
    if qty < 0:
    for i in range(N-1):
    a[i] = a[i+1]
    a[N-1] = 0
    elif qty > 0:
    for i in range(N-1,0,-1):
    a[i] = a[i-1]
    a[0] = 0
    for i in a:
    print("%4d" % i, end='')
    print()

    КуМир

     
    алг
    нач
    цел N=9
    цел таб массив[1:N]
    цел шаги, i, j
    ввод шаги
    нц для i от 1 до N
    массив[i] := i*100+i*10+i
    вывод массив[i]:4
    кц
    вывод нс
    нц для j от 1 до iabs(шаги)
    если шаги > 0 то
    нц для i от N до 2 шаг -1
    массив[i] := массив[i-1]
    кц
    массив[1] := 0
    иначе
    нц для i от 1 до N-1
    массив[i] := массив[i+1]
    кц
    массив[N] := 0
    все
    нц для i от 1 до N
    вывод массив[i]:4
    кц
    вывод нс
    кц
    кон

    В программе используется форматированный вывод, который доступен только в версии 2.x.

    Basic-256

     
    input qty
    N = 9
    dim arr(N)
    for i=0 to N-1
    arr[i] = (i+1)*100 + (i+1)*10 + (i+1)
    print arr[i] + " ";
    next i
    print
    for j=1 to abs(qty)
    if qty < 0 then
    for i=0 to N-2
    arr[i] = arr[i+1]
    next i
    arr[N-1] = 0
    else
    for i=N-1 to 1 step -1
    arr[i] = arr[i-1]
    next i
    arr[0] = 0
    endif
    for i=0 to N-1
    print arr[i] + " ";
    next i
    print
    next j

    Сдвинуть элементы массива на k позиций

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

    int tmp1, tmp2; tmp1 = a[0]; tmp2 = a[1]; for (int i = 0; i < size_array-2; i++) a[i] = a[i+2]; a[size_array-2] = tmp1; a[size_array-1] = tmp2; 

    если нужно сдвинуть на какое то другое кол-во позиций, то обычно применяют последовательный сдвиг. Ещё можно завести массив, равный сдвигу, скопировать туда начальные элементы (memcpy) остальные элементы сдвинуть (memmove) и скопировать с дополнительно массива назад элементы в конец исходного массива.,

    UPD: здесь есть очень интересные объяснения, как делать сдвиг.

    Циклически сдвинуть элементы массива влево

    Элементы массива циклически сдвинуть на k позиций влево
    Помогите пожалуйста написать программу. понимаю что все должно быть оч легко, но. В С++: 1. Дан.

    Сдвинуть циклически элементы одномерного массива на k позиций влево
    Тема и есть условие задачи. Сам же я застопорился на написании алгоритма сдвига :- #include.

    Все элементы массива X(30) циклически сдвинуть на n позиций влево
    Все элементы массива X(30) циклически сдвинуть на n позиций влево при помощи указателей

    Элементы линейного массива сдвинуть циклически на две позиции влево
    Дорогие форумчане помогите с переводом с pascal в C++ < of integer; i,j:integer; .

    Эксперт С++

    13663 / 10580 / 6322
    Регистрация: 18.12.2011
    Сообщений: 28,248
    См. ссылки внизу страницы
    Например Элементы массива циклически сдвинуть на k позиций влево
    Неэпический
    17849 / 10617 / 2049
    Регистрация: 27.09.2012
    Сообщений: 26,686
    Записей в блоге: 1
    Регистрация: 18.04.2020
    Сообщений: 90
    а код никак не может быть короче?
    6578 / 4563 / 1843
    Регистрация: 07.05.2019
    Сообщений: 13,726

    ЦитатаСообщение от Ste Посмотреть сообщение

    а код никак не может быть короче?

    1 2 3 4 5 6 7
    const size_t N = 4; int arr[N] = {1, 2, 3, 4}; int x = arr[0]; for (size_t i = 1; i  N; ++i) arr[i - 1] = arr[i]; arr[N - 1] = x;

    7428 / 5021 / 2891
    Регистрация: 18.12.2017
    Сообщений: 15,692
    87844 / 49110 / 22898
    Регистрация: 17.06.2006
    Сообщений: 92,604
    Помогаю со студенческими работами здесь

    Сдвинуть элементы массива циклически на M влево, перевернуть нечетные строки и посчитать простые числа
    Доброго времени суток. Помогите составить программу. Заранее благодарен. Тут несколько условий, не.

    Сформировать массив десятичных цифр числа А. Элементы массива цифр сдвинуть циклически влево на 1 позицию
    дано целое десятичное число А. Сформировать массив десятичных цифр числа А. Элементы массива цифр.

    Указатели: сдвинуть элементы циклически на 1 позицию влево
    Условие задачи: Заполните случайным образом одномерный массив из n элементов и здвиньте элементы.

    Одномерный массив. Сдвинуть элементы циклически на n позиций влево
    Ввести одномерный статический массив из k чисел. Сдвинуть элементы массива циклически на n позиций.

    Сдвинуть все элементы последовательности циклически на k позиций влево
    1. Дано целое число. Если число отрицательное, то необходимо вывести все четные числа, начиная со.

    Циклически сдвинуть все элементы матрицы влево в строках, которые начинаются с положительного элемента
    (((Там какая та задача из темы Массивов))) Для решения этой задачи: В матрице Z(4,5) сдвинуть все.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *