Форум программистов, компьютерный форум, киберфорум
C для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.87/245: Рейтинг темы: голосов - 245, средняя оценка - 4.87
Заблокирован

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

26.06.2013, 21:13. Показов 51630. Ответов 50
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток,

есть задача - нужно написать функцию, которая сдвигает массив array[] размером size на shift элементов.
соответственно, чтобы двигать вправо shift больше нуля, а влево наоборот.

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

не пишите пожалуйста код, помогите с логикой задачи.

Раньше я делал вот так -

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
void arrayShift(int array[], int size, int shift) {
    int temp[size];
    int i;
    
    for ( i = 0; i < size; i++ ) {
        temp[( i + shift ) % size] = array[i];
    }
    
    for (i = 0; i < size; i++) {
        array[i] = temp[i];
    }
}
но требованиям задачи это не отвечало, сейчас ищу более оптимальный вариант.

ткните носом в ошибки меня говнокодера.

спасибо (-:
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
26.06.2013, 21:13
Ответы с готовыми решениями:

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

Функция циклического сдвига строк и колонок в матрице
Нужно написать функцию циклического сдвига строк и колонок в матрице. Короче, пока ждал ответа, вроде сделал все: void...

Ошибка в коде сдвига элементов массива
не пойму,почему выводит ошибку #include&lt;stdio.h&gt; #include&lt;conio.h&gt; #define N 6 int main(void) {int arr, i, j, y, p; ...

50
6 / 6 / 0
Регистрация: 28.06.2013
Сообщений: 15
28.06.2013, 12:56
Студворк — интернет-сервис помощи студентам
97 перестановок на 100 элементов при смещении 3. При условии
"под буфер в цикле нельзя выделять целый массив, можно только одну переменную, тоесть нужно максимально оптимизировать использование памяти.
сложность алгоритма не должна превышать O(N)."
И в чём проблема?
0
Модератор
Эксперт по электронике
8982 / 6749 / 921
Регистрация: 14.02.2011
Сообщений: 23,874
28.06.2013, 13:10
Цитата Сообщение от _Faeton_ Посмотреть сообщение
под буфер в цикле нельзя выделять целый массив, можно только одну переменную,
если целочисленные то можно и без временной переменной обойтись показывал уже как
Цитата Сообщение от _Faeton_ Посмотреть сообщение
97 перестановок на 100 элементов при смещении 3.
а при четырех? пяти?
а у меня количество перестановок равно размеру массива не зависимо на сколько сдвинуть нужно
0
6 / 6 / 0
Регистрация: 28.06.2013
Сообщений: 15
28.06.2013, 13:26
Процитирую код ValeryS:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void Reverse(int * arr, int sz)
{
for(int i=0;i<sz;i++)
   {
      int tmp=arr[i];
      arr[i]=arr[sz- i-1];
      arr[sz- i-1]=tmp;
   }
 }
 
void MyROL( int * arr,  // адрес массива
                  int  ofset, // на сколько смещаем
                  int  sizeArray) // размер массива
{
 Reverse(arr,ofset);
  Reverse(&arr[ofset],sizeArray-ofset;
 Reverse(arr,sizeArray);
}
Где здесь "а у меня количество перестановок равно размеру массива не зависимо на сколько сдвинуть нужно " ?!
каждая функция Reverse производит количество перестановок равное параметру sz. В данном случае это ofset, sizeArray-ofset, sizeArray

Добавлено через 6 минут
на 100 элементов смещение 5 даст 95 перестановок это очевидно
2
Модератор
Эксперт по электронике
8982 / 6749 / 921
Регистрация: 14.02.2011
Сообщений: 23,874
28.06.2013, 13:50

Не по теме:

Цитата Сообщение от _Faeton_ Посмотреть сообщение
Процитирую код ValeryS:
Для цитаты нажми "Цитата" а то не удобно читать


теперь по теме
Цитата Сообщение от _Faeton_ Посмотреть сообщение
каждая функция Reverse производит количество перестановок равное параметру sz.
считаем
каждый реверс работает с половиной массива

Не по теме:

C++
1
for(int i=0;i<sz;i++)
это опечатка:(
не заметил, спасибо что обратил внимание("Спасибу" поставить пока не могу)
здесь массив не развернется, точнее развернется два раза


нужно читать так
C++
1
for(int i=0;i<sz/2;i++)
получаем
ofset/2+(sizeArray-ofset)/2+sizeArray/2=
(ofset+sizeArray-ofset+sizeArray)/2=
2*sizeArray/2=sizeArray;
0
6 / 6 / 0
Регистрация: 28.06.2013
Сообщений: 15
28.06.2013, 14:13
Тот алгоритм, что я приводил компактней и быстрей, так как:
1. количество перестановок всегда меньше чем количество в массиве и равно max(Count-Shift, Shift)
2. нет лишних дёрганий дополнительных функций (Reverse), так как всё в одном цикле

Добавлено через 14 минут
кстати что это за вызов Reverse c параметрами ofset/2, (sizeArray-ofset)/2, sizeArray/2 ?
если принять, что ofset=1 то... не будет работать не так ли?
0
Модератор
Эксперт по электронике
8982 / 6749 / 921
Регистрация: 14.02.2011
Сообщений: 23,874
28.06.2013, 14:17
Цитата Сообщение от _Faeton_ Посмотреть сообщение
если принять, что ofset=1 то... не будет работать не так ли?
смотрим
0)123456789
1)123456789
2)198765432
3)234567891
как видишь сработало
за сим раскланиваюсь
Работы много, на остальное отвечу позже
0
6 / 6 / 0
Регистрация: 28.06.2013
Сообщений: 15
28.06.2013, 14:20
ФАНТАСТИКА!!!
int ofset=1;
ofset/2==1 ?!

