Сложность обхода порядка в двоичном дереве поиска (с использованием итераторов)?

115
4

Связанный вопрос: Сложность времени трассировки дерева InOrder двоичного дерева O (N)?, однако он основан на обходе через рекурсию (поэтому в O (log N), в то время как итераторы допускают потребление только O (1) пространства.


В С++ обычно требуется требование, чтобы приращение итератора стандартного контейнера выполнялось как операция O (1). В большинстве контейнеров тривиально доказано, однако с map и т.д., Это кажется немного сложнее.


    Если a map были реализованы как список пропусков, тогда результат будет очевиден.
    Однако они часто реализуются как красно-черные деревья (или, по крайней мере, как двоичные деревья поиска)

Итак, во время обхода в порядке есть моменты, когда "следующее" значение не так легко достигается. Например, если вы указываете на нижний правый лист левого поддерева, тогда следующий node для перемещения - это корень, который находится в depth.


Я попробовал "доказать", что алгоритмическая сложность (в терминах "шагов" ) была амортизирована O (1), что кажется в порядке. Однако пока у меня еще нет демонстрации.


Вот небольшая диаграмма, которую я прослеживал для дерева с глубиной 4, числа (вместо узлов) представляют собой количество шагов, которые нужно пройти от этого node к следующему в течение порядка обход:


       3
2 2
1 1 1 1
1 2 1 3 1 2 1 4

Примечание: самый правый лист имеет стоимость 4, если это будет поддерево большего дерева.


Сумма составляет 28, для общего числа узлов 15: таким образом, стоимость в среднем менее 2 на node, которая (если она будет удерживаться) будет хорошей амортизированной стоимостью. Итак:


    Во время обхода в порядке, увеличивает итератор действительно O (1) для сбалансированного (и полного) дерева двоичного поиска?
    Можно ли расширить результат, чтобы покрыть неполные двоичные деревья поиска?

спросил(а) 2020-03-25T14:49:35+03:00 2 месяца назад
1
Решение
116

Да, амортизированная стоимость действительно O(1) за итерацию для любого дерева.


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

Листья посещаются только один раз.
Ни одного листа не посещают не более трех раз:


    при переходе от родителя к самому node.
    при возврате из левого поддерева
    при возврате из правого поддерева

Больше нет посещений для узлов, поэтому, если мы суммируем количество посещений каждого node, мы получим число меньше, чем 3n, поэтому общее количество посещений всех объединенных узлов O(n), что дает нам O(1) на шаг амортизируется.


(Обратите внимание, что в полном дереве есть n/2 листа, мы получаем 2n, с которым вы сталкивались, я считаю, что можно показать, что сумма посещений будет меньше, чем 2n для любого дерева, но эта "оптимизация" находится вне области действия IMO).

В худшем случае на шаге O(h), который является O(logn) в сбалансированном дереве, но может быть O(n) в некоторых случаях.


P.S. Я понятия не имею, как деревья Red-Black реализованы на С++, но если ваша структура данных дерева содержит поле parent из каждого node, она может заменить рекурсивный стек и разрешить использование пространства O(1). (Это, конечно, "обман", потому что хранение n таких полей само O(n)).

ответил(а) 2020-03-25T15:05:14.344111+03:00 2 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема