Зачем использовать плоский список в heapsort? - PullRequest
0 голосов
/ 30 марта 2012

В heapsort данные хранятся в так называемом « heap ». Почти все реализации, которые я видел, используют плоский список для структуры данных.

Может кто-нибудь объяснить мне, почему это так?

Почему бы не использовать вложенных массивов или экземпляра двоичного дерева ? Разве явное не лучше неявного?

Это из-за трудностей реализации, таких как обход структуры или что-то еще?

Ответы [ 2 ]

3 голосов
/ 30 марта 2012

Если вы хотите увидеть, как heapsort может быть реализован в Python, посмотрите не дальше, чем стандартный библиотечный модуль heapq.В Python есть реализации heapsort как на C, так и на Python, а модуль heapq определяет Python, а затем перезаписывает их (если они есть) на C.Это означает, что вы можете прочитать и понять реализацию Python, но получите преимущество версии C, если вы действительно ее используете.

В конце приведен краткий пример использования модуля:

heap = []
data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
for item in data:
    heappush(heap, item)
sort = []
while heap:
    sort.append(heappop(heap))
print sort

Куча представлена ​​частично отсортированным списком, который имеет ограничение, которое для каждого элемента с индексом n в списке имеет отношение heap[n] <= heap[n*2+1] and heap[n] <= heap[n*2+2] (игнорируя элементы, которые не существуют).Это простой способ свернуть двоичное дерево в простой список для удобства хранения.

heappush() помещает новый элемент в список, сохраняя этот инвариант, heappop() удаляет наименьший элемент.heapify(somelist) переупорядочивает список на месте для удовлетворения инварианта.

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

Редактировать : Есть несколько причин, по которым список / массив более подходит для хранения кучи, чем явная древовидная структура.Наиболее очевидные из них - это то, что у явного дерева больше накладных расходов на память (либо с указателями внутри каждого объекта, либо с отдельным объектом, который должен быть выделен для каждого объекта в куче), но и оно медленнее, чем всякий раз, когда объект перемещается в вашей кучеобновить несколько указателей на детей и, возможно, родителей.

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

3 голосов
/ 30 марта 2012

Вы должны взглянуть на это, вы найдете много важных вещей об алгоритмах сортировки: сортировка

С другой стороны heap - это структура данных на основе дерева со специальными свойствами. В случае максимальной кучи наибольший элемент находится в корневом узле, а если B является дочерним узлом A, то ключ (A) ≥ ключ (B).
Кучи имеют решающее значение в нескольких эффективных графовых алгоритмах, таких как алгоритм Дейкстры и в алгоритме сортировки heapsort .
Вы также должны проверить это о сортировке кучи.
[РЕДАКТИРОВАТЬ] Реализованную для Python реализацию сортировки кучи можно найти здесь .

...