<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Flanir1</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Flanir1"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/Flanir1"/>
		<updated>2026-05-19T14:02:26Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46380</id>
		<title>Файл:23treeinsert.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46380"/>
				<updated>2015-05-11T21:26:43Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treeinsert.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46379</id>
		<title>Файл:23treeinsert.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46379"/>
				<updated>2015-05-11T21:26:22Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treeinsert.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46378</id>
		<title>Файл:23treeinsert.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46378"/>
				<updated>2015-05-11T21:26:00Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treeinsert.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46377</id>
		<title>Файл:23treeinsert.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46377"/>
				<updated>2015-05-11T21:23:32Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treeinsert.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46376</id>
		<title>Файл:23treeinsert.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46376"/>
				<updated>2015-05-11T21:23:10Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treeinsert.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46374</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46374"/>
				<updated>2015-05-11T21:02:33Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел,&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{searchNode(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; существует, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, рассмотрим возможные случаи (сперва везде удаляем &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, следовательно, другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Так как у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} родителя &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, оказалось тоже два сына,повторяем для &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; такие же рассуждения,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Просто заберем ближайшего к нам сына у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и прицепим его к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Восстановим порядок в сыновьях &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось снова два сына и все узлы 2-3 дерева корректны,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына:&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x):&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      '''if''' (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0]&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508-509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46373</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46373"/>
				<updated>2015-05-11T21:01:46Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел,&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{searchNode(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; существует, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, рассмотрим возможные случаи (сперва везде удаляем &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, следовательно, другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Так как у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} родителя &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, оказалось тоже два сына,повторяем для &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Просто заберем ближайшего к нам сына у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и прицепим его к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Восстановим порядок в сыновьях &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось снова два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына:&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x):&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      '''if''' (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0]&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508-509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46372</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46372"/>
				<updated>2015-05-11T20:59:59Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел,&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{searchNode(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; существует, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, рассмотрим возможные случаи (сперва везде удаляем &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, следовательно, другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Так как у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} родителя &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, оказалось тоже два сына,повторяем для &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Просто заберем ближайшего к нам сына у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и прицепим его к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Восстановим порядок в сыновьях &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось снова два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына:&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x):&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      '''if''' (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0]&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508-509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46368</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46368"/>
				<updated>2015-05-11T20:56:22Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел,&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{searchNode(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; существует, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, рассмотрим возможные случаи (сперва везде удаляем &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, следовательно, другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Так как у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} родителя &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, оказалось тоже два сына,повторяем для &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось снова два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына:&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      '''if''' (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46367</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46367"/>
				<updated>2015-05-11T20:55:04Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел,&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{searchNode(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; существует, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, рассмотрим возможные случаи (сперва везде удаляем &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, следовательно, другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Так как у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} родителя &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, оказалось тоже два сына,повторяем для &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось снова два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына:&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      '''if''' (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46366</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46366"/>
				<updated>2015-05-11T20:52:19Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Следующий и предыдущий */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел,&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{searchNode(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, рассмотрим возможные случаи (сперва везде удаляем &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Так как у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} родителя &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, оказалось тоже два сына,повторяем для &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось снова два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына:&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      '''if''' (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46365</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46365"/>
				<updated>2015-05-11T20:51:52Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел,&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{searchNode(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, рассмотрим возможные случаи (сперва везде удаляем &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Так как у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} родителя &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, оказалось тоже два сына,повторяем для &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось снова два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына:&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46364</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46364"/>
				<updated>2015-05-11T20:49:34Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел,&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, рассмотрим возможные случаи (сперва везде удаляем &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Так как у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; {{---}} родителя &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у&amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось снова два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у &amp;lt;tex&amp;gt;gp&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына:&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46363</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46363"/>
				<updated>2015-05-11T20:38:10Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46362</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46362"/>
				<updated>2015-05-11T20:35:46Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, то найдем у любого соседнего листа его родителя, обозначим его за &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;.Рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46361</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46361"/>
				<updated>2015-05-11T20:34:34Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} соседний брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, то найдем у любого соседнего листа его родителя, обозначим его за &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;.Рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46360</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46360"/>
				<updated>2015-05-11T20:28:09Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} любой брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} отец &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; {{---}} любой брат &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; два сына, то найдем у любого соседнего листа его родителя, обозначим его за &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;.Рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;np&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(np)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46359</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46359"/>
				<updated>2015-05-11T20:17:02Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Следующий и предыдущий */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} любой брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то найдем у любого соседнего листа его родителя, обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Обозначим отца соседнего листа за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.Рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 3 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если p не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если p существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46358</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46358"/>
				<updated>2015-05-11T20:15:35Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} любой брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то найдем у любого соседнего листа его родителя, обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Обозначим отца соседнего листа за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.Рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 3 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если p не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если p существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != ''null'')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
        '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46357</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46357"/>
				<updated>2015-05-11T20:14:41Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Вставка элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' &lt;br /&gt;
         t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' &lt;br /&gt;
       t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = ''null''&lt;br /&gt;
    t.sons[3] = ''null''&lt;br /&gt;
    '''if''' (t.parent != ''null'')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != ''null'')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == ''null'') &lt;br /&gt;
    root = n&lt;br /&gt;
    '''return'''&lt;br /&gt;
   Node a = searchNode(x)     &lt;br /&gt;
   '''if''' (a.parent == ''null'') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} любой брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то найдем у любого соседнего листа его родителя, обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Обозначим отца соседнего листа за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.Рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 3 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если p не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если p существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != '''null''')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
        '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Timsort&amp;diff=46355</id>
		<title>Timsort</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Timsort&amp;diff=46355"/>
				<updated>2015-05-11T20:03:46Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Шаг 1. Вычисление minrun */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; &lt;br /&gt;
'''Timsort''' {{---}} гибридный алгоритм сортировки, сочетающий различные подходы.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм является относительно новым и был придуман Тимом Петерсом. На массивах данных, которые содержат упорядоченный подмасивы, алгоритм Тима Петерса показывает себя намного лучше других сортировок. В настоящее время '''Timsort''' является стандартной сортировкой в '''Python''' и '''GNU Octave''', реализован в '''OpenJDK 7''' и  '''Android JDK 1.5'''.&lt;br /&gt;
&lt;br /&gt;
== Основная идея алгоритма ==&lt;br /&gt;
Алгоритм '''Timsort''' состоит из нескольких частей:&lt;br /&gt;
* Начало.&lt;br /&gt;
* '''Шаг 1'''. Входной массив разделяется на подмассивы фиксированной длины, вычисляемой определённым образом.&lt;br /&gt;
* '''Шаг 2'''. Каждый подмассив сортируется [[Сортировка вставками | сортировкой вставками]], [[Сортировка пузырьком | сортировкой пузырьком]] или любой другой устойчивой сортировкой.&lt;br /&gt;
* '''Шаг 3'''. Отсортированные подмассивы объединяются в один массив с помощью модифицированной [[Сортировка слиянием | сортировки слиянием]].&lt;br /&gt;
* Конец.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим теперь каждый шаг в отдельности.&lt;br /&gt;
&lt;br /&gt;
== Алгоритм ==&lt;br /&gt;
&lt;br /&gt;
=== Обозначения ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} размер входного массива.&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathtt {run}&amp;lt;/tex&amp;gt; {{---}} подмассив во входном массиве, который обязан быть упорядоченным одним из двух способов:&lt;br /&gt;
** строго по убыванию &amp;lt;tex&amp;gt;\mathtt {a_{i} &amp;gt; a_{i + 1} &amp;gt; \dots}  &amp;lt;/tex&amp;gt;.   &lt;br /&gt;
** нестрого по возрастанию &amp;lt;tex&amp;gt;\mathtt {a_{i} \leqslant a_{i + 1} \leqslant \dots}  &amp;lt;/tex&amp;gt;.   &lt;br /&gt;
*  &amp;lt;tex&amp;gt;\mathtt {minrun} &amp;lt;/tex&amp;gt; {{---}} минимальный размер подмассива, описанного в предыдущем пункте.&lt;br /&gt;
&lt;br /&gt;
===Шаг 1. Вычисление minrun===&lt;br /&gt;
* Начало.&lt;br /&gt;
* '''Шаг 0'''. Число &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt; определяется на основе &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, исходя из следующих принципов:&lt;br /&gt;
** Не должно быть слишком большим, поскольку к подмассиву размера &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt; будет в дальнейшем применена сортировка вставками (эффективна только на небольших массивах).&lt;br /&gt;
**  Оно не должно быть слишком маленьким, так как чем меньше подмассив, тем больше итераций слияния подмассивов придётся выполнить на последнем шаге алгоритма. Оптимальная величина для &amp;lt;tex&amp;gt; \mathtt{\dfrac{n}{minrun}} &amp;lt;/tex&amp;gt; {{---}} ''степень двойки''. Это требование обусловлено тем, что алгоритм слияния подмассивов наиболее эффективно работает на подмассивах примерно равного размера.&lt;br /&gt;
** Автором алгоритма было выбрано оптимальное значение, которое принадлежит диапазону &amp;lt;tex&amp;gt; [32; 65) &amp;lt;/tex&amp;gt; (подробнее о том, почему так, будет сказано ниже). &lt;br /&gt;
** Исключение: если &amp;lt;tex&amp;gt; n &amp;lt; 64 &amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt; n = \mathtt{minrun} &amp;lt;/tex&amp;gt; и '''Timsort''' превращается в сортировку вставками.&lt;br /&gt;
* '''Шаг 1'''. Берем старшие 6 бит числа &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и добавляем единицу, если в оставшихся младших битах есть хотя бы один ненулевой. &lt;br /&gt;
&lt;br /&gt;
Нетрудно понять, что после таких вычислений, &amp;lt;tex&amp;gt;\mathtt{\dfrac{{n}}{minrun}} &amp;lt;/tex&amp;gt; будет степенью двойки.&lt;br /&gt;
* Конец. &lt;br /&gt;
  '''int''' minRunLength(n):&lt;br /&gt;
    flag = 0         &amp;lt;font color=green&amp;gt;// будет равно 1, если среди сдвинутых битов есть хотя бы один ненулевой&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''while''' (n &amp;lt;tex&amp;gt; \geqslant&amp;lt;/tex&amp;gt; 64)&lt;br /&gt;
      flag |= n &amp;amp; 1&lt;br /&gt;
      n &amp;gt;&amp;gt;= 1&lt;br /&gt;
    '''return''' n + flag&lt;br /&gt;
&lt;br /&gt;
===Шаг 2. Алгоритм разбиения на подмассивы и их сортировка===&lt;br /&gt;
На данном этапе у нас есть входной массив, его размер &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и вычисленное число &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt;. Обратим внимание, что если данные изначального массива достаточно близки к случайным, то размер упорядоченных подмассивов близок к &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt;,. Но если в изначальных данных были упорядоченные диапазоны, то упорядоченные подмассивы могут иметь размер, превышающий &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt;. [[Файл:MinrunExample.png‎ |400px|right]]&lt;br /&gt;
* Начало.&lt;br /&gt;
* '''Шаг 0'''. Указатель текущего элемента ставится в начало входного массива.&lt;br /&gt;
* '''Шаг 1'''. Начиная с текущего элемента, идет поиск во входном массиве упорядоченного подмассива &amp;lt;tex&amp;gt;\mathtt{run}&amp;lt;/tex&amp;gt;. По определению, в &amp;lt;tex&amp;gt;\mathtt{run}&amp;lt;/tex&amp;gt; однозначно войдет текущий элемент и следующий за ним. Если получившийся подмассив упорядочен по убыванию, то после вычисления &amp;lt;tex&amp;gt;\mathtt{run}&amp;lt;/tex&amp;gt; для текущего массива элементы переставляются так, чтобы они шли по возрастанию.&lt;br /&gt;
* '''Шаг 2'''. Если размер текущего &amp;lt;tex&amp;gt;\mathtt{run}&amp;lt;/tex&amp;gt; меньше &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt;, тогда выбираются следующие за найденным подмассивом &amp;lt;tex&amp;gt;\mathtt{run}&amp;lt;/tex&amp;gt; элементы в количестве &amp;lt;tex&amp;gt; \mathtt{minrun - size(run)} &amp;lt;/tex&amp;gt;. Таким образом, на выходе будет получен подмассив размером большим или равный &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt;, часть которого (в лучшем случае {{---}} он весь) упорядочена.&lt;br /&gt;
* '''Шаг 3'''. К данному подмассиву применяем сортировка вставками. Так как размер подмассива невелик и часть его уже упорядочена {{---}} сортировка работает эффективно. &lt;br /&gt;
* '''Шаг 4'''. Указатель текущего элемента ставится на следующий за подмассивом элемент. &lt;br /&gt;
* '''Шаг 5'''. Если конец входного массива не достигнут {{---}} переход к шагу 1.&lt;br /&gt;
* Конец.&lt;br /&gt;
&lt;br /&gt;
=== Шаг 3. Слияние ===&lt;br /&gt;
Нужно объединить полученные подмассивы для получения результирующего упорядоченного массива. Для достижения эффективности, нужно ''объединять подмассивы примерно равного размера'' и ''cохранять стабильность алгоритма''. &lt;br /&gt;
[[Файл:Merge2mas.png|400px|right]]&lt;br /&gt;
* Начало.&lt;br /&gt;
* '''Шаг 0'''. Создается пустой стек пар &amp;lt;tex&amp;gt; &amp;lt; &amp;lt;/tex&amp;gt; индекс начала подмассива, размер подмассива &amp;lt;tex&amp;gt; &amp;gt; &amp;lt;/tex&amp;gt;.&lt;br /&gt;
* '''Шаг 1'''. Берется первый упорядоченный подмассив.&lt;br /&gt;
* '''Шаг 2'''. Добавляется в стек пара данных &amp;lt;tex&amp;gt; &amp;lt; &amp;lt;/tex&amp;gt; индекс начала текущего подмассива, его размер &amp;lt;tex&amp;gt; &amp;gt; &amp;lt;/tex&amp;gt;.&lt;br /&gt;
* '''Шаг 3'''. Пусть &amp;lt;tex&amp;gt;X,Y,Z &amp;lt;/tex&amp;gt; {{---}} длины верхних трех интервалов, которые лежат в стеке. Причем &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; {{---}} это последний элемент стека. &lt;br /&gt;
* '''Шаг 4'''. Повторяем пока выражение (&amp;lt;tex&amp;gt;Z &amp;gt; X + Y \wedge Y &amp;gt; X&amp;lt;/tex&amp;gt;) не станет истинным &lt;br /&gt;
** Если размер стека не меньше &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;Z \leqslant X + Y&amp;lt;/tex&amp;gt; {{---}} сливаем &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt; c &amp;lt;tex&amp;gt;\min(X,Z)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
** Иначе Если &amp;lt;tex&amp;gt;Y \leqslant X &amp;lt;/tex&amp;gt; {{---}} сливаем &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; c &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. &lt;br /&gt;
* '''Шаг 5'''. Если всего осталось &amp;lt;tex&amp;gt; 3 &amp;lt;/tex&amp;gt; подмассива, которые сейчас в стеке, то сливаем их в правильном порядке, иначе же переходим к шагу 2.&lt;br /&gt;
* Конец&lt;br /&gt;
&lt;br /&gt;
Основная цель этой процедуры {{---}} сохранение баланса. Изменения будут выглядеть как на картинке, а значит и размеры подмассивов в стеке эффективны для дальнейшей сортировки слиянием.&lt;br /&gt;
&lt;br /&gt;
===Описание процедуры слияния===&lt;br /&gt;
* Начало.&lt;br /&gt;
&lt;br /&gt;
* '''Шаг 0'''. Создается временный массив в размере меньшего из сливаемых подмассивов.&lt;br /&gt;
&lt;br /&gt;
* '''Шаг 1'''. Меньший из подмассивов копируется во временный массив, но надо учесть, что если меньший подмассив {{---}} правый, то ответ (результат сливания) формируется справа налево. Дабы избежать данной путаницы, лучше копировать всегда левый подмассив во временный. На скорости это практически не отразится. &lt;br /&gt;
&lt;br /&gt;
* '''Шаг 2'''. Ставятся указатели текущей позиции на первые элементы большего и временного массива.&lt;br /&gt;
&lt;br /&gt;
* '''Шаг 3'''. На каждом шаге рассматривается значение текущих элементов в большем и временном массивах, берется меньший из них, копируется в новый отсортированный массив. Указатель текущего элемента перемещается в массиве, из которого был взят элемент.&lt;br /&gt;
&lt;br /&gt;
* '''Шаг 4'''. Предыдущий пункт повторяется, пока один из массивов не закончится.&lt;br /&gt;
&lt;br /&gt;
* '''Шаг 5'''.Все элементы оставшегося массива добавляются в конец нового массива.&lt;br /&gt;
&lt;br /&gt;
* Конец.&lt;br /&gt;
===Пример===&lt;br /&gt;
Возьмем &amp;lt;tex&amp;gt;n = 356&amp;lt;/tex&amp;gt;. При таком &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt; оказался равным &amp;lt;tex&amp;gt;45&amp;lt;/tex&amp;gt;. Ниже представлена работа алгоритма.&lt;br /&gt;
Числа с закрывающей скобкой показывают номера шагов, на которых произошло сливание нижестоящих подмассивов. &lt;br /&gt;
&lt;br /&gt;
[[Файл:Example.png|800px]]&lt;br /&gt;
&lt;br /&gt;
== Модификация процедуры слияния подмассивов (Galloping Mode) ==&lt;br /&gt;
Рассмотрим процедуру слияния двух массивов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;A = {1, 2, 3, \dots, 9999, 10000}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;B = {20000, 20001, 20002, \dots, 29999, 30000}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вышеуказанная процедура для них сработает, но каждый раз на её четвёртом пункте нужно будет выполнить одно сравнение и одно копирование. В итоге &amp;lt;tex&amp;gt;10000&amp;lt;/tex&amp;gt; сравнений и &amp;lt;tex&amp;gt;10000&amp;lt;/tex&amp;gt; копирований. '''Timsort''' предлагает в этом месте модификацию, которая получила называет '''галоп'''. Алгоритм следующий:&lt;br /&gt;
&lt;br /&gt;
* Начало.&lt;br /&gt;
* '''Шаг 0'''. Начинается процедура слияния.&lt;br /&gt;
* '''Шаг 1'''. На каждой операции копирования элемента из временного или большего подмассива в результирующий запоминается, из какого именно подмассива был элемент.&lt;br /&gt;
* '''Шаг 2'''. Если уже некоторое количество элементов (например, в '''JDK 7''' это число равно 7) было взято из одного и того же массива {{---}} предполагается, что и дальше придётся брать данные из него. Чтобы подтвердить эту идею, алгоритм переходит в режим '''галопа''', то есть перемещается по массиву-претенденту на поставку следующей большой порции данных бинарным поиском (массив упорядочен) текущего элемента из второго соединяемого массива.&lt;br /&gt;
* '''Шаг 3'''. В момент, когда данные из текущего массива-поставщика больше не подходят (или был достигнут конец массива), данные копируются целиком.&lt;br /&gt;
* Конец.&lt;br /&gt;
Для вышеописанных массивов &amp;lt;tex&amp;gt;\mathtt{A, B}&amp;lt;/tex&amp;gt; алгоритм выглядит следующим образом:&lt;br /&gt;
Первые &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; итераций сравниваются числа &amp;lt;tex&amp;gt;1, 2, 3, 4, 5, 6, 7&amp;lt;/tex&amp;gt; из массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; с числом &amp;lt;tex&amp;gt;20000&amp;lt;/tex&amp;gt;, так как &amp;lt;tex&amp;gt;20000&amp;lt;/tex&amp;gt; больше, то элементы массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; копируются в результирующий. Начиная со следующей итерации алгоритм переходит в режим '''галопа''': сравнивает с числом &amp;lt;tex&amp;gt;20000&amp;lt;/tex&amp;gt; последовательно элементы &amp;lt;tex&amp;gt;8, 10, 14, 22, 38, 7+2^{i - 1}, \dots, 10000 &amp;lt;/tex&amp;gt; массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;( \thicksim\log{n}&amp;lt;/tex&amp;gt; сравнений&amp;lt;tex&amp;gt;)&amp;lt;/tex&amp;gt;. После того как конец массива &amp;lt;tex&amp;gt;\mathtt{A}&amp;lt;/tex&amp;gt; достигнут и известно, что он весь меньше &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;, нужные данные из массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; копируются в результирующий.&lt;br /&gt;
&lt;br /&gt;
== Доказательство времени работы алгоритма ==&lt;br /&gt;
Не сложно заметить, что чем меньше массивов, тем меньше произойдёт операций слияния, но чем их длины больше, тем дольше эти слияния будут происходить. На малом количестве длинных массивов хорошо помогает вышеописанный метод '''Galloping Mode'''. Хоть он и не даёт асимптотического выигрыша, но уменьшает константу.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; {{---}} число кусков, на которые разбился наш исходный массив, очевидно &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; = &amp;lt;tex&amp;gt; \left\lceil \mathtt{\dfrac{n}{minrun}} \right\rceil &amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Главный факт, который нам понадобится для доказательства нужной оценки времени работы в &amp;lt;tex&amp;gt;O(n \log{n})&amp;lt;/tex&amp;gt; {{---}} это то, что сливаемые массивы '''всегда''' имеют примерно одинаковую длину. Можно сказать больше: пока &amp;lt;tex&amp;gt;k &amp;gt; 3&amp;lt;/tex&amp;gt; сливаемые подмассивы будут именно одинаковой длины (данный факт хорошо виден на примере). Безусловно, после разбиения массива на блоки длиной &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt; последний блок может быть отличен от данного значения, но число элементов в нём не превосходит константы &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы выяснили, что при слиянии, длинна образовавшегося слитого массива увеличивается в &amp;lt;tex&amp;gt;\approx 2&amp;lt;/tex&amp;gt; раза. Таким образом получаем, что каждый подмассив &amp;lt;tex&amp;gt;\mathtt{run_i}&amp;lt;/tex&amp;gt; может участвовать в не более &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt; операций слияния, а значит и каждый элемент будет задействован в сравниниях не более &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt; раз. Элементов &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, откуда получаем оценку в &amp;lt;tex&amp;gt;O(n\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Также нужно сказать про [[Сортировка вставками | сортировку вставками]], которая используется для сортировки подмассивов &amp;lt;tex&amp;gt;\mathrm{run_i}&amp;lt;/tex&amp;gt;: в нашем случае, алгоритм работает за &amp;lt;tex&amp;gt;O(\mathtt{minrun + inv})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\mathtt{inv}&amp;lt;/tex&amp;gt; {{---}} число обменов элементов входного массива, равное числу инверсий. C учетом значения &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; получим, что сортировка всех блоков может занять &amp;lt;tex&amp;gt;O(\mathtt{minrun + inv}) \cdot k = O(\mathtt{minrun + inv}) \cdot &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\left\lceil \mathtt{\dfrac{n}{minrun}} \right\rceil &amp;lt;/tex&amp;gt;. Что в худшем случае &amp;lt;tex dpi&amp;gt;(\mathtt{inv = \dfrac{minrun(minrun - 1)}{2}} )&amp;lt;/tex&amp;gt; может занимать &amp;lt;tex&amp;gt;O(\mathtt{n \cdot minrun}) &amp;lt;/tex&amp;gt; времени. Откуда видно, что константа &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt; играет немалое значение: при большом &amp;lt;tex&amp;gt;\mathtt{minrun}&amp;lt;/tex&amp;gt; слияний будет меньше, а сортировки вставками будут выполняться долго. Причём эти функции растут с разной скоростью, поэтому и ещё после эксперементов на различных значениях и был выбран оптимальный диапазон {{---}} от &amp;lt;tex&amp;gt;32&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;64&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации==&lt;br /&gt;
* Peter McIlroy &amp;quot;Optimistic Sorting and Information Theoretic Complexity&amp;quot;, Proceedings of the Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, ISBN 0-89871-313-7, Chapter 53, pp 467-474, January 1993. &lt;br /&gt;
&lt;br /&gt;
* Magnus Lie Hetland Python Algorithms: Mastering Basic Algorithms in the Python Language. — Apress, 2010. — 336 с.&lt;br /&gt;
&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/Timsort Wikipedia {{---}} Timsort]&lt;br /&gt;
&lt;br /&gt;
* [http://habrahabr.ru/company/infopulse/blog/133303/ Habrahabr {{---}} Алгоритм сортировки Timsort]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46346</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46346"/>
				<updated>2015-05-11T19:49:51Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Следующий и предыдущий */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, a.length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = '''null'''&lt;br /&gt;
    t.sons[3] = '''null'''&lt;br /&gt;
    '''if''' (t.parent != '''null''')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == null) &lt;br /&gt;
    root = n&lt;br /&gt;
    return&lt;br /&gt;
   Node a = search(x)&lt;br /&gt;
   '''if''' (a.parent == '''null''') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} любой брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то найдем у любого соседнего листа его родителя, обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Обозначим отца соседнего листа за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.Рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 3 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если p не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если p существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) &amp;lt;font color=green&amp;gt; //x не было в дереве, и мы нашли следующий сразу&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != '''null''')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
        '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46340</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46340"/>
				<updated>2015-05-11T18:26:54Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, a.length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = '''null'''&lt;br /&gt;
    t.sons[3] = '''null'''&lt;br /&gt;
    '''if''' (t.parent != '''null''')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == null) &lt;br /&gt;
    root = n&lt;br /&gt;
    return&lt;br /&gt;
   Node a = search(x)&lt;br /&gt;
   '''if''' (a.parent == '''null''') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} любой брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень (одновременно и единственный элемент в дереве). Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то найдем у любого соседнего листа его родителя, обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Обозначим отца соседнего листа за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.Рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 3 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если p не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если p существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != '''null''')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
        '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46339</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46339"/>
				<updated>2015-05-11T18:25:29Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Поиск */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 19, оранжевые стрелки обозначают путь по дереву при поиске]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, a.length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = '''null'''&lt;br /&gt;
    t.sons[3] = '''null'''&lt;br /&gt;
    '''if''' (t.parent != '''null''')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == null) &lt;br /&gt;
    root = n&lt;br /&gt;
    return&lt;br /&gt;
   Node a = search(x)&lt;br /&gt;
   '''if''' (a.parent == '''null''') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} любой брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то найдем у любого соседнего листа его родителя, обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Обозначим отца соседнего листа за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.Рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 3 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если p не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если p существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != '''null''')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
        '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46338</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46338"/>
				<updated>2015-05-11T18:23:48Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Вставка элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''2-3 tree'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''T''' search('''T''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else''' '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
       t = t.sons[2]&lt;br /&gt;
     '''else''' '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
       t = t.sons[1]&lt;br /&gt;
     '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t.keys[0]&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя, ведь у него тоже могло быть уже &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, а мы разделили и у него стало на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; сына больше. (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 '''function''' splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
    Node a = Node(sons = {t.sons[2], t.sons[3]}, keys = {t.keys[2]}, parent = t.parent, a.length = 2)&lt;br /&gt;
    t.sons[2].parent = a&lt;br /&gt;
    t.sons[3].parent = a&lt;br /&gt;
    t.length = 2&lt;br /&gt;
    t.sons[2] = '''null'''&lt;br /&gt;
    t.sons[3] = '''null'''&lt;br /&gt;
    '''if''' (t.parent != '''null''')&lt;br /&gt;
      t.parent[t.length] = a&lt;br /&gt;
      t.length++&lt;br /&gt;
      сортируем сыновей у t.parent&lt;br /&gt;
      splitParent(t.parent)&lt;br /&gt;
    '''else'''                   &amp;lt;font color=green&amp;gt;// мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&amp;lt;/font&amp;gt;&lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = a&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     a.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 '''function''' updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) &amp;lt;font color=green&amp;gt;// max {{---}} возвращает максимальное значение в поддереве.&amp;lt;/font&amp;gt;&lt;br /&gt;
    a = a.parent                 &amp;lt;font color=green&amp;gt;// Примечание: max легко находить, если хранить максимум &amp;lt;/font&amp;gt;&lt;br /&gt;
                                 &amp;lt;font color=green&amp;gt;// правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 '''function''' insert('''T''' x):&lt;br /&gt;
   Node n = Node(x)&lt;br /&gt;
   '''if''' (root == null) &lt;br /&gt;
    root = n&lt;br /&gt;
    return&lt;br /&gt;
   Node a = search(x)&lt;br /&gt;
   '''if''' (a.parent == '''null''') &lt;br /&gt;
     Node t = root&lt;br /&gt;
     root.sons[0] = t&lt;br /&gt;
     root.sons[1] = n&lt;br /&gt;
     t.parent = root&lt;br /&gt;
     n.parent = root&lt;br /&gt;
     root.length = 2&lt;br /&gt;
     сортируем сыновей у root&lt;br /&gt;
   '''else''' &lt;br /&gt;
     Node p = a.parent&lt;br /&gt;
     p.sons[p.length] = n&lt;br /&gt;
     p.length++&lt;br /&gt;
     n.parent = p&lt;br /&gt;
     сортируем сыновей у p&lt;br /&gt;
     updateKeys(n) &lt;br /&gt;
     split(n)&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
*&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; {{---}} любой брат &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него строго больше &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сыновей, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; уменьшим количество детей.&lt;br /&gt;
&lt;br /&gt;
Если у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то найдем у любого соседнего листа его родителя, обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Обозначим отца соседнего листа за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.Рассмотрим возможные случаи:&lt;br /&gt;
*&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не существует, тогда мы удаляем одного из сыновей корня, тогда другой сын становится новым корнем,&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, но у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; не изменим количество детей. Так у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось тоже два сына,повторяем для него такие же рассуждения.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то необходимо его расщепить. Теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось два сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 2 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось три сына, а у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; все ещё больше одного сына, то все узлы 2-3 дерева корректны.&lt;br /&gt;
*у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; оказалось &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось 3 сына. Подвесим &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а у отца уменьшим количество детей. Так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; оказалось четыре сына, то расщепим его, теперь у отца &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt; вновь три сына и все узлы 2-3 дерева корректны.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обобщим алгоритм при удалении когда у родителя &amp;lt;tex&amp;gt;\mathtt{t}&amp;lt;/tex&amp;gt; два сына(ниже мы никогда не уменьшаем количество детей у &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;):&lt;br /&gt;
*Если p не существует, то оказывается, что мы сейчас удаляем какого-то из сыновей корня (для определенности далее левого, с правым аналогично). Тогда теперь правый сын становится корнем. На этом удаление заканчивается.&lt;br /&gt;
&lt;br /&gt;
*Если p существует, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата (&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;) перецепим к &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Теперь у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына, поэтому повторим аналогичные действия из &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt;: вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;. Теперь рекурсивно удалим &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В результате мы получаем корректное по структуре 2-3 дерево, но у нас есть нарушение в ключах в узлах, исправим их с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  '''T''' next('''T''' x)&lt;br /&gt;
    Node t = search(x)&lt;br /&gt;
    '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
      '''return''' t&lt;br /&gt;
    '''while''' (t != '''null''')&lt;br /&gt;
      t = t.parent&lt;br /&gt;
      if (можно свернуть направо вниз)&lt;br /&gt;
       в t помещаем вершину, в которую свернули&lt;br /&gt;
       '''while''' (пока t {{---}} не лист)&lt;br /&gt;
        t = t.sons[0]&lt;br /&gt;
        '''return''' t&lt;br /&gt;
    '''return''' t.keys[0];&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m  \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treesearch.png&amp;diff=46337</id>
		<title>Файл:23treesearch.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treesearch.png&amp;diff=46337"/>
				<updated>2015-05-11T18:19:47Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treesearch.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treesearch.png&amp;diff=46336</id>
		<title>Файл:23treesearch.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treesearch.png&amp;diff=46336"/>
				<updated>2015-05-11T18:19:26Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treesearch.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46304</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46304"/>
				<updated>2015-05-10T21:39:37Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|Пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|Поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|Добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|Удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|Путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|Изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46303</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46303"/>
				<updated>2015-05-10T21:36:30Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Нахождение m следующих элементов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом: будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46302</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46302"/>
				<updated>2015-05-10T21:33:37Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Нахождение m следующих элементов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; и запишем в &amp;lt;tex&amp;gt;\mathtt{next.left}&amp;lt;/tex&amp;gt; правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46301</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46301"/>
				<updated>2015-05-10T21:30:44Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Нахождение m следующих элементов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел. Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46300</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46300"/>
				<updated>2015-05-10T21:30:25Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Нахождение m следующих элементов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} удаляемый узел.&lt;br /&gt;
&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46299</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46299"/>
				<updated>2015-05-10T21:30:00Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Нахождение m следующих элементов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - удаляемый узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|изменение ссылок при добавлении нового элемента|thumb|center|800px]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treefindm.png&amp;diff=46298</id>
		<title>Файл:23treefindm.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treefindm.png&amp;diff=46298"/>
				<updated>2015-05-10T21:28:33Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46297</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46297"/>
				<updated>2015-05-10T21:25:15Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Нахождение m следующих элементов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - удаляемый узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefindm.png|thumb|изменение ссылок при добавлении нового элемента|border]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46296</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46296"/>
				<updated>2015-05-10T21:18:02Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Источники информации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - удаляемый узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefind.png|border]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} стр. 508 - 509&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46295</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46295"/>
				<updated>2015-05-10T21:13:00Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Источники информации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - удаляемый узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefind.png|border]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск» {{---}} 508с&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46294</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46294"/>
				<updated>2015-05-10T21:09:18Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Источники информации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - удаляемый узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefind.png|border]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск», т. 3, с. 508&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46293</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46293"/>
				<updated>2015-05-10T20:53:27Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Поиск */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|600px|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - удаляемый узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefind.png|border]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск», часть 6.2.4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46292</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46292"/>
				<updated>2015-05-10T20:52:42Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Поиск */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|thumb|center|поиск элемента 2]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - удаляемый узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefind.png|border]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск», часть 6.2.4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treesearch.png&amp;diff=46290</id>
		<title>Файл:23treesearch.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treesearch.png&amp;diff=46290"/>
				<updated>2015-05-10T20:46:44Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treesearch.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treesearch.png&amp;diff=46289</id>
		<title>Файл:23treesearch.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treesearch.png&amp;diff=46289"/>
				<updated>2015-05-10T20:46:23Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treesearch.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46288</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46288"/>
				<updated>2015-05-10T20:21:31Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|пример 2-3 дерева|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - удаляемый узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefind.png|border]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск», часть 6.2.4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treemain.png&amp;diff=46287</id>
		<title>Файл:23treemain.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treemain.png&amp;diff=46287"/>
				<updated>2015-05-10T20:20:26Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treemain.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treemain.png&amp;diff=46286</id>
		<title>Файл:23treemain.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treemain.png&amp;diff=46286"/>
				<updated>2015-05-10T20:20:05Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treemain.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treemain.png&amp;diff=46285</id>
		<title>Файл:23treemain.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treemain.png&amp;diff=46285"/>
				<updated>2015-05-10T20:19:43Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treemain.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46284</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46284"/>
				<updated>2015-05-10T20:18:38Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Вставка элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|thumb|center|добавление элемента с ключом 6|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - удаляемый узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefind.png|border]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск», часть 6.2.4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46283</id>
		<title>Файл:23treeinsert.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46283"/>
				<updated>2015-05-10T20:17:14Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treeinsert.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46282</id>
		<title>Файл:23treeinsert.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:23treeinsert.png&amp;diff=46282"/>
				<updated>2015-05-10T20:16:53Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: загружена новая версия «Файл:23treeinsert.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46281</id>
		<title>2-3 дерево</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=2-3_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE&amp;diff=46281"/>
				<updated>2015-05-10T20:15:09Z</updated>
		
		<summary type="html">&lt;p&gt;Flanir1: /* Удаление элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:23treemain.png|400px|thumb]]''' 2-3 дерево '''(англ. ''Heapsort'') — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. Является частным случаем [[B-дерево#B.2B-.D0.B4.D0.B5.D1.80.D0.B5.D0.B2.D0.BE|B+ дерева]].&lt;br /&gt;
== Свойства ==&lt;br /&gt;
2-3 дерево {{---}} сбалансированное дерево поиска, обладающее следующими свойствами:&lt;br /&gt;
*нелистовые вершины имеют либо &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына,&lt;br /&gt;
*нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения. Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,&lt;br /&gt;
*сыновья упорядочены по значению максимума поддерева сына,&lt;br /&gt;
*все листья лежат на одной глубине,&lt;br /&gt;
*Высота 2-3 дерева &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
== Операции ==&lt;br /&gt;
Введем следующие обозначения:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{root}&amp;lt;/tex&amp;gt; {{---}} корень 2-3 дерева.&lt;br /&gt;
Каждый узел дерева обладает полями:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{parent}&amp;lt;/tex&amp;gt; {{---}} родитель узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{sons}&amp;lt;/tex&amp;gt; {{---}} сыновья узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{keys}&amp;lt;/tex&amp;gt; {{---}} ключи узла, &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{length}&amp;lt;/tex&amp;gt; {{---}} количество сыновей.&lt;br /&gt;
=== Поиск ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} искомое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. &lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;. Будем просматривать ключи в узлах, пока узел не является листом. Рассмотрим два случая:&lt;br /&gt;
*у текущей вершины два сына. Если её значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*у текущей вершины три сына. Если второе значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[2]}&amp;lt;/tex&amp;gt;. Если первое значение меньше &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;t = \mathtt{t.sons[1]}&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;t = \mathtt{t.sons[0]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''Node''' search('''int''' x):&lt;br /&gt;
   Node t = root&lt;br /&gt;
   '''while''' (t не является листом)&lt;br /&gt;
     '''if''' (t.length == 2)&lt;br /&gt;
       '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
         t = t.sons[1]&lt;br /&gt;
       '''else''' t = t.sons[0]&lt;br /&gt;
     '''else'''&lt;br /&gt;
       '''if''' (t.keys[1] &amp;lt; x)&lt;br /&gt;
         t = t.sons[2]&lt;br /&gt;
       '''else'''&lt;br /&gt;
         '''if''' (t.keys[0] &amp;lt; x)&lt;br /&gt;
           t = t.sons[1]&lt;br /&gt;
         '''else''' t = t.sons[0]&lt;br /&gt;
   '''return''' t&lt;br /&gt;
Пример поиска в 2-3 дереве, так как элемент &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; существует, то был возвращен корректный узел, так как элемента &amp;lt;tex&amp;gt;10&amp;lt;/tex&amp;gt; нет, возвращается некорректный узел. На основе этого можно сделать метод &amp;lt;tex&amp;gt;\mathtt{exist}&amp;lt;/tex&amp;gt;, проверяющий наличии элемента в дереве.&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treesearch.png|border]]&lt;br /&gt;
&lt;br /&gt;
=== Вставка элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} добавляемое значение,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущая вершина в дереве. Изначально &amp;lt;tex&amp;gt;t = \mathtt{root}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:&lt;br /&gt;
&lt;br /&gt;
Найдем сперва, где бы находился элемент, применив &amp;lt;tex&amp;gt;\mathtt{search(x)}&amp;lt;/tex&amp;gt;. Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент {{---}} лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.&lt;br /&gt;
&lt;br /&gt;
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;, то разделим родителя на два узла, и повторим разделение теперь для его родителя (перед разделением обновим ключи).&lt;br /&gt;
&lt;br /&gt;
 splitParent('''Node''' t):&lt;br /&gt;
  '''if''' (t.length &amp;gt; 3) &lt;br /&gt;
     Node a;&lt;br /&gt;
     a.sons[0] = t.sons[2]&lt;br /&gt;
     a.sons[1] = t.sons[3]&lt;br /&gt;
     t.sons[2].parent = a&lt;br /&gt;
     t.sons[3].parent = a&lt;br /&gt;
     a.keys[0] = t.keys[2]&lt;br /&gt;
     a.length = 2&lt;br /&gt;
     t.length = 2&lt;br /&gt;
     t.sons[2] = '''null'''&lt;br /&gt;
     t.sons[3] = '''null'''&lt;br /&gt;
     '''if''' (t.parent != '''null''')&lt;br /&gt;
       t.parent[t.length] = a&lt;br /&gt;
       t.length++&lt;br /&gt;
       сортируем сыновей у t.parent&lt;br /&gt;
       splitParent(t.parent)&lt;br /&gt;
     '''else'''                   //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем&lt;br /&gt;
      Node t = root&lt;br /&gt;
      root.sons[0] = t&lt;br /&gt;
      root.sons[1] = a&lt;br /&gt;
      t.parent = root&lt;br /&gt;
      a.parent = root&lt;br /&gt;
      root.length = 2&lt;br /&gt;
      сортируем сыновей у root&lt;br /&gt;
