Двоичная куча — различия между версиями
(→Восстановление свойств кучи) |
(→Восстановление свойств кучи) |
||
Строка 24: | Строка 24: | ||
===Восстановление свойств кучи=== | ===Восстановление свойств кучи=== | ||
− | Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служат процедуры '''sift_down''' (просеивание вниз) и '''sift_up''' (просеивание вверх). Если значение измененного элемента увеличивается, то свойства кучи восстанавливаются функцией ''sift_down(i)'''. | + | Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служат процедуры '''sift_down''' (просеивание вниз) |
+ | и '''sift_up''' (просеивание вверх). | ||
+ | Если значение измененного элемента увеличивается, то свойства кучи восстанавливаются функцией ''sift_down(i)'''. | ||
Работа процедуры: если <tex>i</tex>-й элемент меньше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами <tex>i</tex>-й элемент с наименьшим из его сыновей, после чего выполняем '''sift_down()''' для этого сына. | Работа процедуры: если <tex>i</tex>-й элемент меньше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами <tex>i</tex>-й элемент с наименьшим из его сыновей, после чего выполняем '''sift_down()''' для этого сына. | ||
Процедура выполняется за время <tex>O(\log{N})</tex>. | Процедура выполняется за время <tex>O(\log{N})</tex>. | ||
Строка 47: | Строка 49: | ||
Если значение измененного элемента уменьшается, то свойства кучи восстанавливаются функцией '''sift_up(i)'''. | Если значение измененного элемента уменьшается, то свойства кучи восстанавливаются функцией '''sift_up(i)'''. | ||
− | Работа процедуры: если элемент больше своего отца, условие 1 соблюдено для всего дерева, и больше ничего делать не нужно. Иначе, мы меняем местами его с отцом. После чего выполняем '''sift_up''' для этого отца. Иными словами, слишком большой элемент всплывает наверх. | + | Работа процедуры: если элемент больше своего отца, условие 1 соблюдено для всего дерева, и больше ничего делать не нужно. Иначе, мы меняем местами его с отцом. После чего выполняем '''sift_up''' |
+ | для этого отца. Иными словами, слишком большой элемент всплывает наверх. | ||
Процедура выполняется за время <tex>O(\log{N})</tex>. | Процедура выполняется за время <tex>O(\log{N})</tex>. | ||
Версия 22:27, 18 марта 2012
Содержание
Определение
Определение: |
Двоичная куча или пирамида — такое двоичное дерево, для которого выполнены три условия:
|
Удобная структура данных для сортирующего дерева — массив
, у которого первый элемент, — элемент в корне, а потомками элемента являются и . Высота кучи определяется как высота двоичного дерева. То есть она равна количеству рёбер в самом длинном простом пути, соединяющем корень кучи с одним из её листьев. Высота кучи есть , где — количество узлов дерева.Чаще всего используют кучи для минимума (когда предок не больше детей) и для максимума (когда предок не меньше детей).
Двоичные кучи используют, например, для того, чтобы извлекать минимум из набора чисел за
. Двоичные кучи — частный случай приоритетных очередей.Базовые процедуры
Восстановление свойств кучи
Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служат процедуры sift_down (просеивание вниз) и sift_up (просеивание вверх). Если значение измененного элемента увеличивается, то свойства кучи восстанавливаются функцией sift_down(i)'. Работа процедуры: если
-й элемент меньше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами -й элемент с наименьшим из его сыновей, после чего выполняем sift_down() для этого сына. Процедура выполняется за время .
sift_down(i) left = 2 * i // левый сын right = 2 * i + 1 // правый сын // heap_size - количество элементов в куче If (left <= A.heap_size) and (A[left] < A[i]) min = left else min = i If (right <= A.heap_size) and (A[right] < A[i]) min = right else min = i If (min <> i) Поменять A[i] и A[minimum] sift_down(min)
Если значение измененного элемента уменьшается, то свойства кучи восстанавливаются функцией sift_up(i).
Работа процедуры: если элемент больше своего отца, условие 1 соблюдено для всего дерева, и больше ничего делать не нужно. Иначе, мы меняем местами его с отцом. После чего выполняем sift_up
для этого отца. Иными словами, слишком большой элемент всплывает наверх.
Процедура выполняется за время
.
sift_up(i) If (A[i] < A[i / 2]) Поменять A[i] и A[i / 2] sift_up(i / 2)
Извлечение минимального элемента
Выполняет извлечение минимального элемента из кучи за время
. Извлечение выполняется в четыре этапа:- Значение корневого элемента (он и является минимальным) сохраняется для последующего возврата.
- Последний элемент копируется в корень, после чего удаляется из кучи.
- Вызывается Sift_Down(i) для корня.
- Сохранённый элемент возвращается.
extract_min() min = A[1] A[1] = A[A.heap_size] A.heap_size = A.heap_size - 1 Sift_Down(1) return min
Добавление нового элемента
Выполняет добавление элемента в кучу за время
. Добавление произвольного элемента в конец кучи, и восстановление свойства упорядоченности с помощью
insert(key) A.heap_size = A.heap_size + 1 A[A.heap_size] = key Sift_Up(A.heap_size)