Эффективный список приоритетов

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

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

У кого-нибудь есть лучшее решение?


person ladi    schedule 14.07.2010    source источник
comment
Сколько предметов? Сохраняются ли они где-нибудь, если да, то как?   -  person Lazarus    schedule 14.07.2010
comment
Расскажите подробнее о том, насколько эффективными должны быть вставка, извлечение (приоритетных элементов) и удаление относительно друг друга.   -  person Artelius    schedule 14.07.2010
comment
Я хотел бы сначала оценить элементы, а затем получить первые x лучших элементов в правильном порядке. Так как есть много вставок, вставка должна быть довольно эффективной. Возврат может быть менее эффективным.   -  person ladi    schedule 14.07.2010
comment
Как x соотносится с n? х ‹= 100? x близко к n/2 что?   -  person    schedule 14.07.2010
comment
Кучи - это стандартный способ сделать это, но вы, кажется, возражаете против того факта, что это переупорядочивает содержимое кучи при удалении верхнего элемента. Почему это проблема? Что ты действительно пытаешься сделать?   -  person andand    schedule 14.07.2010


Ответы (4)


Кучи кажутся очень подходящими, и кажется, что вы делаете это неправильно.

Скажем, вам нужны верхние x элементов (как это x соотносится с n, кстати?)

Что вы делаете, так это помещаете все в максимальную кучу и получаете верхний x.

Вместо этого я предлагаю вам использовать минимальную кучу ровно x элементов.

Первые x элементов, которые вы вставляете в кучу.

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

Если входящий элемент больше min, вы увеличиваете min до входящего элемента и просеиваете его в кучу. В худшем случае это должно быть время logx.

После этого (за время nlogx) вы можете извлечь элементы из кучи в отсортированном порядке за время O(xlogx).

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


Если вы действительно хотите, чтобы вставки были сверхбыстрыми и не очень заботились о поиске, вы также можете сделать следующее.

Вставьте элементы в вектор (массив с амортизированным временем вставки O (1)) в том порядке, в котором они появляются.

Используйте алгоритм выбора, чтобы найти x-й по величине элемент (за время O (n), но константы могут быть большими). Скажи, что это число С.

Теперь пройдитесь по массиву, сравнивая каждый элемент с S, и выберите элементы размером с S.

Если x имеет разумный размер и сравним с n (например, n/2 или что-то в этом роде), это может сработать нормально, но если x мал по сравнению с n, я бы предложил использовать мини-кучу.

person Community    schedule 14.07.2010
comment
Я не думал об этом таким образом. Это выглядит очень многообещающе. - person ladi; 14.07.2010

Хм. Пропустить списки? У них должна быть вставка O (log n) (как очередь на основе кучи), но получение верхнего элемента должно быть O (1) [включая его удаление]. Их можно даже реализовать с помощью алгоритма блокировки без блокировки.

person Maciej Piechotka    schedule 14.07.2010
comment
Кучи лучше списков пропуска, если вы используете их правильно. Используйте мини-кучу из x элементов, когда вам нужен верхний x. Вам не нужно строить дерево/кучу всех n. Просто х. - person ; 14.07.2010
comment
Извините - моя вина, я неправильно прочитал текст (я понял, что он хочет быстрого опроса, даже ценой медленного добавления). - person Maciej Piechotka; 15.07.2010

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

В операции Add() вы просто сравниваете элемент с наихудшим значением в списке и, если он лучше, вы меняете текущий наихудший элемент с добавленным элементом. Это занимает O(k) времени в наихудшем случае для вставки, потому что вам нужно найти элемент, который в настоящее время имеет наихудший результат. Однако в среднем это O(1), так как по мере того, как вы добавляете в список более качественные элементы, вероятность того, что вам придется произвести обмен, стремится к 0 (то есть вы не на самом деле добавление каких-либо элементов).

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

person Mau    schedule 14.07.2010
comment
Вместо списка, если вы используете min-heap (см. мой ответ), наихудшее время - O (logK). В остальном аналогично. На самом деле использование min-heaps, как это вполне стандартный метод для этой проблемы! (Когда x мало по сравнению с n). - person ; 14.07.2010

JDK имеет встроенный класс pqueue (java.util.PriorityQueue), основанный на алгоритме кучи.

Извините, я только что увидел немного о кучах, которые не соответствуют вашим потребностям. Можете ли вы объяснить, почему? Вы можете написать собственный компаратор (или сделать ваши товары сопоставимыми), и PriorityQueue упорядочит ваши товары соответствующим образом.

person dty    schedule 14.07.2010
comment
Насколько я его понимаю, он считает getNext за O(log n) неприемлемым. - person Maciej Piechotka; 14.07.2010
comment
Проблема, похоже, в том, что ladi хочет иметь возможность получить x первых предметов, не удаляя ни один из них. Обычно эта операция не поддерживается списками приоритетов. - person Michael Borgwardt; 14.07.2010
comment
Я хотел бы оценить некоторые элементы и получить только n лучших элементов. Поэтому я бродил, есть ли какие-либо структуры данных, которые содержат только самые высокие баллы, но предлагают интерфейс списка. Это означает, что я могу последовательно пройтись по списку самых результативных предметов. Я мог бы, конечно, использовать очередь с приоритетом, основанную на алгоритме кучи, который имеет вставку O (log n) и извлечение O (n), получить элементы с наивысшей оценкой и добавить их в список. Мне просто было интересно, есть ли что-то лучше этого. - person ladi; 14.07.2010
comment
@ladi: Не уверен, что вы подразумеваете под поиском O (n) - извлечение верхнего элемента из кучи - это O (log n). Только если вам нужно найти конкретный (не минимальный) элемент, это поиск O (n). Если все, что вы можете сделать, это сравнить 2 элемента и определить, какой из них больше, то ничто не будет асимптотически быстрее, чем куча для проблемы, на которую вы смотрите. - person j_random_hacker; 14.07.2010