Я пытаюсь сделать LeftRotation
с помощью своего AVLTree. Я вложу 3, 5, а затем 10, чтобы он стал вырожденным деревом. Когда я пройдусь, это даст мне 3, 5, 10
но когда я сделаю поворот, я получаю 5, 10
вместо ожидаемых 5, 3, 10
.
Это что - то делать с установкой a
качестве b
left
ветки. Я пройду через него, а корень моего дерева будет равен 5
, слева будет 3
, а справа будет 10
, но когда я иду, чтобы пройти, он показывает, что левая сторона равна null
.
Вот мой код вращения:
void AVLTree::RotateLeft(Node *root)
{
Node a = *root;
Node b = *root->GetRight();
*root = b;
a.SetRight(b.GetLeft());
b.SetLeft(&a); //This is where the problem occurs
}
И мой код Traversal
:
void AVLTree::Traverse(Node *node)
{
cout << node->GetValue() << ", ";
if (node->GetLeft() != nullptr)
Traverse(node->GetLeft());
if (node->GetRight() != nullptr)
Traverse(node->GetRight());
}
Заранее спасибо!
Изменение: изменил все 0
на nullptr
, спасибо за исправление!
Существует проблема с перемещением root
чтобы указать на новое местоположение. Если есть сомнения в этом, рассмотрите следующие два утверждения. Обратите внимание, что соглашение об именовании переменных из исходного кода выше используется для согласованности.
*root = b; // (1)
root = &b; // (2)
В (1)
содержимое корневого указателя модифицируется так, чтобы содержать значение, сохраненное в переменной b
. Адрес root
не был каким-либо образом изменен. root
адреса перед выполнением (1)
остается неизменным после завершения (1)
.
В (2)
root
теперь указывает на адрес переменной b
. Поскольку адрес, в котором указывается root
, был изменен, содержимое root
указателя теперь равно значению в переменной b
.
Я настоятельно рекомендую по void AVLTree::RotateLeft(Node *root)
через void AVLTree::RotateLeft(Node *root)
и проверять адреса и содержимое всех переменных, чтобы увидеть это из первых рук. Я выполнил симуляцию вышеупомянутых действий над образцами целочисленных данных, и указатели перемещались, как ожидалось, используя (2)
.
До того, как произойдет ротация данных образца, ожидается, что небалансное дерево должно быть организовано таким образом, чтобы на 3
узлах был указан root
. Затем root->right
указывает на 5
, а root->right->right
указывает на 10
. root->right->left
должен быть nullptr
, а root->left
также должен быть nullptr
.
Если это не так, то либо алгоритм вставки AVL реализуется неправильно, либо требования к дизайну отличаются от ожидаемого (например, дерево AVL в Википедии, структуры данных и анализ алгоритмов в C++ (3-е издание) [в твердом переплете] Марк Аллен Вайс, Учебник по дереву AVL по вечно смущенным Жюльеном Уокером).
Что касается перемещения балансировки дерева, где конечный результат равен root
5
, то root->left
указывает на 3
и root->right
указывает на 10
, правый указатель переданного в root
указателе будет установлен на укажите левый указатель локального указателя pB
(см. ниже), левый указатель pB
будет указывать на переданный в root
указатель, а root
будет установлен на локальную переменную pB
(изначально установленную в root->right
указатель в этом случае).
Используя вышеприведенные данные, тело функции изменяется. Обратите внимание, что это не согласуется с тем, как GetRight()
и GetLeft()
возвращают копию узла в исходном сообщении выше. Модифицированный орган функции ниже согласуется с single AVL rotation with right child
реализованным Mark Allen Weiss, упомянутым выше. Поскольку исходное сообщение не имеет переменной высоты, код ниже также не является.
//
// The 'root' variable is passed as a pointer by reference
//
void AVLTree::RotateLeft(Node* & root)
{
//
// This works as long as the GetRight() method returns a pointer, not a Node copy
//
Node *pB = root->GetRight();
//
// In the example values for three nodes, the root->right will become nullptr
//
root->SetRight(pB->GetLeft());
//
// In the example values, the pB->left will point to the node with value of 3
//
pB->SetLeft(root);
//
// Move root to point to where pB does (root->right)
//
root = pB;
}
nullptr
. Для более подробной информации: что такое nullptr? , Если нет, то лучше использовать макросNULL
. Весьма вероятно, что сравнение указателей с нулем будет стоить очков.b.SetLeft(a)
, а не&a
.SetLeft
принимаетNode
, а неNode*
. Если возможно, вам также следует заменить всеNode*
наNode&
в вашей программе, потому что вы используете указатели, как если бы они были ссылками ...