Если сыновей стало &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:&lt;br /&gt;
 updateKeys('''Node''' t): &lt;br /&gt;
   Node a = t.parent&lt;br /&gt;
   '''while''' (a != '''null''')&lt;br /&gt;
    '''for''' i = 0 .. a.length - 1&lt;br /&gt;
      a.keys[i] = max(a.sons[i]) //max {{---}} возвращает максимальное значение в поддереве.&lt;br /&gt;
    a = a.parent                 //Примечание: max легко находить, если хранить максимум &lt;br /&gt;
                                 //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; необходимо запускать от нового узла.&lt;br /&gt;
Добавление элемента:&lt;br /&gt;
 insert('''int''' x):&lt;br /&gt;
 Node n = Node(x)&lt;br /&gt;
 '''if''' (root == null) &lt;br /&gt;
  root = n&lt;br /&gt;
  return&lt;br /&gt;
 Node a = search(x)&lt;br /&gt;
 '''if''' (a.parent == '''null''') &lt;br /&gt;
   Node t = root&lt;br /&gt;
   root.sons[0] = t&lt;br /&gt;
   root.sons[1] = n&lt;br /&gt;
   t.parent = root&lt;br /&gt;
   n.parent = root&lt;br /&gt;
   root.length = 2&lt;br /&gt;
   сортируем сыновей у root&lt;br /&gt;
 '''else''' &lt;br /&gt;
   Node p = a.parent&lt;br /&gt;
   p.sons[p.length] = n&lt;br /&gt;
   p.length++&lt;br /&gt;
   n.parent = p&lt;br /&gt;
   сортируем сыновей у p&lt;br /&gt;
   updateKeys(n) &lt;br /&gt;
   split(n)&lt;br /&gt;
 updateKeys(n) &lt;br /&gt;
