Существуют ли алгоритмы сортировки, которые учитывают ограничения конечной позиции и выполняются в O (n log n) времени?

Я ищу алгоритм сортировки, который оценивает минимальный и максимальный диапазон для каждого элемента 1. Проблемная область - это механизм рекомендаций, который объединяет набор бизнес-правил (ограничений) с оценочной оценкой (значением). Если у нас есть рекомендация, которую мы хотим рекламировать (например, специальный продукт или сделку) или объявление, которое мы хотим увидеть в верхней части списка (например, "Это очень важно, не забудьте подтвердить свой адрес электронной почты для участия в предстоящей акции!" ) или в нижней части списка (например, "Если вам понравились эти рекомендации, нажмите здесь для получения дополнительной информации" ), они будут куратором с определенным ограничением положения на месте. Например, это всегда должно быть верхнее положение, они должны быть в верхней части 10 или середине 5 и т.д. Этот шаг заготовки выполняется заранее и остается фиксированным в течение заданного периода времени, а по соображениям бизнеса должен оставаться очень гибким.

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


Итак, если бы мы сортировали char s, наши данные имели бы структуру

struct {
  char value;
  Integer minPosition;
  Integer maxPosition;
}

Где minPosition и maxPosition могут быть нулевыми (неограниченными). Если бы это было вызвано алгоритмом, где все ограничения позиций были нулевыми, или все minPosition были равны 0 или меньше, а все maxPositions были равны или превосходили размер списка, тогда выход был бы только char в по возрастанию.

Этот алгоритм будет переупорядочивать только два элемента, если бы те minPosition и maxPosition обоих элементов не были бы нарушены их новыми позициями. Алгоритм, основанный на вставке, который продвигает элементы в верхней части списка и переупорядочивает остальную часть, имеет очевидные проблемы в том, что каждый последующий элемент должен быть проверен после каждой итерации; в моей голове, что исключает такие алгоритмы для сложности O (n 3), но я не исключаю таких алгоритмов, не рассматривая доказательства обратного, если они представлены.

В выходном списке некоторые элементы будут не в порядке относительно их значения, тогда и только тогда, когда это задает набор ограничений по положению. Эти выходы по-прежнему действительны.

  • A действительный список - это любой список, в котором все элементы находятся в позиции, которая не противоречит их ограничениям.
  • Список оптимальный - это список, который нельзя переупорядочить, чтобы более точно соответствовать естественному порядку, не нарушая одно или несколько ограничений позиции. Недопустимый список никогда не является оптимальным. У меня нет строгого определения, которое я могу описать для "более близкого соответствия" между одним заказом. Тем не менее, я думаю, что довольно легко позволить интуиции направлять вас или выбрать что-то похожее на показатель расстояния.

    Несколько оптимальных порядков могут существовать, если несколько входов имеют одинаковое значение. Вы можете сделать аргумент, что приведенный выше абзац поэтому неверен, потому что любой может быть переупорядочен другому, не нарушая ограничений, и поэтому ни один из них не может быть оптимальным. Однако любая строгая дистанционная функция будет рассматривать эти списки как идентичные с тем же расстоянием от естественного порядка и, следовательно, допускается переупорядочение одинаковых элементов (поскольку это не-op). Я бы назвал такие выходы правильным, отсортированным порядком, который учитывает ограничения позиции, но несколько комментаторов указали, что мы действительно не возвращаем отсортированный список, поэтому давайте придерживаться "оптимального".

Например, следующие списки входных данных (в форме <char>(<minPosition>:<maxPosition>), где Z(1:1) указывает a Z, который должен быть в начале списка, а M(-:-) обозначает M, который может быть в любой позиции в конечном списке, а естественный порядок (отсортированный по значению) - A...M...Z) и их оптимальные порядки.

Input order
A(1:1) D(-:-) C(-:-) E(-:-) B(-:-)
Optimal order
A      B      C      D      E