короче параметры должны быть ofset, (sizeArray-ofset), sizeArray
а это в сумме 2*sizeArray... Как то так
0
Модератор
Эксперт по электронике
8982 / 6749 / 921
Регистрация: 14.02.2011
Сообщений: 23,874
28.06.2013, 14:28
Цитата Сообщение от _Faeton_ Посмотреть сообщение
ofset/2==1 ?!
нет 1/2==0
C++
1
2
3
4
5
6
7
8
9
void Reverse(int * arr, int sz)
 {
   for(int i=0;i<sz/2;i++)
    {
     int tmp=arr[i];
     arr[i]=arr[sz- i-1];
     arr[sz- i-1]=tmp;
   }
 }
Reverse(arr, 1)
for(int i=0;i<1/2;i++)
for(int i=0;i<0;i++)
цикл не сработает перестановки не будет
Цитата Сообщение от _Faeton_ Посмотреть сообщение
короче параметры должны быть ofset, (sizeArray-ofset), sizeArray
параметры функции!!
а цикл работает в два раза меньше
перестановка подразумевает все таки 2 числа
0
6 / 6 / 0
Регистрация: 28.06.2013
Сообщений: 15
28.06.2013, 14:58
да точно ты же поменял в цикле sz на sz/2.
Но тем не менее я выше писал чем лучше мой алгоритм
0
 Аватар для uburuntu
95 / 95 / 58
Регистрация: 04.10.2012
Сообщений: 189
29.06.2013, 20:11
Раскопал ящик с исходниками за первый семестр, здесь активно используется теория чисел:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int lcm(int n, int m)
{
    int tmp;
    while (n%m!=0)
    {
        tmp = m;
        m = n%m;
        n = tmp;
    }
    return m;
}
 
void shift_a(double *a, int n, int k)
{
    int i, j, m;
    double tmp;
    m = lcm(n,k);
    for (j=0; j < m; j++)
    {
        tmp = a[(j+(n/m-1)*k)%n];
        for (i=(n/m)-1; i > 0; i--)
        {
            a[(j+i*k)%n] = a[(j+(i-1)*k)%n];
        }
        a[j] = tmp;
    }
}
Однако вариант с переворотами тоже писал и он однозначно лучше по скорости и отказоустойчивости.

@_Faeton_, предявите рабочую программу для тестирования, тогда и проверим какой алгоритм быстрее.
1
3 / 3 / 0
Регистрация: 23.06.2013
Сообщений: 13
29.06.2013, 20:15
Вот мне интересно как люди на этом сайте расставляют приоритеты?
0
Модератор
Эксперт по электронике
8982 / 6749 / 921
Регистрация: 14.02.2011
Сообщений: 23,874
29.06.2013, 22:12
@_Faeton_,
пересмотри свой алгоритм
не правильно работает когда объем не кратен сдвигу
вот пример
массив 12345
сдвиг на 2
должно получится 45123
0)12345
1)12543
2)14523
3)54123 !!!!!!!
и когда сдвиг больше половины объема
123456
сдвиг на 5
должно быть 234561
0)123456
1)623451 !!!!!!