Так как мы спускаемся один раз, и поднимаемся вверх при расщеплении родителей не более одного раза, то &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; работает за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Примеры добавления:&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert.png|border|600px]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert2.png|800px|border]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treeinsert3.png|800px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Удаление элемента ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} значение удаляемого узла,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
Пусть изначально &amp;lt;tex&amp;gt;t = \mathtt{search(x)}&amp;lt;/tex&amp;gt; {{---}} узел, где находится &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не существует родителя, то это корень. Удалим его.&lt;br /&gt;
&lt;br /&gt;
Если у &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; существует родитель, и у него &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; сына, то просто удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Обновим ключи, запустив &amp;lt;tex&amp;gt;\mathtt{updateKeys}&amp;lt;/tex&amp;gt; от любого брата &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если у родителя(&amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; сына, то удалим &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а его брата(&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; перецепим к родителю соседнего листа(обозначим его за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;). Вызовем &amp;lt;tex&amp;gt;\mathtt{updateKeys}(b)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{splitParent}(p)&amp;lt;/tex&amp;gt;, так как у &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; могло оказаться &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; сына. Удалим теперь и &amp;lt;tex&amp;gt;\mathtt{t.parent}&amp;lt;/tex&amp;gt;. После возврата из рекурсии обновим все ключи с помощью &amp;lt;tex&amp;gt;\mathtt{updateKeys()}&amp;lt;/tex&amp;gt;, запустившись от &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:23treedelete.png|thumb|center|удаление элемента с ключом 2|1150px]]&lt;br /&gt;
&lt;br /&gt;
=== Следующий и предыдущий ===&lt;br /&gt;
*&amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} поисковый параметр,&lt;br /&gt;
*&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; {{---}} текущий узел.&lt;br /&gt;
В силу того, что наши узлы отсортированы по максимуму в поддереве, то следующий объект это соседний лист справа. Попасть туда можно следующим образом:&lt;br /&gt;
будем подниматься вверх, пока у нас не появится первой возможности свернуть направо вниз. Как только мы свернули направо вниз, будем идти всегда влево. Таким образом, мы окажемся в соседнем листе. Если мы не смогли ни разу свернуть направо вниз, и пришли в корень, то следующего объекта не существует. Случай с предыдущим симметричен.&lt;br /&gt;
  Node next('''int x''')&lt;br /&gt;
  Node t = search(x)&lt;br /&gt;
  '''if''' (t.keys[0] &amp;gt; x) //x не было в дереве, и мы нашли следующий сразу&lt;br /&gt;
    '''return''' t&lt;br /&gt;
  '''while''' (t != '''null''')&lt;br /&gt;
    t = t.parent&lt;br /&gt;
    if (можно свернуть направо вниз)&lt;br /&gt;
     в t помещаем вершину, в которую свернули&lt;br /&gt;
     '''while''' (пока t {{---}} не лист)&lt;br /&gt;
      t = t.sons[0]&lt;br /&gt;
      '''return''' t&lt;br /&gt;
  '''return''' t;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