Это тривиальный пример, показывающий, что естественный порядок преобладает в списке без ограничений.


Input order
E(1:1) D(2:2) C(3:3) B(4:4) A(5:5)
Optimal order
E      D      C      B      A

В этом примере показано, что полностью ограниченный список выводится в том же порядке, в котором он задан. Вход уже является действительным и оптимальнымсписок. Алгоритм должен продолжать работать в O (n log n) времени для таких входов. (Наше начальное решение способно коротко закоротить любой полностью ограниченный список для запуска в линейном времени, я добавил пример как для определения целей оптимального и действительного, так и из-за того, что некоторые алгоритмы подкачки, которые я рассматривал, рассматривали как худший случай. )


Input order
E(1:1) C(-:-) B(1:5) A(4:4) D(2:3)
Optimal Order
E      B      D      A      C

E привязан к 1:1, поэтому он является первым в списке, хотя он имеет самое низкое значение. A аналогично ограничено 4:4, поэтому оно также выходит из естественного порядка. B имеет по существу одинаковые ограничения для C и может появляться в любом месте в конечном списке, но B будет перед C из-за значения. D может находиться в позициях 2 или 3, поэтому он появляется после B из-за естественного упорядочения, но до C из-за его ограничений.

Обратите внимание, что окончательный порядок верен, несмотря на то, что он дико отличается от естественного порядка (который все еще A, B, C, D, E). Как объяснялось в предыдущем абзаце, ничто в этом списке не может быть переупорядочено без нарушения ограничений одного или нескольких элементов.


Input order
B(-:-) C(2:2) A(-:-) A(-:-)
Optimal order
A(-:-) C(2:2) A(-:-) B(-:-)

C остается невозмутимым, поскольку он уже находится в единственном действительном положении. B переупорядочивается до конца, потому что его значение меньше, чем A. На самом деле, будут дополнительные поля, которые различают два A, но с точки зрения алгоритма они идентичны и сохраняют ИЛИ, изменяя их порядок ввода, является оптимальным решением.


Input order
A(1:1) B(1:1) C(3:4) D(3:4) E(3:4)
Undefined output

Этот вход недействителен по двум причинам: 1) A и B оба ограничены положением 1 и 2) C, D и E ограничены диапазоном, чем может удерживаться только 2 элемента. Другими словами, диапазоны 1:1 и 3:4 чрезмерно ограничены. Тем не менее, согласованность и законность ограничений выполняются с помощью проверки UI, поэтому официально это не проблема алгоритмов, если они являются неправильными, и алгоритм может возвращать наилучший порядок или исходный порядок в этом случае. Передача такого типа в алгоритм можно рассматривать как undefined поведение; все может случиться. Итак, для остальной части вопроса...


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

В настоящее время мы установили индивидуальную сортировку (со сложностью выполнения O (n 2)) и обоснованно доказал, что он работает для всех входов, ограничения по которым действительны и согласованы (например, нет забронированы для заданной позиции или диапазона позиций).

Существует ли алгоритм сортировки, который гарантированно вернет оптимальный конечный порядок и будет работать быстрее, чем O (n 2). 3

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

Однако, чем больше я думаю об этом, алгоритм, который работает в O (n log n), не может работать корректно с этими ограничениями. Интуитивно, такие алгоритмы основаны на выполнении n сравнений log n раз. Log n достигается за счет использования механизма разделения и покоя, который сравнивает только определенные кандидаты для определенных позиций.

Другими словами, для любого алгоритма сортировки O (n log n) существуют списки ввода с допустимыми ограничениями позиции (например, контрпримеры), где элемент-кандидат сравнивается с элементом (или диапазоном в случае Quicksort и вариантов) с/к которым он не может быть заменен, и поэтому никогда не переместится в правильную конечную позицию. Если это слишком расплывчато, я могу придумать встречный пример для mergesort и quicksort.