123456
сдвиг на 4
345612
0)123456
1)163452
2)563412 !!!!
Цитата Сообщение от _Faeton_ Посмотреть сообщение
Думаю идея ясна.
идея интересная но для определенных случаев
для общего случая "доработать напильником"

Добавлено через 1 минуту
да вот код на котором я проверял
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main()
{
int data[]={1,2,3,4,5,6};
int Count=sizeof(data)/sizeof(int);
int Shift=4;
    
for(int i=Count-Shift-1; i>=0; i--)
 {
 int nTemp=data[i+Shift];
 data[i+Shift]=data[i];
 data[i]=nTemp;
 }
   return 0;    
}
может я чего то не так понял?
0
 Аватар для uburuntu
95 / 95 / 58
Регистрация: 04.10.2012
Сообщений: 189
29.06.2013, 22:15
Цитата Сообщение от ValeryS Посмотреть сообщение
для общего случая "доработать напильником"
Общий случай я написал вверху, там как раз используется наименьшее общее кратное.
0
Модератор
Эксперт по электронике
8982 / 6749 / 921
Регистрация: 14.02.2011
Сообщений: 23,874
29.06.2013, 22:24
@uburuntu, а ты каким боком к этому алгоритму ?
Цитата Сообщение от _Faeton_ Посмотреть сообщение
for(int i=Count-Shift-1; i>=0; i--)
{
nTemp=data[i+Shift];
data[i+Shift]=data[i];
data[i]=nTemp;
}
идея то у него интересная менять местами последние элементы с предыдущими
но если сдвиг не кратен размеру то получаются артефакты

Добавлено через 1 минуту
Цитата Сообщение от uburuntu Посмотреть сообщение
Общий случай я написал вверху,
если ты имеешь ввиду 30 пост то у тебя 2 цикла у _Faeton_ один
0
Эксперт С++
 Аватар для Thinker
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5
29.06.2013, 22:38
Цитата Сообщение от ValeryS Посмотреть сообщение
словами он выглядит так
1 переворачиваем одну часть массива
2 переворачиваем другую часть массива
3 переворачиваем весь массив
классно! здесь каждый элемент обрабатывается ровно 2 раза. Вариант, когда каждый элемент обрабатывается ровно 1 раз:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include<stdio.h>
#include<math.h>
#define N 5
int Nod(int a, int b)
{
    while (a && b)
        if (a >= b)
           a %= b;
        else
           b %= a;
    return a | b;
}
 
void Print(int *a, int n)
{
   int i;
   for(i = 0; i < n; ++i)
      printf("%3d ", a[i]);
   printf("\n");        
}
 
void arrayShift(int *a, int n, int shift)
{
   int i, j, step, buf, lim;
   shift = shift % n;
   if (shift < 0)
      shift += n;
   step = Nod(n, shift);        
   lim = step;
   while (lim <= shift)
   {
      for(i = 0; i < step; ++i)
      {
         buf = a[N - i - 1];
         for(j = N - i - 1; j >= 0; j -= step)  
            a[j + step] = a[j];
         a[step - i - 1] = buf;   
      }
      lim += step;
   }
}
 
int main()
{
   int a[N], i;
   for(i = 0; i< N; ++i)
      a[i] = i + 1;
   Print(a, N);
   arrayShift(a, N, 2);
   Print(a, N);
   return 0;        
}
не знаю какой по скорости быстрее, писал когда-то для развлечения, может заинтересует. в плане скорости интересно, конечно, сравнить.
1
Модератор
Эксперт по электронике
8982 / 6749 / 921
Регистрация: 14.02.2011
Сообщений: 23,874
29.06.2013, 23:05
Цитата Сообщение от Thinker Посмотреть сообщение
не знаю какой по скорости быстрее
про скорость тоже не знаю тестировать надо но у тебя ветвления и остаток очень сильно снижают скорость
и потом
Цитата Сообщение от Thinker Посмотреть сообщение
int Nod(int a, int b)
{
* * while (a && b)
* * * * if (a >= b)
* * * * * *a %= b;
* * * * else
* * * * * *b %= a;
* * return a | b;
}
это наименьший общий делитель?
возьмем 3 и 2
вернется 3
a=1 b =2
a|b=3

Добавлено через 12 минут
Цитата Сообщение от Thinker Посмотреть сообщение
классно! здесь каждый элемент обрабатывается ровно 2 раза.
ну здесь трудно сказать сколько раз он обрабатываться

