Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Data Structures and Algorithms in C++ 2e (На ру...docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.37 Mб
Скачать

10.1. Деревья двоичного поиска 435

Внедрение оператора приращения, кажется, содержит очевидное

ошибка. Если бы iterator указывает на самый правый узел всего дерева, то вышеупомянутая функция образовала бы петли до достижения корня, у которого нет родителя. У самого правого узла дерева нет преемника, таким образом, iterator должен возвратить конец стоимости.

Есть простой и изящный способ достигнуть желаемого поведения. Мы добавляем специальный сторожевой узел к нашему дереву, названному супер корнем, который создан, когда начальное дерево построено. Корень дерева двоичного поиска, которое мы называем виртуальным корнем, сделан покинутым ребенком супер корня. Мы определяем конец, чтобы быть iterator, который возвращает положение супер корня. Заметьте, что, если мы пытаемся увеличить iterator, который указывает на самый правый узел дерева, функция, данная в Кодовом Фрагменте 10.6, перемещает правильную цепь вверх до достижения виртуального корня, и затем останавливается в его родителе, супер корне, так как виртуальный корень - свой покинутый ребенок. Поэтому, это возвращает iterator, указывающий на супер корень, который эквивалентен концу. Это - точно поведение, которого мы желаем.

Чтобы осуществить эту стратегию, мы определяем конструктора, чтобы создать супер корень. Мы также определяем корень функции, который возвращает положение виртуального корня, то есть, покинутого ребенка супер корня. Эти функции даны в Кодовом Фрагменте 10.7.

/* SearchTree E:: */

SearchTree (): T (), n (0)

T.addRoot (); T.expandExternal (T.root ());/* SearchTree E:: */

Корень TPos () константа

возвращают T.root () .left ();

//конструктор

//создайте супер корень

//получите виртуальный корень

//оставленный ребенок супер корня

Кодовый Фрагмент 10.7: конструктор и полезность функционируют корень. Конструктор

создает супер корень, и корень возвращает виртуальный корень дерева двоичного поиска.

Затем, в Кодовом Фрагменте 10.8, мы определяем функции, начинаются и заканчиваются. Функция начинается, возвращает первый узел согласно inorder пересечению, которое является крайним левым внутренним узлом. Конец функции возвращает положение супер корня.

/* SearchTree E:: */ //iterator к первому входу

Iterator начинаются ()

TPos v = корень ();

в то время как (v.isInternal ()) v = v.left (); возвратите Iterator (v.parent ());

/* SearchTree E:: */

Конец Iterator ()

возвращают Iterator (T.root ());

//начните в виртуальном корне//, находят крайний левый узел

//iterator, чтобы закончить вход

//возвратите супер корень

Кодовый Фрагмент 10.8: начинание и функции конца класса SearchTree. func-

конец tion возвращает указатель на супер корень.

436

Глава 10. Деревья поиска

Мы теперь готовы представить внедрения основных функций класса, для нахождения, вставки и удаления записей. Мы начинаем, представляя func-tion, находят (k) в Кодовом Фрагменте 10.9. Это призывает рекурсивного сервисного искателя функции, начинающего в корне. Эта сервисная функция основана на алгоритме, данном в Кодовом Фрагменте 10.1. Кодекс был структурирован так, чтобы только меньше оператор был определен на ключах.

/* SearchTree E:: */ //находят полезность

Искатель TPos (константа K& k, константа TPos& v)

если (v.isExternal ()) возвращают v;

если (k <v-> ключ ()) возвращают искателя (k, v.left ());

//ключ, не найденный//, ищет оставленное поддерево

еще, если (v-> ключ () <k) возвращают искателя (k, v.right ());//ищут правильное поддерево

еще возвратите v; //нашел его здесь

/* SearchTree E:: */ //находят вход с ключом k

Iterator находят (константа K& k)

TPos v = искатель (k, корень ());

если (v.isInternal ()) возвращают Iterator(v); еще возвратите конец ();

//поиск от виртуального корня//нашел, что это//не находило его

Кодовый Фрагмент 10.9: функции SearchTree имели отношение к нахождению ключей.

Функции вставки показывают в Кодовом Фрагменте 10.10. Полезность вставки делает всю работу. Во-первых, это ищет ключ. Если найдено, мы продолжаем искать до достижения внешнего узла. (Вспомните, что мы позволяем, делают дубликаты ключа.) Мы тогда создаем узел, копируем информацию о входе в этот узел и обновляем количество входа. Функция вставки просто призывает полезность вставки и преобразовывает получающееся положение узла в iterator.

/* SearchTree E:: */ //вставляют полезность

Вставка TPos (константа K& k, константа V& x)

TPos v = искатель (k, корень ());

в то время как (v.isInternal ())

v = искатель (k, v.right ());

T.expandExternal(v);

v-> setKey (k); v-> setValue (x);

n + +;

возвратите v;

// // // // // // //

поиск от виртуального ключа корня уже существует? взгляд далее добавляет новый внутренний вход набора узла еще одно положение вставки возвращения входа

/* SearchTree E:: */ //вставка (k, x)

Вставка Iterator (константа K& k, константа V& x)

TPos v = вставка (k, x); возвратите Iterator(v);

Кодовый Фрагмент 10.10: функции SearchTree для вставки записей.