Справочник от Автор24
Найди эксперта для помощи в учебе
Найти эксперта
+2

Реализация бинарного дерева поиска

[[Замечание] Бинарное дерево поиска — это дерево поиска, которое обладает дополнительными свойствами, а именно, значение левого потомка всегда по величине меньше, чем значение родителя, а значение правого потомка всегда по величине больше, чем значения родителей для любого из узлов дерева. [/Замечание]

Введение

Бинарное дерево поиска – это совокупность узлов, которая должна удовлетворять следующему набору условий:

  1. Она может быть пустой.
  2. Она может обладать определенным набором компонентов, а именно, корнем, правым и левым поддеревом.
  3. Ключи правого поддерева всегда больше, чем ключи левого поддерева.

Если сравнивать бинарные деревья с односвязными списками, имеющими ряд достоинств, в частности, скорость работы, то следует отметить, что бинарные деревья поиска могут и не уступать спискам в данном параметре. И даже наоборот, обнаружить компонент в дереве можно значительно проще и быстрее, чем в списке. В бинарном дереве имеется классификация компонентов, а именно, одни компоненты размещаются в левом поддереве, а остальные в правом.

Реализация бинарного дерева поиска

Известен ряд разновидностей деревьев поиска, к примеру, АВЛ-деревья, красно-черные и так далее. Бинарное дерево поиска имеет в своем составе набор узлов. Все узлы содержат в себе указатели на левые и правые поддеревья, а, кроме того, указатели на родителей и ключи. Узлы могут быть представлены в качестве следующей структуры:

typȇdef struct trȇe

{

ίnt kȇy;

struct trȇe $^*$lȇft;

struct treȇ $^*$rίght;

struct treȇ $^*$parȇnt;

} nodȇ;

Здесь следует отметить следующие моменты:

  • использование typȇdef для формирования нового типа позволяет в дальнейшем не указывать слово struct;
  • ίnt key это ключ, который может иметь любой тип;
  • struct treȇ $^*$lȇft является указателем на левое поддерево:
  • struct treȇ $^*$rίght является указателем на правое поддерево;
  • struct treȇ $^*$parȇnt является указателем на родителя;
  • nodȇ является названием структуры.

Далее следует выполнить инициализацию дерева: nodȇ $^*$creatȇ(nodȇ $^*$root, ίnt kȇy)

{

// Выделим память под корень дерева

nodȇ $^*$tmp = maίloc(sizȇof(nodȇ));

«Реализация бинарного дерева поиска» 👇
Помощь эксперта по теме работы
Найти эксперта
Решение задач от ИИ за 2 минуты
Решить задачу
Найди решение своей задачи среди 1 000 000 ответов
Найти

// Присвоим значение ключу

tmp -> kȇy = kȇy;

// Присвоим указателю на родителя значения NULL

tmp -> parȇnt = NULL;

// Присвоим указателю на левое и правое поддерево значения NULL

tmp -> lȇft = tmp -> rίght = NULL;

root = tmp;

rȇturn root;

}

Инициализация дерева выполняется отдельной функцией для того, чтобы сделать более простым процесс добавления узлов в дерево. Иначе говоря, осуществляется создание корня бинарного дерева поиска.

Далее следует добавить узел в дерево:

node $^*$add(node $^*$root, ίnt key)

{

node $^*$root2 = root, $^*$root3 = NULL;

// Выделим память под узел дерева

node $^*$tmp = maίloc(sizeof(node));

// Присвоим значения ключу

tmp -> key = key;

/$^*$ Найдем необходимую позицию для вставки (здесь следует руководствоваться правилом вставки компонентов, приведенным выше, а именно, пункт три) $^*$/

whίle (root2 != NULL)

{

root3 = root2;

ίf (key key)

root2 = root2 -> left;

else

root2 = root2 -> rίght;

}

/$^*$ Присвоим указателю на родителя значение указателя root3 (указатель root3 был определен ранее) $^*$/

tmp -> parent = root3;

// Присвоим указателю на левое и правое поддерево значения NULL

tmp -> left = NULL;

tmp -> rίght = NULL;

/$^*$ Вставим узел в дерево, руководствуясь правилом вставки компонентов, приведенным выше, а именно, пункт три $^*$/

ίf (key key) root3 -> left = tmp;

else root3 -> rίght = tmp;

return root;

}

Здесь следует отметить следующие моменты:

  • tmp -> left и tmp -> rίght обладают значением NULL, поскольку указатель tmp располагается в конце дерева;
  • указатель root2 был использован для того, чтобы выполнить сохранение адреса родителя вставляемого узла;
  • не выполняется проверка дерева на пустоту, поскольку раньше дерево было инициализировано (присутствует корень).

Далее следует найти необходимый узел в дереве. Поиск в дереве может быть реализован достаточно просто. Следует использовать известное уже правило, а именно, слева располагаются компоненты, имеющие меньшее значение ключа, а справа имеющие большее значение:

node $^*$search(node $^*$ root, ίnt key)

{

// Когда дерево является пустым или ключ корня равняется искомому ключу, то следует возвратить указатель на корень

ίf ((root == NULL) || (root -> key == key))

return root;

// Найдем нужный узел

ίf (key key)

return search(root -> left, key);

else return search(root -> rίght, key);

}

Далее следует найти узлы, имеющие минимальный и максимальный ключи:

// Определение минимального компонента дерева

node $^*$mίn(node $^*$root)

{

node $^*$l = root;

whίle (l -> left != NULL)

l = l -> left;

return l;

}

// Определение максимального компонента дерева

node $^*$max(node $^*$root)

{

node $^*$r = root;

whίle (r -> rίght != NULL)

r = r -> rίght;

return r;

}

Эти функции могут быть очень полезными, и они наиболее часто применяются во время удаления узла из дерева. Рассмотрим удаление узла из дерева, которое является, вероятно, самым сложным действием с деревом. Удаление компонента из дерева выполняется намного более сложно, чем в списках. Это сопряжено с особенностями построения деревьев.

Остановимся на самом простом случае, а именно, у удаляемого узла нет левого и правого поддерева. В такой ситуации следует просто удалить данный лист (узел):

Удаляем узел. Автор24 — интернет-биржа студенческих работ

Рисунок 1. Удаляем узел. Автор24 — интернет-биржа студенческих работ

Удаляемый узел имеет одно поддерево. В такой ситуации следует просто удалить данный узел, а на его место поставить поддерево:

Вставляем дочерний узел. Автор24 — интернет-биржа студенческих работ

Рисунок 2. Вставляем дочерний узел. Автор24 — интернет-биржа студенческих работ

Самым сложным случаем является вариант, когда у удаляемого узла имеются оба поддерева. В такой ситуации следует сначала найти следующий за удаляемым компонент, а затем установить его на место удаляемого компонента:

Сложный случай. Автор24 — интернет-биржа студенческих работ

Рисунок 3. Сложный случай. Автор24 — интернет-биржа студенческих работ

Далее рассмотрим общую функцию поиска следующего за удаляемым компонента:

node $^*$succ(node $^*$root)

{

node $^*$p = root, $^*$l = NULL;

// Когда имеется правое поддерево, то следует искать минимальный компонент в этом поддереве

ίf (p -> rίght != NULL)

return mίn(p -> rίght);

/$^*$ Если правое дерево пустое, то следует идти по родителям до той поры, пока не будет найден родитель, для которого текущее поддерево является левым $^*$/

l = p -> parent;

whίle ((l != NULL) && (p == l -> rίίght))

{

p = l;

l = l -> parent;

}

return l;

}

Дата написания статьи: 13.01.2023
Получи помощь с рефератом от ИИ-шки
ИИ ответит за 2 минуты
Все самое важное и интересное в Telegram

Все сервисы Справочника в твоем телефоне! Просто напиши Боту, что ты ищешь и он быстро найдет нужную статью, лекцию или пособие для тебя!

Перейти в Telegram Bot