Опубликован: 05.01.2015 | Доступ: свободный | Студентов: 2177 / 0 | Длительность: 63:16:00
Лекция 12:

Таблицы символов и деревья бинарного поиска

Реализации других функций АТД с помощью BST -ДЕРЕВА

Рекурсивные реализации из раздела 12.5 для основных операций найти, вставить и сортировать, использующие структуру бинарных деревьев, достаточно просты. В этом разделе мы рассмотрим реализации функций выбрать, объединить и удалить. Одна из них, выбрать, также допускает естественную рекурсивную реализацию, однако для других это может оказаться трудной задачей, приводящей к потере производительности. Операцию выбрать важно рассмотреть потому, что возможность эффективной поддержки операций выбрать и сортировать - одна из причин, по которой для многих приложений BST-деревья оказываются удобнее других структур. Хотя некоторые программисты стараются не использовать BST-деревья, чтобы не возиться с операцией удалить. В этом разделе рассматривается компактная реализация всех этих операций, использующая технику ротации к корню из раздела 12.8.

Обычно эти операции связаны с перемещением вниз по дереву; поэтому для случайных BST-деревьев можно ожидать, что затраты будут логарифмическими. Однако нельзя гарантировать, что BST-деревья останутся случайными после выполнения над ними многочисленных операций. В конце этого раздела мы еще вернемся к данному вопросу.

Для реализации операции выбрать можно использовать рекурсивную процедуру, аналогичную методу выборки на основе быстрой сортировки, описанному в "Быстрая сортировка" . Для отыскания в BST-дереве элемента с k-ым наименьшим ключом проверяется количество узлов в левом поддереве. Если там к узлов, возвращается корневой элемент. Иначе, если левое поддерево содержит более к узлов, в нем (рекурсивно) отыскивается к-й наименьший узел. Если неверно ни одно из этих условий, то левое поддерево содержит t элементов при t < k, и k-й наименьший элемент в BST-дереве является (k - t - 1)- ым наименьшим элементом в правом поддереве. Программа 12.14 является непосредственной реализацией этого метода. Как обычно, поскольку каждое выполнение функции завершается максимум одним рекурсивным вызовом, очевидна и нерекурсивная версия (см. упражнение 12.78).

Программа 12.14. Выборка с помощью BST-дерева

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

private:
  Item selectR(link h, int k)
  { if (h == 0) return nullItem;
    int t = (h->l == 0) ? 0: h->l->N;
    if (t > k) return selectR(h->l, k);
    if (t < k) return selectR(h->r, k-t-1);
    return h->item;
  }
public:
  Item select(int k)
  { return selectR(head, k); }
      

Реализация операции выбрать - основная алгоритмическая причина включения поля размера поддерева во все узлы BST-дерева. С помощью этого поля можно также обеспечить тривиальную " энергичную " реализацию операции подсчитать (возврат значения поля счетчика в корневом узле); в "Сбалансированные деревья" будет продемонстрировано еще одно применение. Недостатки присутствия поля счетчика заключаются в использовании дополнительной памяти для каждого узла и необходимости обновления поля каждой функцией, изменяющей дерево. Использование поля размера поддерева может не окупаться в некоторых приложениях, в которых основным операциями являются вставить и найти, но эта плата может оказаться незначительной, если в динамической таблице символов важна поддержка операции выбрать.

Эту реализацию операции выбрать можно преобразовать в операцию разбить (на части - partition), которая реорганизует дерево для помещения к-го наименьшего элемента в корень, используя точно такую же рекурсивную технику, которая использовалась для вставки в корень в разделе 12.8: если мы (рекурсивно) помещаем требуемый узел в корень одного из поддеревьев, его затем с помощью единственной ротации можно сделать корнем всего дерева. Программа 12.15 содержит реализацию этого метода. Подобно ротациям, разбиение не является операцией АТД, поскольку эта функция преобразует конкретное представление таблицы символов и должна быть прозрачной для клиентов. Скорее, это вспомогательная процедура, которую можно использовать для реализации операций АТД либо для повышения их эффективности. На рис. 12.17 приведен пример, показывающий, аналогично т рис. 12.14, что этот процесс эквивалентен спуску по пути от корня до требуемого узла дерева, а затем подъему обратно с выполнением ротаций для перемещения этого узла в корень.

Программа 12.15. Разбиение BST-дерева

Добавление ротаций после рекурсивных вызовов преобразует функцию выборки из программы 12.14 в функцию, которая помещает к-й наименьший узел BST-дерева в его корень.

void partR(link& h, int k)
  { int t = (h->l == 0) ? 0 : h->l->N;
    if (t > k)
      { partR(h->l, k); rotR(h); }
    if (t < k)
      { partR(h->r, k-t-1); rotL(h); }
  }
      
 Разбиение BST-дерева

Рис. 12.17. Разбиение BST-дерева

Здесь показан результат (внизу) разбиения BST-дерева (вверху) по медианному ключу; при этом выполняется (рекурсивно) ротация - точно так же, как и при вставке в корень.

Чтобы удалить из BST-дерева узел с заданным ключом, вначале необходимо проверить, находится ли он в одном из поддеревьев. Если да, мы заменяем это поддерево результатом (рекурсивного) удаления из него данного узла. Если удаляемый узел находится в корне, дерево заменяется результатом объединения двух поддеревьев в одно. Для выполнения такого объединения существует несколько возможностей. Один из возможных подходов проиллюстрирован на рис. 12.18, а реализация представлена в программе 12.16.

 Удаление корня в BST-дереве

Рис. 12.18. Удаление корня в BST-дереве

Здесь показан результат (внизу) удаления корня из BST-дерева (вверху). Вначале после удаления корневого узла остаются два поддерева (второй сверху рисунок). Затем мы разбиваем правое поддерево для помещения его наименьшего элемента в корень (третий сверху рисунок) - при этом левая ссылка указывает на пустое поддерево.

И, наконец, мы заменяем эту ссылку указателем на левое поддерево исходного дерева (внизу).

Бактыгуль Асаинова
Бактыгуль Асаинова

Здравствуйте прошла курсы на тему Алгоритмы С++. Но не пришел сертификат и не доступен.Где и как можно его скаачат?

Александра Боброва
Александра Боброва

Я прошла все лекции на 100%.

Но в https://www.intuit.ru/intuituser/study/diplomas ничего нет.

Что делать? Как получить сертификат?