-
Notifications
You must be signed in to change notification settings - Fork 80
Recursively delete unused nodes after Remove #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recursively delete unused nodes after Remove #36
Conversation
| t.root = t.put(t.root, key, val, 0) | ||
| } | ||
|
|
||
| func (t *Trie[V]) put(x *node[V], key string, val V, d int) *node[V] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved put up to sit underneath Put rather than under Remove. The only functional change to this method is the removal of the valid boolean parameter.
|
I've switched this back to draft, as I've realized that some unnecessary keys can remain in the cases where a node should be replaced by either its left or right child. Bear with me. |
Extends deletion code to delete all nodes without values or middle children, rather than deleting only nodes whose children are all nil.
|
This is ready to review again. |
| x.valid = valid | ||
| var v V | ||
| x.val = v | ||
| x.valid = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible for this case to happen? It seems like this still uses some tombstones if so (shouldn't we be aiming to completely remove valid?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
valid is required to distinguish between keys that have V's zero-value as their val and non-keys. We can't simply check for the presence of a value, because, for example, in a trie of ints, 0 may be either a genuine value or the zero-value of a non-key node.
To demonstrate how this case can happen, imagine a trie containing the keys "she" and "shell". When we delete "she", we must keep all the nodes, since they're still used by "shell". In this case we simply mark the "e" node as invalid (i.e. a non-key).
If the trie contained only "she", we mark the "e" node as invalid, then check whether the node has a middle child on line 174. If not, we know the node is no longer part of any active key and is safe to delete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, sorry it’s been a while since I’ve looked at this code haha.
This PR addresses #35.
It replaces the existing tombstone method of key removal with recursive deletion of unused nodes, ensuring that logarithmic time complexity for search misses is maintained even as many keys are deleted.
Additionally, it removes the
validboolean parameter from(*Trie[V]).put, which is no longer required.