Структура данных и алгоритм 06 2-3-4 дерево. 2-3-4 введение дерева
Структура данных и алгоритм 06 2-3-4 дерево. 2-3-4 введение дерева
Каждый узел дерева 2-3-4 имеет до четырех байтовых точек и трех элементов данных.Цифра 2, 3, 4 в имени указывает количество дочерних узлов, которые может содержать узел. Есть три возможных сценария для нелистовых узлов:
① Узел с одним элементом данных всегда имеет два дочерних узла;
② Узел с двумя элементами данных всегда имеет три дочерних узла;
③ Узел с тремя элементами данных всегда имеет четыре дочерних узла;
Короче говоря, количество дочерних узлов нелистового узла всегда на один элемент данных больше, чем он содержит. Если количество дочерних узлов равно L, а количество элементов данных равно D, то: L = D + 1
Листовой узел (нижняя строка на рисунке выше) не имеет дочерних узлов, но может содержать один, два или три элемента данных. Пустых узлов не будет.
Очень важным моментом в древовидной структуре является взаимосвязь между ключевыми значениями между узлами. В двоичном дереве все узлы со значением ключа меньше определенного значения узла находятся в поддереве с корнем в левом дочернем узле этого узла; все узлы со значением ключа больше определенного значения узла находятся в правом дочернем узле этого узла Корень поддерева. Правило 2-3-4 дерева остается прежним, но добавляются следующие пункты:
Для удобства описания используйте числа от 0 до 2 для нумерации элементов данных и числа от 0 до 3 для нумерации подузлов, как показано на следующем рисунке:
①, значение ключа всех дочерних узлов поддерева, корнем которого является child0, меньше, чем key0;
②, значение ключа всех дочерних узлов поддерева, корнем которого является child1, больше, чем key0, и меньше, чем key1;
③, значение ключа всех дочерних узлов поддерева, корнем которого является child2, больше, чем key1, и меньше, чем key2;
④, значение ключа всех дочерних узлов поддерева, корнем которого является child3, больше, чем key2.
Упрощенная взаимосвязь показана на рисунке ниже.Поскольку повторяющееся значение ключа обычно не допускается в дереве 2-3-4, нет необходимости рассматривать случай сравнения одного и того же значения ключа.
Бинарный код дерева. Создание дерева, вставка
Рассмотрим существующее двоичное дерево. Корень содержит число 3, все узлы в левом поддереве меньше текущего, в правом — больше. Такие же правила действуют для любого рассматриваемого узла и его поддеревьев.
Попробуем вставить в это дерево элемент -1.
Из корня идем в левое поддерево, так как -1 меньше 3. Из узла со значением 1 также идём в левое поддерево. Но в этом узле левое поддерево отсутствует, вставляем в эту позицию элемент, создавая новый узел дерева.
Вставим в получившееся дерево элемент 3.5.
Проходим по дереву, сравнивая на каждом из этапов вставляемое значение с элементом в узле, пока не дойдем до узла, в котором следующий узел для сравнения отсутствует, в эту позицию и вставляем новый узел.
Если дерево не существует, то есть root равен null, то элемент вставляется в корень, после этого проводится вставка по описанному выше алгоритму.
2-3 дерево.
2-3 дерево — структура данных , являющаяся B-деревом , каждый узел (страница) которого имеет либо два потомка и одно поле, либо три потомка и два поля. Листовые вершины являются исключением — у них нет детей, но есть одно или два поля. 2-3 деревья сбалансированы, то есть все листовые вершины находятся на одной высоте от корня дерева.
2-вершина
3-вершина
- и , и
Нелистовые вершины содержат одно или два поля, указывающие на диапазон значений в их поддеревьях. Значение первого поля строго больше наибольшего значения в левом поддереве и меньше или равно наименьшему значению в правом поддереве (или в центральном поддереве, если это 3-вершина); аналогично, значение второго поля (если оно есть) строго больше наибольшего значения в центральном поддереве и меньше или равно, чем наименьшее значение в правом поддереве. Эти нелистовые вершины используются для направления функции поиска к нужному поддереву и, в конечном итоге, к нужному листу.
Бинарное дерево. Двоичное дерево
Двои́чное де́рево — иерархическая структура данных , в которой каждый узел имеет не более двух потомков (детей). Как правило, первый называется родительским узлом, а дети называются левым и правым наследниками. Двоичное дерево является упорядоченным ориентированным деревом .
Для практических целей обычно используют два подвида двоичных деревьев — двоичное дерево поиска и двоичная куча .
Существует следующее рекурсивное определение двоичного дерева (см. БНФ ):
::= ( ) | null .
То есть двоичное дерево либо является пустым, либо состоит из данных и двух поддеревьев (каждое из которых может быть пустым). Очевидным, но важным для понимания фактом является то, что каждое поддерево в свою очередь тоже является деревом. Если у некоторого узла оба поддерева пустые, то он называется листовым узлом (листовой вершиной) или конечным (терминальным) узлом.
Например, показанное справа на рис. 1 дерево согласно этой грамматике можно было бы записать так:
(m (e (c (a null null) null ) (g null (k null null) ) ) (s (p (o null null) (s null null) ) (y null null) ) ) |
Структуры данных. 10 типов структур данных, которые нужно знать
«Плохие программисты думают о коде. Хорошие программисты думают о структурах данных и их взаимосвязях», — Линус Торвальдс, создатель Linux.
Структуры данных играют важную роль в процессе разработки ПО, а еще по ним часто задают вопросы на собеседованиях для разработчиков. Хорошая новость в том, что по сути они представляют собой всего лишь специальные форматы для организации и хранения данных.
Программа обучения: « Big Data: основы работы с большими массивами данных »
В этой статье я покажу вам 10 самых распространенных структур данных. Для каждой из них приведены видео и примеры их реализации на JavaScript. Чтобы вы смогли попрактиковаться, я также добавил несколько упражнений из бета-версии новой учебной программы freeCodeCamp.
Обратите внимание, что некоторые структуры данных включают временную сложность в нотации «большого О». Это относится не ко всем из них, так как иногда временная сложность зависит от реализации. Если вы хотите узнать больше о нотации «большого О», посмотрите это видео от Briana Marie .
Офлайн-курс: « Data Scientist »
В статье я привожу примеры реализации этих структур данных на JavaScript: они также пригодятся, если вы используете низкоуровневый язык вроде С. В многие высокоуровневые языки, включая JavaScript, уже встроены реализации большинства структур данных, о которых пойдет речь. Тем не менее, такие знания станут серьезным преимуществом при поиске работы и пригодятся при написании высокопроизводительного кода.
Связные списки
Связный список — одна из базовых структур данных. Ее часто сравнивают с массивом, так как многие другие структуры можно реализовать с помощью либо массива, либо связного списка. У этих двух типов есть преимущества и недостатки.
Так устроен связный список
Связный список состоит из группы узлов, которые вместе образуют последовательность. Каждый узел содержит две вещи: фактические данные, которые в нем хранятся (это могут быть данные любого типа) и указатель (или ссылку) на следующий узел в последовательности. Также существуют двусвязные списки: в них у каждого узла есть указатель и на следующий, и на предыдущий элемент в списке.
Основные операции в связном списке включают добавление, удаление и поиск элемента в списке.
Пример реализации на JavaScript
Временная сложность связного списка
Упражнения от freeCodeCamp
- Work with Nodes in a Linked List
- Create a Linked List Class
- Remove Elements from a Linked List
- Search within a Linked List
- Add Elements at a Specific Index in a Linked List
- Create a Doubly Linked List
- Reverse a Doubly Linked List
Стеки
Стек — это базовая структура данных, которая позволяет добавлять или удалять элементы только в её начале. Она похожа на стопку книг: если вы хотите взглянуть на книгу в середине стека, сперва придется убрать лежащие сверху.
Стек организован по принципу LIFO (Last In First Out, «последним пришёл — первым вышел») . Это значит, что последний элемент, который вы добавили в стек, первым выйдет из него.
Так устроен стек
В стеках можно выполнять три операции: добавление элемента (push), удаление элемента (pop) и отображение содержимого стека (pip).
Пример реализации на JavaScript
Временная сложность стека
Упражнения от freeCodeCamp
- Learn how a Stack Works
- Create a Stack Class
Очереди
Эту структуру можно представить как очередь в продуктовом магазине. Первым обслуживают того, кто пришёл в самом начале — всё как в жизни.
Так устроена очередь
Очередь устроена по принципу FIFO (First In First Out, «первый пришёл — первый вышел»). Это значит, что удалить элемент можно только после того, как были убраны все ранее добавленные элементы.
Очередь позволяет выполнять две основных операции: добавлять элементы в конец очереди (enqueue) и удалять первый элемент (dequeue).
Красно-чёрное дерево. Algorithm
A nonempty tree where the root color has been changed from black to red and the new tree has the original black height.
A nonempty tree where the root color has not been changed and the new tree has the original black height.
Insertion into a red rooted tree ends witha x b y c
wherea
,b
andc
are black rooted valid red black trees where the insertion has been successul in one of them andx
andy
are two info elements separating them. The black height ofa
,b
andc
is the black height of the original tree. Therefore we cannot form a valid red black tree of the original height without creating a red violation. The parent is black.
Note that all subtrees must be valid red black trees.
We have to prove that we can maintain the insertion invariant.
Initially we are in state 1. We insert the new element into an empty tree by creating a singleton red tree. Because the empty tree is considered black rooted, the root color has been changed from black to red. The new tree has the same black height as the initial tree (namely zero) and the new tree is a valid red black tree.
Now we have to consider inserting into a treeNode(color, left, info, right)
. We only analyze the situation of inserting into the left child. Inserting into the right child is symmetrical. We assume that insertion into the left subtree ended in state 1, 2 or 3. We have to prove that insertion at the current level ends either in state 1, 2 or 3 as well.
Insertion intoleft
created a new treeNode(Red, a, x, b)
anda
andb
have the black height of the original treeleft
.
color = Black: We createNode(Black, Node(Red,a,x,b), info, right)
and end in state 2.
color = Red: We cannot create a new valid red black tree. Therefore we end in state 3 witha x b info right
. The next parent must be black, because the current node is red.
Insertion intoleft
created a new tree Node(color, leftNew, info, right)
Insertion intoleft
ended up witha x b y c
. The black height ofa
,b
andc
is the same as the black height ofleft
. Because we are in state 3, the color of the current node must be black. We end in state 1 and returnNode (Red, Node (Black, a, x, b), y, Node (Black, c, info, right))
.
During insertion we have the following state diagramm.
++++++
| |
v |
1 -------> 2 ++++
^ \
| \
| -----> 3
| |
\--------------/
If the insertion ends in state 1 or 2 at the root, then there is nothing to do. State 1 and 2 represent valid red black trees.
Ending in state 3 witha x b y c
at the root we are allowed to introduce a new black level and generate eitherNode (Black, a, x, Node (Red, b, y, c))
orNode (Black, Node (Red, a, x, b), y, c)
.