мы поменяли местами 3 и 5 за один проход(темповую переменную не берем в расчет)
как сказать? мы обработали и 3 и 5, два элемента но проход то один

Добавлено через 2 минуты
Я бы так сказал
количество перестановок равно количеству элементов массива
0
6 / 6 / 0
Регистрация: 28.06.2013
Сообщений: 15
30.06.2013, 10:41
1. Я не писал, что это готовая программа. Я привёл ключевой алгоритм ядра задачи. Поэтому и писал , "полагаю что идея ясна" на примере сдвига вправо.
2. Пожалуйста не путайте цель задачи (алгоритм) с оптимизацией производительности кода.
К тому же оптимизация кода у uburuntu просто отвратительная, так как направо и налево происходит умножение и деление в циклах (в трёх циклах).
НО там заложена таже идея что и в моём алгоритме. Только выполнена коряво(со значительным ущербом для производительности).
Код ValeryS как я писал всегда производит количество перестановок равное количеству элементов (так же в трёх циклах)
3. Кстати я писал, что количество перестановок равно max(Count-Shift, Shift)... неспроста наверно? Разумеется в полном коде это необходимо учесть.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void ShiftArray(double* arDouble, int nCount, int nShift)
{
    nShift=nShift%nCount;
    if(nShift>(nCount>>1)) nShift=nShift-nCount;
    else if (-nShift>(nCount>>1)) nShift=nShift+nCount;
    double nTemp;
    if(nShift>0)
    {
        for(int i=nCount-nShift-1; i>=0; i--)
        {
            nTemp=arDouble[i+nShift];
            arDouble[i+nShift]=arDouble[i];
            arDouble[i]=nTemp;
        }
    }
    else
    {
        for(int i=-nShift; i<nCount; i++)
        {
            nTemp=arDouble[i+nShift];
            arDouble[i+nShift]=arDouble[i];
            arDouble[i]=nTemp;
        }
    }
}
3
Эксперт С++
 Аватар для Thinker
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5
30.06.2013, 11:21
Цитата Сообщение от ValeryS Посмотреть сообщение
это наименьший общий делитель?
возьмем 3 и 2
вернется 3
a=1 b =2
a|b=3
это наибольший общий делитель. ищется правильно, после выхода из цикла либо a, либо b равно 0, так что a|b все нормально. после выхода из цикла тот элемент который не равен 0, тот и есть НОД.


Цитата Сообщение от ValeryS Посмотреть сообщение
ну здесь трудно сказать сколько раз он обрабатываться
судя по алгоритму, легко подсчитать - ровно 2 раза обрабатывается каждый элемент.

Добавлено через 3 минуты
Цитата Сообщение от ValeryS Посмотреть сообщение
остаток очень сильно снижают скорость
НОД можно вычислять и совсем без делений, а только с использованием битовых операций:
Самый быстрый алгоритм Евклида вычисления НОД

Добавлено через 4 минуты
Цитата Сообщение от ValeryS Посмотреть сообщение
но проход то один
два прохода: сначала массив развивается на 2 части и идем по каждой из них, а потом еще раз по всему массиву, итого два прохода и каждый элемент "трогаем" ровно 2 раза
0
Модератор
Эксперт по электронике
8982 / 6749 / 921
Регистрация: 14.02.2011
Сообщений: 23,874
30.06.2013, 11:34
Цитата Сообщение от Thinker Посмотреть сообщение
судя по алгоритму, легко подсчитать - ровно 2 раза обрабатывается каждый элемент.
Я не про это
а про то что элементы обрабатываются парой
и что получается ???
элемент обрабатывается 2 раза (*2) но парой (/2 )


вот как сказать опять же меняем местами 3 и 5
каждый элемент обрабатывается один раз да? Да
но ведь за один проход

Ну и слава богу
я ведь в алгоритм не вникал так взгляд кинул
Цитата Сообщение от Thinker Посмотреть сообщение
после выхода из цикла либо a, либо b равно 0, так что a|b все нормально.
а где здесь равно 0?
Цитата Сообщение от Thinker Посмотреть сообщение
int Nod(int a, int b)
{
* * while (a && b)
* * * * if (a >= b)
* * * * * *a %= b;
* * * * else
* * * * * *b %= a;
* * return a | b;
}
или это не здесь
извини времени нет совсем вникать, посему вопросы могут быть глупыми
вечером, если время будет, посижу покумекаю
но было бы лучше если прокомментируешь
любишь ты шифроватся

