Клавіша збільшення та зменшення клавіш у двійковій міні-купі


17

У багатьох обговореннях бінарної купи зазвичай використовується лише клавіша зменшення, яка підтримується операцією для міні-купи. Наприклад, розділ 6.1 CLR та ця сторінка вікіпедії . Чому клавіша збільшення зазвичай не вказана для min-heap? Я думаю, що можна зробити це в O (висота) шляхом ітеративного заміщення збільшеного елемента (x) мінімумом своїх дітей, поки жоден з його дітей не перевищить x.

напр

IncreaseKey(int pos, int newValue)
{
   heap[pos] = newValue;
   while(left(pos) < heap.Length)
   {
      int smallest = left(pos);
      if(heap[right(pos)] < heap[left(pos)])
         smallest = right(pos);
      if(heap[pos] < heap[smallest])
      { 
         swap(smallest, pos);
         pos= smallest;
      }
      else return;
   }   
}

Чи правильно сказане вище? Якщо ні, то чому? Якщо так, чому не вказано ключ збільшення для min-heap?


1
Прочитавши всі відповіді, я б сказав, це дивний упущення, ймовірно, спричинене історично першим використанням min-heap в алгоритмі Dijkstra.
maaartinus

3
Звичайно, ви завжди можете реалізовувати ключ збільшення, використовуючи видалення з подальшим вставкою, а само видалення може бути реалізовано як ключ зменшення (до -∞) з подальшим удаленням-хв.
davmac

Коментар @maaartinus - правильна відповідь.
макс

Відповіді:


6

Запропонований вами алгоритм просто переосмислити. І дійсно - якщо ви збільшите значення елемента в min-heap, а потім перезавантажте його піддір, тоді ви закінчитеся з легальною min-heap.


то не значить, чому CLR або список Вікіпедії збільшують клавішу для підтримуваної операції? Мені
якось введено в

Я згоден, що це вводить в оману, але я не бачу жодної помилки в алгоритмі.
Шаул

5

Причина того, що ваша операція не вказана в тому, що вона не просто зацікавлена ​​у всіх операціях, які можна легко здійснити за допомогою певної структури даних, а навпаки. З огляду на набір операцій, який є найбільш ефективним способом (з точки зору простору та часу) для здійснення цих операцій. (Але я до цього додаю ще пізніше)

Бінарні купи реалізують чергу пріоритетів структури абстрактних даних даних, яка запитує операції is_empty, add_element (ключ зі своїм пріоритетом), find_min та delete_min. Більш розширені черги також дозволяють зменшити пріоритет ключа (у min_heap) або навіть збільшити його. Насправді ви дали реалізацію.

Два зауваження. Ваша операція використовується в функції heapify, яка ефективно створює купу з масиву. У іншому випадку ваша операція повторюється (починаючи з останньої клавіші).

Тоді, головне, ваш код використовує положення вузла. Для чистої структури даних черга пріоритетів, яка обманює. Ця структура даних просить виконати певну операцію, задану ключем. Отже, щоб зменшити або збільшити пріоритетність елемента, спершу доведеться його знайти. Я думаю, що це основна причина, по якій вона не перелічена.


1
Дякую за пояснення. Однак у CLR клавіші зменшення також є позиція як вузол як параметр.
GatotPujo

Ти правий. Я не міг знайти причину для цієї асиметрії у визначенні черг пріоритетів у розділі 6.5 CLRS. Зверніть увагу, ключ збільшення не використовується в Heapsort, застосуванні цього розділу. Здається, асиметрія між збільшенням і зменшенням пов'язана лише з тим, як використовується структура даних в алгоритмі Дійкстри. Там (використовуючи міні-купу) деякі вибрані вузли можуть стати більш терміновими і переміщуються «вгору» у купу.
Гендрик Ян

0

Я думаю, що перше, що слід врахувати, - що це підтримувана операція?

Чи відповідає "вставлення значення певним, фіксованим ключем" (наприклад, для ключів, узятих із цілої області, вставки з ключем = 3), що підтримується операцією для мінімальної купи?

Ні, тому що цю операцію можна тривіально реалізувати за допомогою більш загальних підтримуваних операцій. Аналогічно, введення одразу двох елементів може бути здійснено за допомогою існуючої insertоперації.

З іншого боку, insertоперацію неможливо визначити інакше, ніж викрити деталі реалізації. Це майже те саме для операцій, перелічених на сторінці вікіпедії, за heapifyвинятком, які, можливо, можуть бути реалізовані послідовністю insert.

Іншими словами, є елементарні операції, надані на тип, які тісно пов'язані з деталями реалізації, щоб вони добре працювали, і є інші операції, які не дотримуються цього правила, і, таким чином, можуть бути реалізовані як комбінації канонічних.

Зважаючи на це визначення, чи вважаєте ви, що ключ-ключ може бути реалізований виключно з іншими підтримуваними операціями, без втрати продуктивності? Якщо так, то це не підтримується операція згідно з наведеним вище визначенням, інакше ви цілком можете мати рацію.

Напевно, визначення підтримуваної операції, яку я надаю, є моїм, наскільки я знаю. Це не формально, і, таким чином, підлягає обговоренню (хоча мені це здається досить зрозумілим). Однак я би радий, якби хтось міг надати джерело, яке чітко і однозначно визначає, що підтримується операція для типів даних, або принаймні визначає її в кращих термінах, ніж моє (це визначення, наведене в CLR? У мене немає копії ).

Мій другий пункт стосуватиметься того, як ми визначаємо пріоритетну чергу (яка є причиною розвитку бінарних груп). Чи increase_keyнеобхідна операція для цього типу даних, тобто для правильного його використання?

Як ви бачите, мій кут стосується визначень. Я дійсно не даю відповіді на ваші запитання, лише деякі вказівки, тому покращення вітаються.


1
випадок використання зразка може бути, якщо я хочу підтримувати пріоритетну чергу об’єкта на основі найменш використовуваних (наприклад, щоб я міг легко видаляти найменш використовувані об'єкти). Я можу використовувати міні-купу з останньою датою доступу в якості свого ключа. Якщо доступ до об’єкта, його ключ потрібно буде збільшити.
GatotPujo

Дуже хороший момент. Моя точка зору трохи обмежена, здається. Дійсно, відповідь @HendrikJan дає дуже хороше пояснення.
didierc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.