Изменения

Перейти к: навигация, поиск

Hashed Array Tree

374 байта добавлено, 19:05, 12 июня 2014
Нет описания правки
'''HAT(Hashed Array Tree)''' {{---}} структура данных, объединяющая в себе некоторые возможности массивов, хэш-таблиц и деревьев. Внешне структура похожа на хеш-таблицу с разрешением коллизий методом цепочек, используя расширение структуры, отсюда и название. В действительности HAT {{---}} это эффективный способ реализовать массивы переменной длины, так как он предлагает хорошую производительность порядка <mathtex>O(N)</mathtex>, чтобы добавить <mathtex>N</mathtex> элементов к пустому массиву, и требует всего лишь <mathtex>O(\sqrt{N})</mathtex> дополнительной памяти.
==Значимость==
<font color=green>// Вернуть элемент HAT. Нет проверки на выход за пределы массива.</font>
'''return''' top[topIndex(j)][leafIndex(j)]
*Формула для <tex>leafIndex</tex> справедлива, так как элементы, которые находятся в разных листьях и различаются на <tex>2^k</tex>, будут иметь одинаковую позицию в этих листах, а младшие <tex>k</tex> бит у них будут общими.
Рассмотрим как происходит вычисление адреса на примере. Пусть у нас есть HAT с размером листа равным <tex>4</tex>, тогда для нашего случая <tex>power = 2</tex>. Получим значения функций для элемент под номером <tex>5</tex>:
*<tex>topIndex(5)</tex> : в данном случае битовый сдвиг эквивалентен операции деления (взятию по модулю) <tex>j</tex> на <mathtex>2^{2}</mathtex>. То есть получим <tex>1</tex> {{---}} действительно элемент под номером <tex>5</tex> находится в первом листе (нумерация листов с <tex>0</tex>).
*<tex>leafIndex(5)</tex> : в данном случае битовый сдвиг эквивалентен умножению <tex>1</tex> на <tex>2^{2}</tex>. То есть после вычитания <tex>1</tex> получим число формата <tex>011..11</tex>, в нашем случае {{---}} <tex>011</tex>.
*<tex>5_{10} = 101_2 - </tex> , следовательно <tex>101</tex> <tex>\&</tex> <tex>011 = 001</tex>, то есть индекс в листе равен <tex>1</tex> (в листах нумерация тоже с <tex>0</tex>).
[[Файл:fullHAT.png|200px]]
===Добавление элементов===
*Чаще всего при добавлении элемента в одном из листьев (последнем незаполненном на данный момент) найдется свободное место, что позволит осуществить быструю вставку {{---}} <mathtex>O(1)</mathtex>. *Реже мы столкнемся со случаем, когда необходимо создать новый лист. Достаточно всего лишь добавить указатель в свободную ячейку главного массива, что также позволит произвести вставку элемента за <mathtex>O(1)</mathtex>.*Самый интересный случай {{---}} когда главный массив и все листья заполнены. Cначала вычислим нужный размер (массивы <tex>top</tex> и <tex>leaf</tex> увеличиваются в <tex>2</tex> раза, то есть <mathtex>power = power \cdot 2 </mathtex>), затем скопируем элементы в новую структуру HAT, освобождая старые листья и распределяя новые листья(размер листа изменился, а значит количество элементов в листе и количество используемых листьев так же изменится).*Такой подход к расширению помогает избежать избыточного перекопирования, используемого во многих реализациях массивов переменной длины, потому что увеличения размеров всех массивов происходит редко (как будет видно ниже). Копировать элементы мы будем только тогда, когда главный массив полон (достигли соответствующей степени двойки, то есть <tex> N = (2 \cdot 2)^k</tex>, где <tex>k</tex> {{---}} натуральное число), тогда общая сумма перекопирования будет равна <mathtex>1+4+16+64+256+...+N</mathtex>. Воспользуемся тождеством: <mathtex>(x^{n+1} -1)=(x-1)(1+x+x^2+x^3+... + x^k)</mathtex>, тогда для нашего случая: <mathtex>1 +4+4^2+4^3+...+4^k = (4^{k+1} -1)/(4-1) = (4N-1)/3</mathtex>, или около <mathtex>4N/3</mathtex>. Это означает, что среднее число дополнительных операций копирования {{---}} <mathtex>O(N)</mathtex> для последовательного добавления N элементов, а не <mathtex>O(N^2)</mathtex>. Мы получили <mathtex>4N/3</mathtex> против <mathtex>2N</mathtex> в обычном динамическом массиве, то есть константа уменьшилась.
[[Файл:AlgoF2.gif|400px]]
===Расход памяти===
HAT использует меньше дополнительной памяти, чем в стандартных подходах к расширению массивов, то есть полном перекопировании и перераспределении всего массива.
Затраты дополнительной памяти (уже выделенной, но еще не используемой) в самом плохом случае {{---}} <mathtex>(top+leaf-1) ~= 2\sqrt{N} = O(\sqrt{N})</mathtex> (этот случай при пустой HAT {{---}} в <tex>top</tex> один указатель на единственный пустой лист). Если в листе будет <tex>power/2</tex> элементов, то ожидаемая трата дополнительной памяти уменьшается до <mathtex>(top + leaf/2) \approx 1.5\sqrt{N}</mathtex>. Таким образом HAT использует <tex>\Theta(\sqrt{N})</tex> дополнительной памяти. Это лучше [[wikipedia:ru:Динамический массив |динамического массива]], который использует <tex>O(N)</tex> дополнительной памяти сразу после перекопирования элементов, и лучше [[wikipedia:ru:Список (информатика) |списка]].
==Эффективность==
90
правок

Навигация