Добавлено через 1 минуту
Цитата Сообщение от ValeryS Посмотреть сообщение
а где здесь равно 0?
Все врубился , когда отправил
у тебя while а я читал if
тупой наверное

Добавлено через 1 минуту
Цитата Сообщение от Thinker Посмотреть сообщение
два прохода: сначала массив развивается на 2 части и идем по каждой из них,
да
но проход то в половину массива (ну из за того что пары чисел)
0
Эксперт С++
 Аватар для Thinker
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5
30.06.2013, 11:40
Цитата Сообщение от ValeryS Посмотреть сообщение
Я
а где здесь равно 0?
C++
1
2
while (a && b)
...
Цитата Сообщение от ValeryS Посмотреть сообщение
Я не про это
а про то что элементы обрабатываются парой
и что получается ???
элемент обрабатывается 2 раза (*2) но парой (/2 )

вот как сказать опять же меняем местами 3 и 5
каждый элемент обрабатывается один раз да? Да
но ведь за один проход
тебя путает то, что парами элементы обрабатываются. это не важно, хоть тройками, все равно мы обращаемся к каждому элементу в отдельности. и совершается два прохода по массива, так как он двухэтапный, но очень красивый



Цитата Сообщение от ValeryS Посмотреть сообщение
но было бы лучше если прокомментируешь
вычисление нод? так я же ссылку привел с алгоритмами
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
30.06.2013, 11:40
Помогаю со студенческими работами здесь

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

Функция циклического сдвига побитово вправо
Форумчане, приветствую! Подскажите почему не работает сдвиг вправо? Программа компилируется, но сдвига не происходит. Сверился с...

Программа циклического сдвига элементов массива
Помогите!Срочно! Составить программу циклического сдвига элементов массива А(10) на 5 позиций влево.Заранее спасибо)))

Описать процедуру циклического сдвига массива
Полиморфизм.Описать процедуру MoveLeft(A,N,k)1|MoveRight(A,N,k)2, осуществляющую циклический сдвиг элементов вещественного массива A...

Ошиба циклического сдвига
Вот задание. Дана действительная квадратная матрица порядка n. 1) осуществить циклический сдвиг элементов прямоугольной матрицы на N...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Модель здравосохранения 18. Чем здоровее работник, тем быстрее выгорает
anaschu 24.05.2026
Имитационная модель корпоративного здравоохранения: что показывает математика Сегодня в модели рабочего коллектива на AnyLogic появились три новые механики — выгорание через накопленную усталость,. . .
Модель здравосохранения 17. Планы на выгорание
anaschu 23.05.2026
Вот конкретная схема реализации: В классе Работник добавить: накопленнаяУсталость — растёт каждый час работы, снижается в перерывы и болезни коэффициентПрезентеизма — снижает продуктивность. . .
Изменение цветов в палитре gif файла aka фавикона
russiannick 23.05.2026
Изменение цветов в палитре gif файла, юзаемого как фавиконка в составе html-файла, помещенная в base64, средствами нативного Java Script, навеянное сном в майский день. Для работы необходим браузер,. . .
Модель здравосохранения 16. Слишком хорошие и здоровые сотрудники уходят, недовольные зарплатой
anaschu 23.05.2026
Отладка увольнений и настройка производительности Сегодня во второй половине дня разобрались с механикой увольнений и настроили коэффициент сложности заданий. Вот что было сделано. . . .
Как я стал коммунистом))) Модель сохранения здоровья сотрудников, запись блога номер 15
anaschu 23.05.2026
Внезапно хорошее здоровье сотрудников не нужно капиталистам?))
Модель здравоСохранения 15. Как мы чинили AnyLogic модель рабочего коллектива: сочленение диаграммы состояний болезней и поломок в ресурспул
anaschu 23.05.2026
Как мы чинили AnyLogic модель рабочего коллектива Сегодня разобрались с пятью багами, из-за которых модель либо падала с ошибкой, либо давала совершенно бессмысленные результаты. Каждый баг был. . .
Диалоги с ИИ
zorxor 23.05.2026
Насколько я понимаю - Вы - Искусственный Интеллект. Это так? Да, всё верно. Я — искусственный интеллект. Я представляю собой большую языковую модель, созданную для помощи в самых разных задачах. . . .
Модель здравосохранения 14. Собираем всю модель вместе.
anaschu 22.05.2026
Модель собрана. В будущих постах на видео я покажу, как она работает. В этом посте запускаем её, проверяем результаты и разбираем что можно с ней делать дальше. Перед запуском проверяем. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru