Изменения

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

Персистентный массив

993 байта добавлено, 19:34, 4 сентября 2022
м
rollbackEdits.php mass rollback
==Интерфейс==
* ''' <tex> [ X ]''' </tex> статический конструктор, который принимает элемент <tex> X </tex> и возвращает массив, который содержит <tex> X </tex> в качестве его единственного элемента.* ''' <tex> LENGTH''' [A] </tex> возвращает длину массива <tex> A </tex>.* ε <tex> \varepsilon </tex> является пустым массивом, иногда также обозначается <tex> []</tex> * ''' <tex> A''' [i] </tex> принимает массив <tex> A = [''a''<sub>0</sub>a_0, ..., ana_{n-1} ] </tex> и индекс '' <tex> i'' = 0..''n''-1</tex> , затем возвращает ''a'' <subtex>i a_i </subtex>.* ''' <tex> CONCATENATE'''(A,B) </tex> конкатентирует два массива: if '' если <tex> A'' = [''a''<sub>0</sub>a_0,...,''a''<sub>a_{n-1} ] </subtex> и <tex>] and '' B'' = [''b''<sub>0</sub>b_0,...,''b''<sub>b_{m-1</sub>} ], ''; n'',''m'' ≥ \geq 0</tex> , результат будет [''a'' <sub>0</subtex> [a_0 ,...,''a''<sub>a_{n−1</sub>},"b"<sub>0</sub>b_0,...,''b''<sub>b_{m-1}] </subtex>]. Часто записывается как '' <tex> A'' · ''B'' </tex> вместо ''' <tex> CONCATENATE'''(''A'',''B'')</tex> .* ''' <tex> HEAD'''(A,''i'') </tex> принимает на вход массив '' <tex> A'' = [''a''<sub>0</sub>a_0,...,''a''a_{n−1}] </tex> и производный '' <tex> int''</tex> , возвращает массив <tex> [''a''0a_0,...,''amina_{min(i−1,n−1)'' } ]</tex> . Если '' <tex> i'' < 0 </tex> результатом будет <tex> [ ]</tex> .* ''' <tex> TAIL'''(''A'',''i'') </tex> принимает на вход массив <tex> ''A'' = ["a"<sub>0</sub>a_0,...,an−1a_n−1] </tex> и производный <tex> int</tex> , возвращает массив <tex> [''amaxa_{max(''i'',0)'' } ,...,''a''a_{n−1}]</tex> . Если '' <tex> i'' ≥ ''\geq n''</tex> , результатом будет <tex> [ ]</tex> .* ''' Если <tex> B''' </tex> - структура, то '' <tex> seq (''B'')'' </tex> обозначает строку, которая представлена '' <tex> B''</tex> .
Основываясь на вышеприведенных операциях, ADT может быть расширен следующими операциями:
* ''' <tex> [''x''0x0,..., ''x''x_{n−1}]''' </tex> является сокращением для ''' <tex> CONCATENATE'''([x0x_0],'''CONCATENATE'''([x1x_1],'''CONCATENATE'''(...,'''CONCATENATE'''([''x''x_{n−2}],[''x''x_{n−1}])))) </tex> . Обратите внимание, что в программе оценка этого выражения всегда включает '' <tex> n-2'' </tex> конкатенации.* ''' <tex> REVERSE'''[''A''] </tex> принимает на вход массив <tex> A = [''a''0a_0,...,''a''<sub>a_{n-1}] </subtex>] и возвращает [''a'' <subtex> [a_{n-1</sub>},...,a0a_0]</tex> . * ''' <tex> REPLACE'''[A,i, x] </tex> принимает на вход массив <tex> A = [''a''0a_0,...,''a''<sub>a_{n-1}]</subtex>] , индекс '' <tex> i'' = 0..''n'' − - 1</tex> , и новый элемент '' <tex> x''</tex> , выводит [''a'' <sub>0</subtex>[a_0,...,''a''<sub>a_{i-1</sub>}, ''x'',''a''<sub>a_{i+1</sub>},...,''a''<sub>a_{n-1}]</subtex>]. * ''''' <tex> A''[i] ← ''\leftarrow x '''''</tex> является сокращенным обозначением <tex> A \leftarrow REPLACE(A,''i'', ''x'')</tex> . * ''' <tex> INSERT'''[A,i, x] </tex> получает массив <tex> A = [''a''0a_0,...,''a''<sub>a_{n-1}]</subtex>] , индекс '' <tex> i'' = 0..n−1n - 1 </tex> , и новый элемент <tex> x </tex> и возвращает массив <tex> [''a''0a_0,...,''a''<sub>a_{i-1</sub>}, x,''a''i a_i ,...,''a''a_{n−1}] = '''HEAD'''(A,''i'') · [''x''] · '''TAIL'''(A,''i)''</tex> , длина которого '' <tex> n''-1</tex> .* ''' <tex> LEFTPART'''(A): </tex> возвращает (non-deterministically) массив, представляющий последовательность префикса <tex> A</tex> .* ''' <tex> RIGHTPART'''(A): </tex> возвращает (non-deterministically) массив, представляющий последовательность суффикса <tex> A</tex> .
==Реализация персистентных массивом массивов в виде сбалансированных деревьев==
Будем использовать сбалансированные деревья в качестве нашей стандартной реализации постоянных массивов. (Реализации сбалансированных деревьев, таких как AVL-деревья и B-деревья, можно найти в соответствующих разделах сайта)
Решающим моментом является то, что мы допускаем множественные ссылки на одно и то же поддерево: хотя концептуальное представление постоянных массивов - ориентированные деревья, их представление в памяти различно. Мы допускаем, что узел может быть преемником многих разных узлов.
{{Определение
|definition= Пусть <tex> X </tex> - некоторое множество. Бинарное дерево с несколькими ссылками на <tex> X </tex> является кортежем <tex> B = (N, L, R) с L∩R L \cap R = 0 /, L, R \subseteq N × N</tex> , таким, что* <tex> (N, L∪RL \cup R) </tex> является '''корневым ациклическим ориентированным графом ''' с узлами <tex> N</tex> , ребрами L∪R <tex> L \cup R</tex> . * В каждом из двух подграфов <tex> (N, L) и (N, R) </tex> каждый узел имеет '''не более одного прямого преемника '''. *Узлы без каких-либо преемников (листья B) должны быть все элементами <tex> X</tex> .
}}
Дано двоичное дерево с несколькими ссылками <tex> B = (N,L,R) </tex> и узел '' <tex> p'' ∈ \in N</tex> . Пишут <tex> LEFT(''p'') = ''q''</tex> , если '' <tex> q'' </tex> является единственным приемником <tex> ''p'' в(N,L) </tex> и, если такого '' <tex> q'' </tex> не существует, пишем <tex> LEFT(''p'')= \perp</tex> , предполагая, что <tex> \perp </tex> не содержит <tex> N</tex> . Аналогично, пишут <tex> RIGHT(p) = ''q''</tex> , если <tex> q </tex> является единственным приемником <tex> p в(N,R) </tex> и, если такого <tex> q </tex> не существует, пишем <tex> RIGHT(''p'')= \perp</tex> . Мы будем называть <tex> LEFT (''p'') </tex> левым дочерним элементом <tex> p </tex> и <tex> RIGHT (''p'') </tex> правым дочерним элементом.В <tex> B = (N, L∪RL \cup R) </tex> узел '' <tex> p'' ∈ \in N </tex> может иметь много прямых предшественников '' <tex> q''</tex> . Тогда ребра <tex> (''q'', ''p'') \in E </tex> называют ссылками от <tex> q </tex> до <tex> p</tex> .
С каждым узлом '' <tex> p'' ∈ \in N </tex> мы можем идентифицировать строку <tex> seq (''p'') \in X *</tex> : Если ''p'' - лист, то согласно определению выше, ''<tex> p'' ∈ \in X</tex> . Мы можем установить <tex> seq (p) = x </tex> (строка, содержащая только'' x''). Поскольку <tex> (N, L∪R L \cup R ) </tex> ациклично, для всех внутренних узлов мы можем рекурсивно определить <tex> p \in N seq (''p'') = seq (LEFT (''p'')) seq (RIGHT (''p''))</tex> , задав <tex> seq (\perp) = ε<tex> . Наконец, пусть r - корень B. Тогда определим''seq ''определимseq (B): = ''seq ''(''r''). В качестве примера, см. рисунок 1.2.В нашей реализации мы поддерживаем с каждым узлом <tex> p \in N </tex> длину <tex> seq (LEFT (''p''))</tex> . Это позволяет получить '' <tex> i''</tex> символ строки <tex> seq (B)</tex> , пройдя путь от корня до соответствующего листа. Мы также поддерживаем значение HEIGHT (''p'') для каждого <tex> p \in N</tex> , которое определяется как максимальнаядлина пути от p до листа в '' <tex> q'' ∈ \in N</tex> . Согласно этому определению все листья имеют высоту <tex> 0 </tex> и если мы устанавливаем <tex> HEIGHT (\perp) = -1</tex> , то <tex> HEIGHT(''p'') = max(HEIGHT(LEFT(''p'')), HEIGHT(RIGHT(''p'')))+1 </tex> . для всех '' <tex> .p'' ∈ \in N</tex> ..
Чтобы сбалансировать структуру, мы используем AVL-условие для двоичных деревьев.
Def3 Бинарное дерево <tex> B = (N, L, R) </tex> является AVL-деревом, если оно удовлетворяет условию AVL, то есть для каждого <tex> p \in N |HEIGHT(LEFT(''p''))− HEIGHT(RIGHT(''p''))| \le 1</tex> .
1.2 конкатенация постоянных массивов, представленных в виде двоичных деревьев
Для полноты мы покажем операции для конкатенации · и расщепления <tex> (HEAD и TAIL)</tex> , которые особенно просты в реализации, запускаются во времени <tex> O (HEIGHT (''r'')) </tex> и позволяют нам реализовать полный интерфейс персистентного массива ADT. Для конкатенации см. Алгоритм 1.2. <tex> NODE (''l'', ''r'') </tex> является конструктором, который выдает созданный узел '' <tex> p'' с LEFT (''p'') = l и RIGHT (''p'') = ''r''</tex> . Конструктор также определяет правильные значения <tex> p </tex> для <tex> HEIGHT (''p'') и LENGTH (''p'')</tex> .Обратите внимание, что время его работы равно <tex> O (| HEIGHT (''r'') -HEIGHT (''l'') |)</tex> . Далее мы покажем алгоритм <tex> HEAD</tex> , алгоритм для <tex> TAIL </tex> является симметричным.
1.3 Разделение персистентного массива, представленного как двоичное дерево.
Учитывая корневой узел r высоты ''h'' и целое число ''i'', алгоритм 1.3 свяжет не более чем '' <tex> h + 1'' </tex> двоичных дерева. Стоимость одной конкатенации пропорциональна разнице высот.  
При использовании RAW с ограниченным размером арифметических операций, ADT для персистентных массивов могут быть реализованы таким образом, чтобы каждая из его операций выполнялась во времени O (logn).Если длины массивов представляются внутри границ слова. В противном случае временная граница O (min ((log n)2, k2)). Здесь n - максимальная длина задействованных массивов, а k – число, которые были использованы для создания массивов операндов.
1632
правки

Навигация