Напротив, алгоритм сортировки O (n 2) делает исчерпывающие сравнения и всегда может перенести элемент в его правильную конечную позицию.

Чтобы задать реальный вопрос:Является ли моя интуиция правильной, когда я полагаю, что сортировка O (n log n) не гарантируется для нахождения действительного порядка? Если да, можете ли вы предоставить более конкретные доказательства? Если нет, почему бы и нет? Существуют ли другие существующие исследования по этому классу проблем?


1: мне не удалось найти набор условий поиска, которые указывают мне на какую-либо конкретную классификацию такого алгоритма сортировки или ограничений; поэтому я задаю некоторые основные вопросы о сложности. Если есть термин для этого типа проблемы, отправьте его.

2: Валидация - отдельная проблема, достойная собственного исследования и алгоритма. Я уверен, что существование допустимого порядка может быть доказано в линейном времени:

  • Выделить массив кортежей длины, равный вашему списку. Каждый кортеж представляет собой целочисленный счетчик k и двойное значение v для относительного веса присваивания.
  • Пройдите список, добавив дробное значение каждого ограничения позиции элемента к соответствующему диапазону и увеличив его счетчик на 1 (например, диапазон 2: 5 в списке из 10 добавляет 0,4 к каждой из 2,3,4 и 5 в нашем списке кортежей, увеличивая счетчик каждого также)
  • Пройдите список кортежей и
  • Если ни одна запись не имеет значения v больше суммы ряда от 1 до k 1/k, существует действительный порядок.
  • Если есть такой кортеж, позиция, в которой он находится, является чрезмерной; вызывать исключение, регистрировать ошибку, использовать массив удвоений для исправления элементов проблемы и т.д.

Изменить:. Этот алгоритм проверки фактически является O (n 2). В худшем случае каждый элемент имеет ограничения 1:n, вы в конечном итоге переходите свой список из n кортежей n раз. Это по-прежнему не имеет отношения к сфере действия вопроса, поскольку в реальной проблемной области ограничения выполняются один раз и не изменяются.

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

3: Это, по общему признанию, немного преждевременная оптимизация. Наше первоначальное использование для этого - для довольно небольших списков, но мы смотрим на расширение до более длинных списков, поэтому, если мы сможем оптимизировать сейчас, мы получим небольшой прирост производительности и большую производительность. И кроме того, мое любопытство вызвано, и если есть какие-то исследования по этой теме, я хотел бы увидеть это и (надеюсь) узнать из него.

Ответ 1

О существовании решения: вы можете рассматривать это как двудольный орграф с одним набором вершин (U), являющимися значениями k, а другое множество (V) k рангов (от 1 до k) и дугой от каждой вершины в U до ее действительных рангов в V. Тогда существование решения эквивалентно максимальному согласованию, являющемуся биекцией. Один из способов проверить это - добавить исходную вершину с дугой в каждую вершину в U и вершину слитка с дугой из каждой вершины в V. Присвойте каждому ребру емкость 1, затем найдите максимальный поток. Если это k, то есть решение, иначе нет.

http://en.wikipedia.org/wiki/Maximum_flow_problem

- edit-- O (k ^ 3) solution: Сначала сортируйте, чтобы найти отсортированный ранг каждой вершины (1-k). Затем рассмотрим ваши значения и ранжируем как 2 набора k вершин, U и V, с взвешенными ребрами из каждой вершины в U ко всем своим законным рангам в V. Вес для назначения каждого ребра равен расстоянию от рангов вершин в отсортированных заказ. Например, если U составляет от 10 до 20, то естественный ранг 10 равен 1. Ребро от значения 10 до ранга 1 будет иметь вес нуля, а ранг 3 будет иметь вес 2. Затем предположим, что все отсутствующие края существуют и назначить им бесконечный вес. Наконец, найдите "МИНИМАЛЬНОЕ СОВЕРШЕНСТВОВАНИЕ ВЕСА" в O (k ^ 3).

