Задать вопрос
@1eg10n

Как «выпрямить» кольцевой буфер c ограниченной доп.памятью?

Добрый день!

Не подскажете: функцию, алгоритм или переформулировку
Необходимо "выпрямить" кольцевой буфер c ограниченной доп.памятью.
Доступ к элементу кольцевого буфера O(1).
Размерность буфера до 0x10000.

Упрощенный пример: Буфер (5, 6, 7, 1, 2, 3, 4). Доп. памяти есть под 2 элемента.
P.S. На случай алгоритмов сортировок - в нем не хранятся последовательные числа.
  • Вопрос задан
  • 276 просмотров
Подписаться 1 Средний 10 комментариев
Решения вопроса 1
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Ваша задача - сделать циклический сдвиг массива на k позиций влево на месте, с O(1) дополнительной памяти.
Вот код:
void ShiftLeft(std::vector<int> &a, int k) {
  int n = a.size();
  int cycles = std::gcd(n, k);
  for (int start = 0; start < cycles; ++start) {
    int tmp = a[start];
    int i = start;
    while (true) {
      int next = i + k;
      if (next >= n) next -= n;
      if (next == start) break;
      a[i] = a[next];
      i = next;
    }
    a[i] = tmp;
  }
}


Работает это так: на место элемента вставет элемент на k позиций правее. Возьмем первый элемент, запомним его в tmp, поставим на его место тот, кто там должен быть. Освободилось место, поставим на него опять того, кто там должен быть и так далее. Рано или поздно мы вернемся к первому элементу. Но там уже стоит второй. Тут можно выйти из цикла и поставить на нужное место тот, кого мы сохранили в tmp. Но мы могли обойти не весь массив, как, например в случае n=6, k=2. Начав с 0 мы тут подвинем элементы 0,2,4, но не 1,3,5. Всего будет циклов gcd(n, k), и они все идут со сдвигом 1. Поэтому можно начинать с каждого из нескольких первых элементов.

Додуматься до этого можно так: сдвиг на 1 позицию понятно как циклом while сделать-то и одной переменной tmp. А на несколько? Надо только заметить что элементы разбиваются на циклы.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
mayton2019
@mayton2019
Bigdata Engineer
Автор мне кажется ты решаешь две разных задачи.
Первое - кольцевой буфер. Его не надо сортировать и его API
обычно очень простой. Это блокирующие push/pop или там атомарный
peek или проверка на пустоту. Они работают быстро и в этом их преимущество.

Если ты задумал очереди с приоритетами то посмотри например пирамиду (heap).
Ответ написан
Комментировать
@apevzner
Это то же самое, что поменять местами две неравные "половинки" одного массива.

1) Реверсируем каждую из половинок (т.е., первый элемент станет последним, второй - предпоследним и т.д. Это тривиальный алгоритм, который я оставляю пытливому читателю:

{5, 6, 7}, {1, 2, 3, 4)
|
{7, 6, 5}, {4, 3, 2, 1}

2) Реверсируем массив целиком:
{1, 2, 3, 4},{5, 6, 7}

Время - O(N), доп. памяти надо - 1 штука (а можно и без нее, если элементами являются числа).

В принципе, это классический, хорошо известный алгоритм.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы