- •Оглавление
- •Введение
- •Раздел 1. Основные структуры данных
- •Тема 1. Введение в структуры данных. Динамическое распределение памяти
- •Классификация структур данных
- •1.2. Переменные-указатели и динамическое распределение памяти.
- •Например, указатели на простейшие базовые типы вводятся следующим образом:
- •Var pStr1,pStr2 :TpString; {переменные-указатели на строки}
- •1.3. Дополнительные вопросы использования переменных-указателей
- •1.4. Контрольные вопросы по теме
- •Тема 2. Структуры данных “стек” и “очередь”
- •2.1. Что такое стек и очередь?
- •2.2. Статическая реализация стека
- •2.3. Динамическая реализация стека
- •{Ссылочный тип для адресации элементов стека}
- •2.4. Статическая реализация очереди
- •2.5. Динамическая реализация очереди
- •{Ссылочный тип для адресации элементов очереди}
- •2.6. Практические задания
- •2.7. Контрольные вопросы по теме
- •Тема 3. Основы реализации списковых структур
- •3.1. Структуры данных типа “линейный список”
- •3.2. Первый способ статической реализации списка.
- •3.3. Второй способ статической реализации списка.
- •3.4. Управление памятью при статической реализации списков
- •3.5. Динамическая реализация линейных списков
- •3.6. Практические задания
- •3.7. Контрольные вопросы по теме
- •Тема 4. Усложненные списковые структуры
- •4.1. Двунаправленные линейные списки
- •4.2. Комбинированные структуры данных: массивы и списки указателей
- •4.3. Комбинированные структуры данных: массивы и списки списков
- •4.4. Практические задания.
- •4.5. Контрольные вопросы по теме
- •Тема 5. Основные понятия о древовидных структурах
- •5.1. Основные определения
- •5.2. Двоичные деревья
- •5.3. Идеально сбалансированные деревья
- •5.4. Практические здания
- •5.5. Контрольные вопросы по теме
- •Тема 6. Реализация поисковых деревьев
- •Двоичные деревья поиска.
- •6.2. Добавление вершины в дерево поиска
- •6.3. Удаление вершины из дерева поиска
- •6.4. Практические задания
- •Контрольные вопросы по теме
- •Тема 7. Дополнительные вопросы обработки деревьев. Графы.
- •Проблемы использования деревьев поиска
- •7.2. Двоичные деревья с дополнительными указателями
- •7.3. Деревья общего вида (не двоичные).
- •Представление графов
- •Практические задания
- •Контрольные вопросы по теме
- •Раздел 2. Алгоритмы сортировки и поиска
- •Тема 1. Классификация методов. Простейшие методы сортировки
- •1.1. Задача оценки и выбора алгоритмов
- •1.2. Классификация задач сортировки и поиска
- •1.3. Простейшие методы сортировки: метод обмена
- •1.4. Простейшие методы сортировки: метод вставок
- •1.5. Простейшие методы сортировки: метод выбора
- •1.6. Практическое задание
- •1.7. Контрольные вопросы по теме
- •Тема 2. Улучшенные методы сортировки массивов
- •2.1. Метод Шелла
- •2.2. Метод быстрой сортировки
- •2.3. Пирамидальная сортировка
- •2.4. Практическое задание
- •2.5. Контрольные вопросы по теме
- •Тема 3. Специальные методы сортировки
- •3.1. Простейшая карманная сортировка.
- •3.2. Карманная сортировка для случая повторяющихся ключей
- •3.3. Поразрядная сортировка
- •3.4. Практическое задание
- •3.5. Контрольные вопросы по теме
- •Тема 4. Поиск с использованием хеш-функций
- •4.1. Основные понятия
- •4.2. Разрешение конфликтов: открытое хеширование
- •4.3. Разрешение конфликтов: внутреннее хеширование
- •4.4. Практические задания
- •4.5. Контрольные вопросы по теме
- •Тема 5. Внешний поиск и внешняя сортировка
- •5.1. Особенности обработки больших наборов данных
- •5.2. Организация внешнего поиска с помощью б-деревьев.
- •5.4. Поиск элемента в б-дереве.
- •5.5. Добавление вершины в б-дерево
- •5.6. Удаление вершины из б-дерева
- •5.7. Внешняя сортировка
- •5.8. Практические задания
- •5.9. Контрольные вопросы по теме
- •Основные термины и понятия
- •Литература
6.3. Удаление вершины из дерева поиска
Теперь рассмотрим удаление вершины из ДП. По сравнению с добавлением удаление реализуется более сложным алгоритмом, поскольку добавляемая вершина всегдаявляетсятерминальной, а удаляться можетЛЮБАЯ, в том числе и нетерминальная. При этом может возникать несколько различных ситуаций.
Рассмотрим фрагмент ДП с целыми ключами.
50
30 70
20 40 60 80
25 45 35
23 33 37
Ситуация 1. Удаляемая вершинане имеет ни одного потомка, т.е. является терминальной. Удаление реализуется очень легко обнулением соответствующего указателя у родителя. Например, для удаления вершины с ключом 23 достаточно установить 25.left=nil.
Ситуация 2. Удаляемая вершина имееттолько одного потомка. В этом случае удаляемая вершина вместе со своим потомком и родителем образуют фрагмент линейного списка. Удаление реализуется простым изменением указателя у родительского элемента. Например, для удаления вершины с ключом 20 достаточно установить 30.left= 20.right= 25
Ситуация 3. Пусть удаляемая вершина имеетдвух потомков. Этот случай наиболее сложен, поскольку нельзя просто в родительской вершине изменить соответствующее ссылочное поле на адрес одного из потомков удаляемой вершины. Это может нарушить структуру дерева поиска. Например, замена вершины 30 на одного из ее непосредственных потомков 20 или 40 сразу нарушает структуру дерева поиска.
Существует специальное правило для определения вершины, которая должна заменитьудаляемую. Это правило состоит из двух взаимоисключающих действий:
либо войти в левоеподдерево удаляемой вершины и в этом поддереве спустится как можно глубже, придерживаясь толькоправыхпотомков; это позволяет найти в дереве ближайшуюменьшуювершину (например, для вершины 30 это будет вершина 25)
либо войти в правоеподдерево удаляемой вершины и спустится в нем как можно глубже придерживаясь тольколевыхпотомков; это позволяет найти ближайшуюбОльшуювершину (например, для той же вершины 30 это будет вершина 33).
Перейдем к программной реализации процедуры удаления. Поскольку при удалении могут изменяться связи между внутренними вершинами дерева, удобно (но, конечно же, не обязательно) использовать рекурсивную реализацию. Основная процедура DeleteNode рекурсивно вызывает сама себя для поиска удаляемой вершины. После нахождения удаляемой вершины процедураDeleteNode определяет число ее потомков. Если потомков не более одного, выполняется само удаление. Если потомков два, то вызывается вспомогательная рекурсивная процедураChangerдля поиска вершины-заменителя.
Procedure DeleteNode ( var pCurrent : Tp);
VarpTemp : Tp;
Procedure Changer ( var p : Tp);
begin
{реализация рассматривается ниже}
end;
begin
ifpCurrent=nilthen“удаляемой вершины нет, ничего не делаем”
else
if x < pCcurrent^.inf then DeleteNode ( pCcurrent^.left)
else
if x > pCurrent^.inf then DeleteNode ( pCurrent^.right)
else {удаляемая вершина найдена}
begin
pTemp := pCurrent;
if pTemp^.right = nil then pCurrent := pTemp^.left
else
if pTemp^.left = nil then pCurrent := pTemp^.right
else{два потомка, ищем заменитель}
Changer ( pCurrent^.left); { а можно и pCurrent^.right }
Dispose ( pTemp);
end;
end;
Схема процедуры Changer:
begin
if p^.right <> nil then Changer ( p^.right)
else{правое поддерево пустое, заменитель найден, делаем обмен}
begin
pTemp^.inf:=p^.inf; {заменяем информац. часть удаляемой вершины}
pTemp:=p; {pTempтеперь определяет вершину-заменитель}
p:=p^.left; {выходной параметр адресует левого потомка заменителя}
end;
end;
Дополнительный комментарий к процедурам. Подпрограмма Changerв качестве входного значения получает адрес левого (или правого) потомка удаляемой вершины и рекурсивно находит вершину-заменитель. После этого информационная часть удаляемой вершины заменяется содержимым вершины-заменителя, т.е.фактического удаления вершины не происходит. Это позволяет сохранить неизменными обе связи этой вершины с ее потомками. Удаление реализуется относительновершины-заменителя, для чего ссылкаpTempпосле обмена устанавливается в адрес этой вершины. Кроме того, в самом конце процедурыChangerустанавливается новое значение выходного параметраp: оно равно адресу левого потомка вершины-заменителя. Это необходимо для правильного изменения адресной части вершины-родителя для вершины-заменителя. Само изменение происходит при отработке механизма возвратов из рекурсивных вызовов процедурыChanger. Когда все эти возвраты отработают, происходит возврат в основную процедуруDeleteNode, которая освобождает память, занимаемую вершиной-заменителем. Отметим, что приведенная выше реализация процедурыChangerориентирована на поиск в левом поддереве удаляемой вершины и требует симметричного изменения для поиска заменителя в правом поддереве.
Для окончательного уяснения данного алгоритма настоятельно рекомендуем провести ручную пошаговую отработку его для небольшого примера, как это было сделано для значительно более простого алгоритма построения идеально сбалансированного дерева.