http://www-math.mit.edu/~goemans/18433S09/matching-notes.pdf

Это не использует тот факт, что юридические ранги для каждого элемента из U смежны, что может помочь сократить время работы до O (k ^ 2).

Ответ 2

Вот что мы с коллегой придумали. Я думаю, что это решение O (n 2), которое возвращает действительный, оптимальный порядок, если он существует, и самое близкое возможное усилие, если начальные интервалы были чрезмерно ограничены. Я только что подправил несколько вещей о реализации, и мы все еще пишем тесты, поэтому есть шанс, что он не будет работать так, как рекламируется. Это чрезмерно ограниченное условие обнаруживается довольно легко, когда оно происходит.

Для начала все упрощается, если вы нормализуете свои входы, чтобы иметь все ненулевые ограничения. В линейном времени, то есть:

  • для каждого элемента ввода
  • Если элемент не имеет минимальной позиции, установите его в 1
  • если элемент не имеет максимальной позиции, установите его в длину вашего списка

Следующая цель состоит в том, чтобы построить список диапазонов, каждый из которых содержит все элементы-кандидаты, которые имеют этот диапазон и упорядочен по оставшейся емкости диапазона, поэтому восходящий так изменяется с наименьшим количеством оставшихся пятен, а затем начинается положение диапазона, затем конечное положение диапазона. Это можно сделать, создав набор таких диапазонов, затем отсортировав их в O (n log n) с помощью простого компаратора.

Для остальной части этого ответа диапазон будет простым объектом, таким как

class Range<T> implements Collection<T> {
   int startPosition;
   int endPosition;
   Collection<T> items;

   public int remainingCapacity() {
       return endPosition - startPosition + 1 - items.size();
   }

   // implement Collection<T> methods, passing through to the items collection
   public void add(T item) {
       // Validity checking here exposes some simple cases of over-constraining
       // We'll catch these cases with the tricky stuff later anyways, so don't choke
       items.add(item);
   }
}

Если элемент A имеет диапазон 1:5, постройте объект range(1,5) и добавьте A к его элементам. Этот диапазон имеет оставшуюся емкость 5 - 1 + 1 - 1 (max - min + 1 - size) = 4. Если элемент B имеет диапазон 1:5, добавьте его в существующий диапазон, который теперь имеет емкость 3.

Тогда это относительно простой вопрос выбора лучшего элемента, который по очереди подходит к каждой позиции 1 => k. Итерируйте диапазоны в упорядоченном порядке, отслеживая лучший подходящий элемент, с завихрением, которое вы прекратите искать, если вы достигли диапазона, который имеет оставшийся размер, который не может вписаться в его оставшиеся позиции. Это эквивалентно простому расчету range.max - текущая позиция + 1 > range.size(что, вероятно, может быть упрощено, но я считаю это наиболее понятным в этой форме). Удалите каждый элемент из своего диапазона по мере его выбора. Удалите каждый диапазон из своего списка, поскольку он опустел (необязательно, итерация пустого диапазона не даст кандидатов). Это плохое объяснение, поэтому давайте сделаем один из наших примеров из вопроса. Обратите внимание, что C(-:-) был обновлен до дезинфицированного C(1:5), как описано выше.

Input order
E(1:1)    C(1:5)    B(1:5)    A(4:4)    D(2:3)
Built ranges (min:max) <remaining capacity> [elements]
(1:1)0[E] (4:4)0[A] (2:3)1[D] (1:5)3[C,B]

Найти лучшее для 1

  Consider (1:1), best element from its list is E
  Consider further ranges?
    range.max - current position + 1 > range.size ?
    range.max = 1; current position = 1; range.size = 1;
    1 - 1 + 1 > 1 = false; do not consider subsequent ranges
Remove E from range, add to output list

Найти лучшее для 2; текущий список диапазонов:

