Skip to content

Fix/splaytree delete last node - #366

Open
B7M wants to merge 359 commits into
RodrigoDLPontes:masterfrom
B7M:fix/splaytree-delete-last-node
Open

Fix/splaytree delete last node#366
B7M wants to merge 359 commits into
RodrigoDLPontes:masterfrom
B7M:fix/splaytree-delete-last-node

Conversation

@B7M

@B7M B7M commented Aug 27, 2026

Copy link
Copy Markdown

Fix crash when deleting the last remaining node in a Splay Tree

---------- PR DESCRIPTION BELOW THIS LINE ----------

Problem

In SplayTree.treeDelete, the root is replaced by its left child and then written to right away:

this.treeRoot = this.treeRoot.left;
this.treeRoot.parent = null;

When there is only one node in the tree, that node has no left child and no right child. The code takes this branch because the right child is null, so this.treeRoot becomes null too. The next line then tries to set parent on null and throws:

TypeError: Cannot set properties of null (setting 'parent')

The error also stops the animation commands for that delete from running, and one of those commands is the one that erases the node's circle. So the node the user just deleted is still drawn on the screen, even though the tree is now empty. The two stay out of sync until you press Clear.

This is not only the one-node case. Any sequence that empties the tree hits it, because the last delete always happens when a single node is left.

Fix

I checked for null before setting parent:

 this.treeRoot = this.treeRoot.left;
-this.treeRoot.parent = null;
+if (this.treeRoot != null) {
+	this.treeRoot.parent = null;
+}
 this.resizeTree();

The tree is allowed to be empty here, so a null root is a normal result and not an error. resizeTree() already checks for a null root, so nothing else needed to change.

I did not change the other branch (left == null). That one only runs when there is a right child, so its new root can never be null.

Testing

I tested the change in the browser and looked at what was actually drawn on the canvas at the end. nodes below is what stays on the screen.

Steps Before After
insert 5, delete 5 error, nodes=[5] no error, nodes=[]
insert 5, delete 5, insert 7 error, nodes=[5,7] no error, nodes=[7]
insert 5, delete 5, insert 7, delete 7 2 errors, nodes=[5,7] no error, nodes=[]
insert 5,3, delete 3, delete 5 error, nodes=[5] no error, nodes=[]
insert 5,3,8, delete 3,5,8 error, nodes=[8] no error, nodes=[]
insert 5, delete 5, insert 5,2,9 error, nodes=[5,5,2,9] no error, nodes=[5,2,9]

The last row shows the leftover node most clearly: the old 5 is still there, so the canvas draws 5 twice.

I also checked the cases that were already working, to make sure the fix did not change them. These behave the same before and after:

Steps Result
insert 5,3, delete 5 (root with one child) nodes=[3], no error
insert 5,3,8, delete 5 (root with two children) nodes=[3,8], no error
insert 5, delete 9 (value not in the tree) nodes=[5], no error
delete 9 from an empty tree nodes=[], no error

To see the bug you have to delete the tree down to empty by hand, which is probably why it went unnoticed — the Random button only inserts, it never deletes.

Checks

  • npm run lint passed
  • Prettier check passed for the changed file
  • Only src/algo/SplayTree.js was changed (3 lines added, 1 removed)

kathy-tran07 and others added 29 commits November 24, 2025 14:41
Fix indentation for StackArray.push()
…wording

Fix wording for quickSelect pseudo
treeDelete reassigns treeRoot to its left child and then writes
treeRoot.parent unconditionally. With one node in the tree both children
are null, so treeRoot becomes null and the write throws. The throw
escapes before startNewAnimation, dropping the queued act.delete, so the
deleted node stays drawn on the canvas.

Guard the parent write; resizeTree already handles a null root.
@vercel

vercel Bot commented Aug 27, 2026

Copy link
Copy Markdown

@B7M is attempting to deploy a commit to the rodrigodlpontes' projects Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.