edit: последний абзац для ответа, спасибо Sticky.
tl; dr: перейти к последнему абзацу
Это та же проблема, с которой у меня проблемы. (Да и DS). Пока все прогоны, кроме 5, верны. Я протестировал несколько вещей, одна из которых очень проста: просто поменяйте местами в OSRank слева и справа. В некоторых случаях он давал правильный ответ, но в более сложных случаях это было немного не так. О, я также добавил, что если y.score == y.parent.score, я добавляю только правильный размер y.parent, если нет, я добавляю правильный размер + 1.
public int OSRank(Node x)
{
int r = x.Right.Size + 1;
Node y = x;
while (y != root)
{
if (y == y.Parent.Left)
{
if (y.Score == y.Parent.Score)
r = r + y.Parent.Right.Size;
else
r = r + y.Parent.Right.Size + 1;
}
y = y.Parent;
}
return r;
}
Давайте сначала протестируем этот метод на дереве на странице 340 (рисунок 14.1). Мы будем искать ранг 38 (который должен вернуть 4, потому что 39, 47 и 41 выше):
- r = 1 + 1 = 2 // Правая сторона + 1
- r = 2 // ничего не происходит, потому что мы правильный ребенок
- r = r + 1 + 1 = 4 // мы левый потомок, ключ нашего родителя больше и parent.Right.size = 1
- r = 4 // ничего не происходит, потому что мы правильный ребенок
Так что в этом случае результат правильный. Но что, если мы добавим к нашему дереву еще один узел с ключом 38. Это немного меняет форму нашего дерева, правая часть узла 26 теперь выглядит так:
(Мне пока не разрешено добавлять изображения, посмотрите здесь: http: //i47.tinypic.com/358ynhh.png)
Если бы мы использовали тот же алгоритм, то получили бы следующий результат (выбрав красный):
- r = 0 + 1 = 1 // нет правой стороны
- r = 1 // мы правильный ребенок
- r = 1 // мы правильный ребенок
- r = 1 + 3 + 1 = 5 // 3 происходит от размера узла 41.
- r = 5 // мы правильный ребенок
Хотя мы ожидаем здесь 4-го ранга. Пока я печатал это, я заметил, что мы проверяем y.Score == y.Parent.Score, но я совершенно забыл, что y меняется. Итак, в строке 4 предложение «y.Score == y.Parent.Score» было ложным, потому что мы сравнили узел 30 с 38. Итак, если мы изменим эту строку на:
if (x.Score == y.Parent.Score)
Алгоритм выводит ранг 4, что верно. Значит, мы устранили еще одну проблему. Но есть еще кое-что, о чем я тоже не догадался:
- Случай, когда Y.Parent.Right содержит повторяющиеся ключи. Технически, если у нас есть 3 узла с одним и тем же ключом, они должны считаться 1.
- Случай, когда Y.Parent.Right содержит ключи, которые равны x.Key (узел, ранг которого вы хотите присвоить). Это неправильно вернуло бы нас на несколько рангов.
Я полагаю, вы могли бы сохранить другое целое число, которое содержит количество узлов с более высокой оценкой. После вставки вы можете подняться по дереву и скорректировать значения, если поддерево этого узла не содержит узла с такой же оценкой. Но как это делается (и эффективно) мне сейчас неизвестно.
изменить: сначала найдите последнего преемника x с той же оценкой x. Затем вычислите ранг обычным способом. Код выше работает.
person
Kevin A
schedule
28.06.2012