LL Rotation, lose the newParent previous right node; RR Rotation too.
beblueblue opened this issue · comments
If the newParent.left previous is exist, we will lose it;
function leftRotation(node) {
const newParent = node.right; // E.g., node 3
const grandparent = node.parent; // E.g., node 1
// swap node 1 left child from 2 to 3.
swapParentChild(node, newParent, grandparent);
// Update node 3 left child to be 2, and
// updates node 2 parent to be node 3 (instead of 1).
newParent.setLeftAndUpdateParent(node);
// remove node 2 left child (previouly was node 3)
node.setRightAndUpdateParent(null);
return newParent;
}
function setLeftAndUpdateParent(node) {
this.left = node;
if (node) {
node.parent = this;
node.parentSide = LEFT;
}
}
If we do this: newParent.setLeftAndUpdateParent(node); in leftRotation, and
this.left = node; in setLeftAndUpdateParent,
we will lose the left of newParent.
I think the above should write as follow.
function leftRotation(node) {
const newParent = node.right; // E.g., node 3
const grandparent = node.parent; // E.g., node 1
const previousLeft = newParent.left;
// swap node 1 left child from 2 to 3.
swapParentChild(node, newParent, grandparent);
// Update node 3 left child to be 2, and
// updates node 2 parent to be node 3 (instead of 1).
newParent.setLeftAndUpdateParent(node);
// remove node 2 left child (previouly was node 3)
node.setRightAndUpdateParent(previousLeft);
return newParent;
}
Add this: const previousLeft = newParent.left; and node.setRightAndUpdateParent(previousLeft);
right? Maybe I am wrong.
Thanks for commenting @beblueblue! You are right about losing the left node in the case of a LL rotation. However, the use case for rotations is to balance a tree:
E.g.
1 1
\ \
2* 3
\ --left-rotation(2)-> / \
3 2* 4
\
4
If you have a tree with a left node (as you mentioned) it means that is balanced and it doesn't need to have a rotation.
1*
\
2
/ \
3 4
Do you have a use case where it needed to do a LL rotation on an already balanced tree?
Thanks for commenting @beblueblue! You are right about losing the left node in the case of a LL rotation. However, the use case for rotations is to balance a tree:
E.g.
1 1 \ \ 2* 3 \ --left-rotation(2)-> / \ 3 2* 4 \ 4
If you have a tree with a left node (as you mentioned) it means that is balanced and it doesn't need to have a rotation.
1* \ 2 / \ 3 4
Do you have a use case where it needed to do a LL rotation on an already balanced tree?
Thank you for your prompt reply.
Now, Let's make a preset, we have a tree.
16* 16*
/ \ --- add two node(8, 2)--> / \
4 32 4 32
/ \
2 8
The tree is still balanced. The next step, we add the node 1.
16* 16*
/ \ / \
4 32 --- add the node (1) --> 4 32
/ \ / \
2 8 2 8
/
1
In this case that Node16.balanceFactor is 2, should we make the RR rotation for the root(16)?
If we have to do it, we use the function.
rightRotation(16)
function rightRotation(node) {
const newParent = node.left; // E.g., node 4
const grandparent = node.parent; // E.g., undefiend
swapParentChild(node, newParent, grandparent);
newParent.setRightAndUpdateParent(node);
// we will lose the node 8!
node.setLeftAndUpdateParent(null);
return newParent;
}
Now, our tree became the one below.
4 4
/ \ / \
2 16 --- the correct tree --> 2 16
/ \ / / \
1 32 1 8 32
rightRotation(16); -- to get right tree;
function rightRotation(node) {
const newParent = node.left; // E.g., node 4
const grandparent = node.parent; // E.g., undefiend
const previousRight = newParent.right || null;
swapParentChild(node, newParent, grandparent);
newParent.setRightAndUpdateParent(node);
// we should make the node-8 to be the left of the node-16
node.setLeftAndUpdateParent(previousRight);
return newParent;
}
Last and foremost, I learn a lot form your article. Thank you!
Thank you so much @beblueblue for taking the time and providing an example. I made the fixes and added some tests. Let me know if you find anything else.