amejiarosario / dsa.js-data-structures-algorithms-javascript

🥞Data Structures and Algorithms explained and implemented in JavaScript + eBook

Home Page:https://books.adrianmejia.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.