[[Файл:23treenext.png|thumb|center|400px|путь при поиске следующего элемента после 2]]&lt;br /&gt;
&lt;br /&gt;
=== Нахождение m следующих элементов ===&lt;br /&gt;
B+ деревья, поддерживают операцию &amp;lt;tex&amp;gt;\mathtt{find}&amp;lt;/tex&amp;gt;, которая позволяет находить m следующих элементов. Наивная реализация выглядит следующим образом, будем вызывать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; раз поиск следующего элемента, такое решение работает за &amp;lt;tex&amp;gt;O(m * \log{n})&amp;lt;/tex&amp;gt;. Но 2-3 деревья, позволяют находить m следующих элементов за &amp;lt;tex&amp;gt;O(m + \log{n})&amp;lt;/tex&amp;gt;, что значительно ускоряет поиск при больших &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
По построению, все листья у нас отсортированы в порядке возрастания, воспользуемся этим для нахождения m элементов. Нам необходимо связать листья, для этого модифицируем&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{delete}&amp;lt;/tex&amp;gt;. Добавим к узлам следующие поля:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{right}&amp;lt;/tex&amp;gt; {{---}} указывает на правый лист,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{left}&amp;lt;/tex&amp;gt; {{---}} указывает на левый лист.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - добавленный узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом конце, после того как мы уже обновили все ключи, найдем &amp;lt;tex&amp;gt;\mathtt{next(t)}&amp;lt;/tex&amp;gt; и запишем ссылку на него в &amp;lt;tex&amp;gt;\mathtt{t.right}&amp;lt;/tex&amp;gt;. Аналогично с левым.&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - удаляемый узел.&lt;br /&gt;
Изменим &amp;lt;tex&amp;gt;\mathtt{insert}&amp;lt;/tex&amp;gt; следующим образом: в самом начале, до удаления &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, найдем следующий (&amp;lt;tex&amp;gt;mathtt{next}&amp;lt;/tex&amp;gt;) и запишем в (&amp;lt;tex&amp;gt;mathtt{next.left}&amp;lt;/tex&amp;gt;) правый лист относительно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. С левым поступим аналогично.&lt;br /&gt;
&lt;br /&gt;
В итоге, мы имеем двусвязный список в листьях, и чтобы нам вывести &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов, нам достаточно один раз найти нужный элемент и пробежаться вправо на &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:23treefind.png|border]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://is.ifmo.ru/vis/tree23/tree23_ru.html is.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/trees/2-3-2002 rain.ifmo.ru {{---}} Визуализатор 2-3 дерева]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/2-3-дерево Википедия {{---}} 2-3 дерево]&lt;br /&gt;
* Д. Кнут «Искусство программирования. Сортировка и поиск», часть 6.2.4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Структуры данных]]&lt;br /&gt;
[[Категория:Деревья поиска]]&lt;/div&gt;</summary>
		<author><name>Flanir1</name></author>	</entry>

	</feed>