(4:4)0[A] (2:3)1[D] (1:5)3[C,B]
  Consider (4:4); skip it because it is not eligible for position 2
  Consider (2:3); best element is D
  Consider further ranges?
     3 - 2 + 1 > 1 = true; check next range
  Consider (2:5); best element is B
End of range list; remove B from range, add to output list

Дополнительным упрощающим фактором является то, что возможности не нужно обновлять или диапазоны переупорядочиваться. Элемент удаляется, только если остальные диапазоны с более высокой степенью сортировки не будут нарушены. Остальная емкость никогда не проверяется после начальной сортировки.

Найти лучшее для 3; выход теперь E, B; текущий список диапазонов:

(4:4)0[A] (2:3)1[D] (1:5)3[C]
  Consider (4:4); skip it because it is not eligible for position 3
  Consider (2:3); best element is D
  Consider further ranges?
     same as previous check, but current position is now 3
     3 - 3 + 1 > 1 = false; don't check next range
Remove D from range, add to output list

Найти лучшее для 4; выход теперь E, B, D; текущий список диапазонов:

(4:4)0[A] (1:5)3[C]
  Consider (4:4); best element is A
  Consider further ranges?
     4 - 4 + 1 > 1 = false; don't check next range
Remove A from range, add to output list

Выход теперь E, B, D, A, и остается один элемент, который нужно проверить, поэтому он добавляется в конец. Это список результатов, который мы хотели иметь.

Этот процесс сборки является самой длинной частью. По своей сути, это простой алгоритм сортировки выбора n 2. Ограничения диапазона работают только для того, чтобы сократить внутренний цикл, и нет обратной петли или рекурсии; но худший случай (я думаю) по-прежнему равен сумме я = 0 n (n - i), которая n 2/2 - n/2.

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

У меня есть несколько других контр-примеров, которые сорвали мои предыдущие алгоритмы, в том числе хороший пример, который показывает несколько обнаружений избыточного ограничения в том же списке входных данных, а также то, как конечный результат ближе всего к оптимальному, как позволяют ограничения. В то же время, пожалуйста, публикуйте любые оптимизации, которые вы можете видеть, и особенно любые примеры счетчиков, где этот алгоритм делает объективно неверный выбор (т.е. Приходит к недопустимому или субоптимальному выводу, когда он существует).


Я не буду принимать этот ответ, потому что я специально спросил, можно ли это сделать лучше, чем O (n 2). Я еще не обернулся вокруг подхода к удовлетворению ограничений в ответе @DaveGalvin, и я никогда не делал проблемы с максимальным потоком, но я думал, что это может быть полезно для других, чтобы посмотреть.

Кроме того, я обнаружил, что лучший способ получить достоверные тестовые данные - начать с допустимого списка и рандомизировать его: для 0 → я создать случайное значение и ограничения, так что min < я < Максимум. (Опять же, отправляя его, потому что он занимал меня дольше, чем следовало придумать, а другие могли бы найти его полезным.)

Ответ 3

Неверно *. Я предполагаю, что вы имеете в виду среднее время выполнения O (n log n) на месте, нестабильное, офф-лайн. Большинство алгоритмов сортировки, которые улучшают среднее время выполнения буферов O (n ^ 2), например tim sort, полагаются на то, что сравнение двух элементов в sub set даст тот же результат в супер-наборе. Более медленный вариант Quicksort будет хорошим подходом к вашим ограничениям диапазона. Наихудший случай не изменится, но средний случай, скорее всего, уменьшится, и алгоритм будет иметь дополнительное ограничение существующего вида.

Является ли... O (n log n) sort не гарантируется для нахождения действительного порядка?

Все популярные алгоритмы сортировки, о которых я знаю, гарантированно найдут заказ до тех пор, пока будут выполнены ограничения. Формальный анализ (конкретное доказательство) находится на каждой странице algorithems wikepedia.

Существуют ли другие исследования по этому классу проблем?

Да; есть много журналов, таких как IJCSEA с исследованиями сортировки.

*, но это зависит от вашего среднего набора данных.