Федеральное агентство по образованию РФ Государственное образовательное учреждение высшего профессионального образования Белгородский Государственный Технологический Университет им В.Г.Шухова. Кафедра программного обеспечения вычислительной техники и автоматизированных систем. Курсовая работа По дисциплином “Структура и Алгоритмы Обработки Данных” По теме “B-ДЕРЕВО” Исполнитель: МАНИТРАРИВУ Адама Маэфа Специальность: Программное обеспечение вычислительной техники и автоматизированных систем (230105) Группа: ПВ-21 Руководитель: Василий Григорьевич Синюк Белгород 2012 1 Оглавление Введение Постановка задачи Теоритическое сведение Структуры и принцип построение B-дерево Алгоритм поиска ключа Алгоритм включения ключа Алгоритм удаления ключа Программная реализация и вычислительный эксперимент Заключение Приложение 2 Введение B-дерево — структура данных, дерево поиска. С точки зрения внешнего логического представления, сбалансированное, сильно ветвистое дерево во внешней памяти. Использование B-деревьев впервые было предложено Р. Байером и Е. Маккейном в 1970 году. Сбалансированность означает, что длина любых двух путей от корня до листов различается не более чем на единицу. Ветвистость дерева — это свойство каждого узла дерева ссылаться на большое число узлов-потомков. С точки зрения физической организации B-дерево представляется как мульти списочная структура страниц внешней памяти, то есть каждому узлу дерева соответствует блок внешней памяти (страница). Внутренние и листовые страницы обычно имеют разную структуру. Структура B-дерева применяется для организации индексов во многих современных СУБД. B-дерево может применяться для структурирования (индексирования) информации на жёстком диске. Время доступа к произвольному блоку на жёстком диске очень велико (порядка миллисекунд), поскольку оно определяется скоростью вращения диска и перемещения головок. Поэтому важно уменьшить количество узлов, просматриваемых при каждой операции. Использование поиска по списку каждый раз для нахождения случайного блока могло бы привести к чрезмерному количеству обращений к диску, вследствие необходимости осуществления последовательного прохода по всем его элементам, предшествующим заданному; тогда как поиск в B-дереве, благодаря свойствам сбалансированности и высокой ветвистости, значительно позволяет сократить количество таких операций. 3 Постановка задачи Познакомится со структурными данными B-дерево. 4 Теоритическое сведение Структура и принципы построения B-дерево В-дерево – это дерево с некоторым характеристиками, которые отличают его от нормального дерева. Само дерево – это конечное непустое множество T, над которым определены отношения иерархического порядка (т.е. «один ко многим»), и состоящее из 1 или более вершин таких, что выполняются следующие условие: Имеется одна специально обозначенная вершина, называемая корнем данного дерево Остальные вершины (исключая корень) содержаться в m>=0 попарно не пересекающихся множествах T1, T2, … Tm, каждое из которых в свою очередь являются деревом. T1, T2 … Tm называют поддеревьями данного корня, а корня каждого этих дерев являются сыновым корня дерева T. Если у дерева нет поддерева (нет сыновей или нет потомок), то его корень называется листьям. С одной стороны, B-дерево – это дерево поиска. То есть, значения ключей в правом поддереве больше чем значения ключ в корне данного дерева. Однако значения ключей в левом поддереве меньше чем значения ключ в корне данного дерева. С другой стороны, B-дерево – это сбалансированное дерево. То есть, расстояния от корня до любого листья равны. Короче говоря, B-дерево – это сбалансированное дерево поиска, удовлетворяющее следующими условьями: Каждый узел содержит хотя бы один ключ. Ключи в каждом узле упорядочены. Корень содержит от 1 до 2t-1 ключей. Любой другой узел содержит от t-1 до 2t-1 ключей. Листья не являются исключением из этого правила. У листьев потомков нет. Любой другой узел, содержащий ключи k1, … kn содержит n+1 сыновей. При этом 1. Первый сын и все его потомки содержат ключи из интервала (-∞,k1) 2. Для 2 ≤ i ≤ n, i-й сын и все его потомки содержат ключи из интервала (ki, ki-1) 3. (n+1)-й сын и все его потомки содержат ключи из интервала (kn,inf) 5 Глубина всех листьев одинакова. Свойство 2 можно сформулировать иначе: каждый узел B-дерева, кроме листьев, можно рассматривать как упорядоченный список, в котором чередуются ключи и указатели на сыновей. t - называется порядком B-дерево, значение которого не меньшее 2 (и обычно принимающий значения от 50 до 2000). Верхний предел равен 2t-1, но временно в узле может находиться 2t ключ; эту ситуацию назовём переполнением узла. Соответственно массив ключей и курсоров имеют размеры 2t и 2t+1. Временно в узле может содержаться t-2 ключ; это ситуация нехватки, возникающая при удалениях ключей. Обе ситуаций вызывают немедленную локальную перестройку B-дерева. При добавлениях (исключениях) записей высота B-дерево может растить (убывать). В качестве примера, поставим согласные буквы английского алфавита в B-дереве. Получим дерево как изображено на рис. 1. Рисунок 1 В-дерево в примере Варианты B-дерево B+-дерево: Особенность B+дерево и его отличие от B-дерево это: a) Поиск обязательно заканчивается в листе. b) Удаление ключа имеет преимущество — удаление всегда происходит из листа. c) Другие операции выполняются аналогично B-деревьям. 6 d) B+ деревья требуют больше памяти для представления, чем B-деревья. e) B+ деревья имеют возможность последовательного доступа к ключам. B*-дерево: Оно балансирует более соседних внутренных узлов, чтобы сохранить их компактности. Для этого, вместо посредственно разделения узел на 2 когда она полная, остаточный ключ дают только соседнему узлу. Если оба полны, то эти 2 узлы разделяется на 3. Замечание: 1) если имеется n ключей, и их нужно сохранить, используя структура данных тип Bдерева, то такое дерево имеет высота h ≈ O(logt(n)) доказательство: Каждый узел имеет, по крайней мере, t-1 сын и не больше 2t-1 сын, и если количество узел на i-ый уровень равен pi , to количество узел на i-ый уровень будет pi(t-1) ≤ pi+1 ≤ pi(2t-1) . Итак: (t-1) + (t-1)2 + (t-1)3 + … + (t-1)h ≤ n ≤ (2t-1) + (2t-1)2 + (2t-1)3 + … + (2t-1)h (t − 1) (1−(t−1)) (1-(t-1)h+1) ≤ n ≤ (𝑡−1) 𝑡 ln ( (𝑡−1) 𝑡 ((t-1)h+1-1) ≤ n ≤ ((t-1)h+1-1) ≤ ln(n) ≤ ln ( (𝑡−1) ln ( ln ( 𝑡 (2t − 1) (1−(2t−1)) (2𝑡−1) 2𝑡 (1-(2t-1)h+1) ((2t-1)h+1-1) . (2𝑡−1) 2𝑡 ((2t-1) h+1-1)) ((t-1)h+1-1) ≈ (h+1)ln(t) (2𝑡−1) 2𝑡 ((2t-1) h+1-1)) ≈ (h+1)ln(2t) поэтому h+1 ≥ ln(n)/ln(t) ; h+1 ≤ lnt(n) и h+1 ≤ ln(n) /ln(2t) ; h+1 ≤ ln2t(n) следовательно, что h ≈ O(lnt(n)) 2) Вся операция начинается с корня дерева, поэтому корень сохраняется во внутренней памяти. 3) В программной реализаций, каждый узел представляет собой записей (uzl), состоящий из следующих полей : N : integer - количество ключей в узле K : array[1 .. 2t-1] of key - массив ключей, где ключ key может быть число, слова или другие упорядоченные типы данных 7 leaf : boolean – принимает значение истинно если узел является листьям, иначе ложно C : array[0 .. 2t-1] of puzl - массив указатель на узлы Доступными операциями над B-деревом являются : Обход / чтение поиск данного ключа включение ключа исключение ключа создание уничтожение Обход B-дерево это похоже на обход бинарного дерева: в глубину в прямом или обратном порядке, и в ширину. Только вместо прохождения левого и правого поддерева, проходим каждых сыновых потомков и вершин заданного узла рекурсивно. Эти алгоритмы более касается у бинарного дерева, поэтому глубоко не будим смотреть. Алгоритм создания и уничтожения B-дерева также используют тривиальные алгоритмы, поэтому их отдельно смотреть нам не нужно. Нам осталось рассмотреть и обсуждать алгоритмы поиска, включения и исключения ключа, которые в свою очередь являются чуть-чуть хитрим. Алгоритм Поиска. При поиске ключ в B-дереве, необходимо только обходить B-дерева с учётом того, что оно упорядоченно, и что узел на самом деле является массив упорядоченных ключей. Итак, находим ключ в корне (используя алгоритм нахождения ключа в упорядоченном массиве ключей: бинарный поиск). Если находили то конец алгоритм, иначе рекурсивно находить ключ в правом потомке ключа наиболее близкого меньшего значения заданного ключа. Иначе, если потомков нет, то ключ не находится в B-дереве. Алгоритм представлен в виде укрупнённого блока на рисунке 2. Входные данные : 8 x – узел, корень дерева в котором нужно искать ключ k – ключ, который нужно искать. Выходные данные : (x,i) – узел x в котором находили ключ k, и i индекс этого ключа в этом узле. То есть k = x.k[i] NULL – если ключ не находили Анализ : На каждом узле, мы ищем ключ или ключ с найблизким значением данного ключ используя алгоритм бинарного поиска в массиве. То есть, в каждом узле временная сложность алгоритм имеет одинаковую порядку с функцией log2(t) (t – количество ключ в узле). И мы знаем, что количество узлов, по которым нужно искать наш ключ не перывыщает высоту дерева O(logt(n)). То есть, алгоритм поиска ключа в B-дереве имеет порядок сложность O(log2(t)logt(n)). 9 10 Рисунок 2 : алгоритм поиска ключ в B-дереве Алгоритм включения. При включений ключ, возможно, что количество ключ в узле уже достигло верхнего предела, т.е. 2t-1. Если добавим ещё элементы то будет переполнение, и тогда нужно преобразовать дерево таким, чтобы свойства B-дерево сохраняется. Этот процесс очень важен, поэтому рассмотрим его алгоритм перед тем, что смотреть алгоритм включение. Итак, чтобы исправить переполнение, или чтобы добавить новый ключ в насыщенный узел, нам следует делать расщепление : добавить ключ в узле (количество ключ в узле временно перевешает максимальное допустимое количество ключей) выбираем и исключаем ключ со средним значением из этого узла. создаём 2 новых узла отсекая узел на середине добавим исключённый ключ в родительский узел и поставим на его левую и правую потомку ранее созданные узлы (, которые имеют размер t-1 и t) при добавлении ключ в родительский узел, если будет переполнение, то алгоритм принимается рекурсивно. На рисунке 3 привели пример. 11 Рисунок 3 : расщепление переполненного узла На рисунке 4 изображена блок-сема алгоритма расщепление переполненного узла. Входные данных : x – родительский узел i – индекс переполненного сынового потомка y – переполненный узел, то есть y = x.C[i] Выходные данных : x – родительский узел с добавлением новым ключом y, z – левый и правый потомки 12 13 Рисунок 4 : алгоритм расщепления узла Добавление нового ключа всегда делается на листе. И так, мы рекурсивно проходим дерево, начиная с корня следующим образом: Если узел является листом, то добавим ключ, в этом узле используя один из алгоритмов вставки. Если количество ключей в этом листе равен 2t, то принимаем алгоритм расщепления узла. Иначе, находим ближайший ключ меньшего значения и спускаем в правую потомку этого ключа. Принимаем снова алгоритм под узлом этой потомки На рисунке 6, изображена блок-схема алгоритма включения нового ключа в ненасыщенном узле. На рисунке 5, приведена блок-схема алгоритма включения нового ключа. В алгоритме включения только вызывают рекурсивный процедур включения, в ненасыщенном узле передавая корень как начальный узел для включения. Но перед тем, что вызывать этот процедур, проверяют сначала, насыщен ли корень дерева или нет. Если корень насыщен, то создаём новый корень, расщепляя текущий корень. Входные данные: х – корень дерева, в котором нужно добавить ключ k. k – добавляемый ключ. Анализ: На каждом уровни дерева порядок временной сложности для нахождения нужного ключа равен О(t). Но, можно даже быстрее это делать, используя алгоритм блочного или бинарного поиска (поскольку узел на самом деле является упорядоченным массивом ключей). То есть, можно уменьшить порядок временной сложности до О(log2(t)). Нам следует проходить всего h узлы (h=logt(N) – Высота дерева). 14 И так, временная сложность алгоритма добавления ключа имеет порядок О(log(t)*logt(N)) = O(log(n)) Рисунок 5 : включения нового ключа 15 16 Рисунок 6 : включения нового ключа в ненасыщенном узле На рисунках 7,8 привели примеры добавления ключа. На примере 1 добавим ключ со значением 2 на дерево. Включение происходить без трудности. На втором примере, добавление ключ 17 вызывает переполнение на 4ём листе. Поэтому этот лист надо разбить на два, и добавить исключённый средней ключ (20) из этого листа в Рисунок 7 родительский узел. 17 Рисунок 8 Алгоритм удаления ключа Для удаления ключа из B-дерево надо учитывать 3 случая. 1. Если корень одновременно является листом, то есть в дереве всего один узел, мы просто удаляем ключ из этого узла. В противном случае сначала находим узел, содержащий ключ, запоминая путь к нему. Пусть этот узел 2. Если - лист, удаляем оттуда ключ. Если в узле . осталось не меньше ключей, мы на этом останавливаемся. Иначе мы смотрим на количество ключей в следующем, а потом в предыдущем узле. Если следующий узел есть, и в нём не менее добавляем в ключей, мы ключ-разделитель между ним и следующим узлом, а на его место ставим первый ключ следующего узла, после чего останавливаемся. Если это не так, но есть предыдущий узел, и в нём не менее ключей, мы добавляем в ключ- разделитель между ним и предыдущим узлом, а на его место ставим последний ключ предыдущего узла, после чего останавливаемся. Наконец, если и с предыдущим ключом не получилось, мы объединяем узел со следующим или предыдущим узлом, и в объединённый узел перемещаем ключ, разделяющий два узла. При этом в родительском узле может остаться только ключей. Тогда, если это не корень, мы выполняем аналогичную процедуру с ним. Если мы в результате дошли до корня, и в нём осталось от 1 до иметь и меньше ключей, делать ничего не надо, потому что корень может ключей. Если же в корне не осталось ни одного ключа, исключаем корневой узел, а его единственный потомок делаем новым корнем дерева. 3. Если - не лист, а K - его -й ключ, удаляем самый правый ключ из поддерева потомков -го сына го сына , или, наоборот, самый левый ключ из поддерева потомков - . После этого заменяем ключ K удалённым ключом. Удаление ключа происходит так, как описано в предыдущем абзаце. Блок-схема алгоритм показана на рисунке 9. Входные данных : T – дерево в котором нужно удалить ключ K – удаляемый ключ Подпрограммы : Root(T) – возвращает указатель на корень дерева T 18 REMOVE-KEY(x,k) – просто удаляет ключ k из узла x PARENT-NODE(x) - возвращает указатель на родитель узла x PRECEDING/SUCCESSOR-CHILD(x) – возвращает указатель на левый/правый соседний узел узла x MAX(k,x) – возвращает максимальное значение ключ в дереве с корнем x. При выходе, x становится узел содержащий k MOVE(k,x1,x2) – исключает ключ k из x1 в x2 MERGE(x1,x2) – копирует все данные из x2 в x1, удаляет x2. Копирует ключразделитель и указатель на x2 из родителя в x1, и удалить их. При выходе, x1 x1 x2 {k – ключ-разделитель x1 и x2} 19 Рисунок 9 : удаление ключа 20 Анализ : Для анализа, рассмотрим порядок сложность для всех 3х случаев, таким образом, узнаем сложность наихудшего случай • Если корень дерева является листом, то удаления имеет порядок O(t) (проход узла для удаления ключа.) • Если ключ находится в листе, то нужно для нахождения этого ключа временной сложности порядка O(log(N)). Потом удаление можно сделать за один проход листа (O(t)). В случае нехватки в листе, т.е. x.N < t-1, и если соседний лист имеет, по крайней мере, t ключ, то для перемещения нужно O(t). Также в противном случае (то есть, когда надо 2 листа слинять), необходимо временной сложности порядка O(t). Итак, исключения ключ находящихся в листе требует временную сложность порядка O(log(N)+t). • При случае, когда ключ находится во внутренном узле, нам всего надо его обменят с наибольшем (наименьшем) ключом в левом (правом) поддереве. И потом принимать алгоритм исключения ключ из листа. Итак, эта операция требует временную сложность порядка O(log(N))+O(t)+O(log(N)+t) = O(log(N)+t). Итак, удаление ключ с B-дерева, если корень не является листом, имеет временную сложность O(log(N)+t). t – в реальном мире, это констант, и более того может имеет значение t << N, что на самом деле, временная сложность удаления ключа в B-дереве имеет порядка O(log(N)). 21 Программная реализация и вычислительный эксперимент Диаграмм класса: BTree (класс дерево): Private Root – указатель на корень B-дерево SplitChild – расщепление узла y с предком x Adjust – рекурсивное расщепление узлов начиная с x если нужно. FindParent – нахождение предка узла x. На выходе из этого процедура, x указывает на родительский узел, и i индекс по которому Public Insert – процедура для включения ключ k Search – нахождение ключ k в B-дереве. Если находили ключ, то поставим в x указатель на узел, содержащий ключ к, и в i индекс этого ключа в узле Delete – удаляет ключ k из B-дерева BTree – конструктор объект типа BTree с порядком t. ~BTree – уничтожение объекта Node (класс узел) : 22 Private N – количество ключ в узле k – массив ключей C – массив указателя на потомках Leaf – атрибут болевого типа. Принимать значение true, если узел является листом, иначе false. Public setC, setK, setN, setLeaf – процедуры для установления значения находящихся в закрытых секций класса (c, K, N и leaf). Кроме того, они проверяют правильность вводимых новых значений в узле. getC, getK, getN, isLeaf – процедуры для получения значения находящихся в закрытых секций класса FindKey – находить ключ k используя алгоритм с временной сложности O(log2(N)) в узле и возвращает его индекс. Если ключ не находиться в узле, то возвращают индекс найблизкого младшего ключа. RemoveKey – удаляет ключ k. InsertKey – включить ключ k. Замер количества расщепления относительно количество ключей в B-дереве. N npslit N npslit N npslit N npslit N npslit 985 48 8683 423 14648 734 19167 946 22783 1142 1947 94 9417 464 15215 758 19615 971 23133 1151 2873 139 10146 505 15754 784 20079 995 23437 1167 3763 186 10860 552 16282 808 20497 1016 23776 1183 4656 225 11551 587 16787 832 20894 1046 24100 1202 5511 277 12195 614 17273 860 21270 1064 24390 1213 6321 320 12856 641 17775 885 21670 1083 24705 1228 7118 354 13489 678 18270 906 22064 1110 24982 1247 7931 389 14075 703 18729 926 22425 1128 25259 1258 23 график расщепления в B-дереве 1400 1200 Название оси 1000 800 600 400 200 0 количество элементов в B-дереве 24 Заключение После рассмотрение структуры данных B-дерева и алгоритмов работающих над ними, можем сделать вывод о том что, B-дерево удобно использовать для организаций большего количество данных. Все его алгоритмы имеют порядок временной сложности O(log(N)). Быстрота действе над ним – это его основное достоинство. Обращения к физическим блокам (т.е. внешняя память) очень редка относительно других структур данных. Применение алгоритма расщепления является его недостатком. Но по результате замеров, видно, что количество расщепления при увеличений количества ключей в B-дереве растёт по логарифмическим законом. 25 Список литературы “BTrees” - Andreas Kaltenbrunner, Lefteris Kellis & Dani Mart´ “Структура и методы обработки данных” – В.С. Зубов, И.В. Шевченко “The art of Computer Programming” – Donald Knuth Wikipedia 26 Приложение Node.h: #ifndef NODE_H #define NODE_H typedef int key; class Node { public: Node(); virtual ~Node(); static int t; int findkey(key k); void removekey(key k); void insertkey(key k); void shownode(); void setC(Node *C,int i); void setK(key k,int i); void setLeaf(bool vl); Node* getC(int i); key getK(int i); bool isLeaf(); int getN(); void setN(int sn); private: int N; key *k; bool leaf; Node **C; }; #endif // NODE_H Node.cpp: #include "../include/Node.h" #include <stdlib.h> #include <stdio.h> Node::Node() { N = 0; k = (key*)calloc((2*Node::t+2),sizeof(key)); C = (Node**)calloc((2*Node::t+1),sizeof(Node*)); leaf = true; } 27 Node::~Node() { } int Node::getN(){ return N; } void Node::shownode(){ int i; printf("Node contents : ["); for (i=1;i<=N;i++) printf("%d ",k[i]); printf("] "); for (i=0;i<=N;i++) if (C[i]) printf("%d ",(C[i])->k[1]); else printf("0 "); puts(""); } int Node::findkey(key k){ int i=1,j=N,l,p=1; while (i<j&&p<1000){ p++; l=(i+j)/2; if (this->k[l]>k) j=l; else if (this->k[l]<k) i=l; else return l; } if (i==j) if (this->k[i]>k) return j-1; else return j; else if(p==1000) if(this->k[i+1]<k) return i+1; else return i; } void Node::removekey(key k){ int i=1; while (this->k[i++]<k) if (i>=N) break; if(this->k[i]==k){ while(i<N){ this->k[i]=this->k[i+1]; i++; } N--; } } void Node::setN(int sn){ this->N = sn; } 28 void Node::insertkey(key k){ N++; if (N>2*Node::t+1) {puts("Node size exceded!"); exit(-1);}; int i=N; while(this->k[i-1]>k&&i>1){ this->k[i]=this->k[i-1]; i--; } this->k[i]=k; } void Node::setC(Node *C,int i){ if (i>=0&&i<=2*Node::t) this->C[i]=C; } void Node::setK(key k,int i){ if (i>=0&&i<=2*Node::t) this->k[i]=k; } void Node::setLeaf(bool vl){ leaf = vl; } Node* Node::getC(int i){ if (i>=0&&i<=2*Node::t) return this->C[i]; else return NULL; } key Node::getK(int i){ if (i>=0&&i<=2*Node::t) return this->k[i]; else return -1; } bool Node::isLeaf(){ return leaf; } BTree.h: #ifndef BTREE_H #define BTREE_H #include "Node.h" #include <ctime> class BTree { 29 public: BTree(int t); virtual ~BTree(); static int sym; void void void void ReadData(); Insert(key k); Search(key k,Node **x,int *i); Delete(key k); int getHeight(); int nbrEl; int nbrSplit; double tins; private: void readNode(Node *x); void SplitChild(Node **x,int i,Node **y); void insertNonFull(Node *x,key k); void adjust(Node *x); void findParent(Node **x,int *i); Node* Root; }; #endif // BTREE_H BTree.cpp: #include #include #include #include "../include/BTree.h" "../include/Node.h" <stdio.h> <stdlib.h> Node *s=Root; int h=0; while(s->getC(0)){ h++; s=s->getC(0); } return h; using namespace std; int Node::t; int BTree::sym; BTree::BTree(int t) { Node::t = t; Root = new Node(); BTree::sym = 0; nbrEl=0; nbrSplit=0; } BTree::~BTree() {} int BTree::getHeight(){ } void BTree::readNode(Node (*x)){ int i=0; if (x==0||x==NULL) return; while (i<x->getN()){ readNode(x->getC(i++)); printf("%d ",(int)x>getK(i)); } if (x->getC(i)!=NULL) readNode(x>getC(i)); } void BTree::ReadData(){ readNode(Root); 30 } void BTree::Search(key k,Node *(*x),int* i){ int p=1,q=((*x))->getN(); if((*x)==NULL) return; while (p<q){ *i=(p+q)/2; if((*x)->getK(*i)==k) return; else if ((*x)->getK(*i)>k) *i=q; else *i=p; } (*x)=(*x)->getC(q); Search(k,x,i); } void BTree::SplitChild(Node **x,int i,Node *(*y)){ if((*y)->getN()<2*Node::t-1) return; Node **z = (Node**)malloc(sizeof(Node*)); (*z) = new Node(); int j; (*z)->setLeaf((*y)->isLeaf()); (*z)->setN((*y)->getN()-Node::t); (*z)->setC((*y)>getC(Node::t),0); for(j=Node::t+1;j<=(*y)->getN(); j++){ (*z)->setK((*y)->getK(j),jNode::t); (*z)->setC((*y)->getC(j),jNode::t); }; j=(*x)->getN(); if(j>i); for(j=(*x)->getN();j>i;j--) { (*x)->setC((*x)>getC(j),j+1); (*x)->setK((*x)>getK(j),j+1); } j++; (*x)->setC((*z),j); (*x)->setK((*y)>getK(Node::t),j); (*x)->setN((*x)->getN()+1); (*y)->setN(Node::t-1); nbrSplit++; } void BTree::insertNonFull(Node (*x),key k){ int i; if(x->isLeaf()){ if (k==x->getK(x>findkey(k))) return (void)(BTree::sym++); x->insertkey(k); nbrEl++; if (x->getN()>=2*Node::t) adjust(x); } else { i=x->findkey(k); if(x->getK(i)==k) return; insertNonFull(x->getC(i),k); } } void BTree::findParent(Node *(*x),int *i){ int j,k=(*x)->getK(1); Node (*s)=Root; *i = s->findkey(k); while(s->getC(*i)!=(*x) && !s>isLeaf()) { s = s->getC(*i); *i = s->findkey(k); } if (!s->isLeaf()) { (*x)=s; } else { (*x) = NULL; } } void BTree::adjust(Node (*x)){ if(x->getN()>=2*Node::t){ Node **tmp = (Node**)calloc(1,sizeof(Node*)); *tmp=x; int *i=(int*)malloc(sizeof(int)); findParent(tmp,i); //printf("%p\n",*tmp); if((*tmp)!=NULL&&(*tmp)!=x){ SplitChild(tmp,*i,&x); adjust(*tmp); } } } 31 void BTree::Insert(key k){ clock_t t1,t2; t1 = clock(); if (Root->getN()==(2*Node::t-1)){ Node *(*s)=(Node**)malloc(sizeof(Node*)); (*s) = new Node(); (*s)->setLeaf(false); (*s)->setC(Root,0); SplitChild(s,0,&Root); Root=(*s); } else insertNonFull(Root,k); t2 = clock(); tins = difftime(t2,t1); } void BTree::Delete(key k){ if (Root->isLeaf()) Root>removekey(k); else do { Node *tmp=Root; int i; Search(k,&tmp,&i); if(tmp=NULL) return; if(tmp->isLeaf()); } while (false); } 32