void unbalance(Node **pp) {
Node *p;
while ((p = *pp)) {
if (!p->left) {
pp = &p->right;
} else {
Node *tmp = p->left->right;
*pp = p->left;
p->left->right = p;
p->left = tmp;
}
}
}
...
Node *tree = ...;
unbalance(&tree);
Этот код основан на ответе @ templatetypedef. Он использует указатель на указатель, чтобы избежать сиротских узлов (который также избавляется от finalRoot
, единственной целью которого является избегать сирот первоначального корня, переданного вызывающим).
Идея состоит в том, чтобы спуститься по дереву вдоль самой правой ветви. Если никогда не осталось детей, мы вводим только первую часть инструкции if
и выходим, ничего не делая.
Часть else
используется, когда имеется левое поддерево. В этом случае мы поворачиваем дерево справа.
Это приводит к вытягиванию одного узла из левого поддерева, то есть наше левое поддерево теперь на один узел меньше. Мы повторяем это до тех пор, пока левое поддерево полностью не исчезнет, и в этот момент мы снова войдем в первую часть if
. Затем мы переходим к остальной правой поддереве и повторяем все это.
Указатели на указатели часто полезны при изменении структуры связанного списка или дерева. Они позволяли нам работать непосредственно с оригинальными указателями, а не копировать их. В этом случае назначение *pp = ...
изменяет указатель в другом месте (на который указывает pp
). Это либо исходный корень (как передается вызывающим), либо один из указателей right
внутри дерева (как установлено pp = &p->right
). Это повторное назначение необходимо, потому что вращение дерева в ветке else
перемещает узлы вокруг, поэтому то, что раньше было корнем поддерева, перемещается дальше вниз, а прежний левый узел подтягивается, чтобы стать новым корнем. Мы обновляем *pp
, чтобы сохранить инвариант, указатель выше (либо переменная tree
в нашем вызывающем абоненте, либо член right
нашего родительского узла) указывает на (новый) корень поддерева.
Если вы получили это задание в классе, я бы ожидал, что ваш преподаватель заранее предоставил достаточный материал, необходимый для выполнения этого задания; поэтому ваша собеседница, которой ваши вопросы должны быть продвинуты, будет вашим инструктором. –
Это не присвоение класса @SamVarshavchik, я занимаюсь – C2K
благодаря @melpomene, сделав это редактирование в вопросе – C2K