Regarding splay trees - algorithm

I am reading about splay trees in Data structures and algorithms by Mark Allen Wesis
The splaying strategy is similar to the rotation idea, except that we
are a little more selective about how rotations are performed. We will
still rotate bottom up along the access path. Let x be a (nonroot)
node on the access path at which we are rotating. If the parent of x
is the root of the tree, we merely rotate x and the root. This is the
last rotation along the access path. Otherwise, x has both a parent
(p) and a grandparent (g), and there are two cases, plus symmetries,
to consider. The first case is the zig-zag case, Here x is a right
child and p is a left child (or vice versa). If this is the case, we
perform a double rotation, exactly like an AVL double rotation.
Otherwise, we have a zig-zig case: x and p are either both left
children or both right children.
In above text what does author mean by following statement "There are two cases plus symmetries"? two cases are given but what are symmetires here?
Thanks!

I think it's just pretty basic axial symetry:
example for a zig zag case, here are 2 symetric trees:
g
/ \
p d
/\
c x
/ \
a b
g
/ \
d p
/\
x c
/ \
a b

For example, say a case is "When the node in questions is the right child of its parent and the parent is the left child of the grandparent" In this case you do a left rotation and then a right rotation. So the node will come up to the grand parent.
The symmetric part of this case is "When the node in questions is the left child of its parent and the parent is the right child of the grandparent" In this case you do a right rotation and then a left rotation. So the node will come up to the grand parent.
replace left with right and right with left you get the symmetric case.
There are only 3 cases for rotation in a splay tree. Listed it here
You can see the runtime difference in searching with and without splaying.

Related

Is this red-black tree insertion "fix-up" algorithm incomplete?

I'm reading Introduction to Algorithms, 3rd Edition (ISBN-10: 9780262033848) and in it is the following algorithm to "fix" a red-black tree after the insertion of a red node.
On line 3 it says to set y = to 'z's parent's parent's right child' (z's right uncle). My question is, what if z is only the third insertion and it is a left child of a left child? Wouldn't there need to be another case that handles z not having a right uncle but its parent being a red left child?
gp (blck)
/
p (red)
/
z (red)
The third case has already been taken care of by the lines 12-14.
Have a look at following image which explains your case:
Feel free to ask any doubts

Splay trees: how do the zig-zig and zig-zag rotations work, in details?

I need help understanding a specific example of zig-zag and zig-zig rotations in splay trees. I have read about them in a book, and on Wikipedia as well as a few other online resources, and whilst I can understand them when they are applied on simple trees (i.e. trees with very few nodes), I get lost when I see examples of them applied to bigger trees (i.e. trees with more nodes).
In particular, I don't understand at least one of these 2 examples:
Example 1
(this is not the full example but this is the part of it I don't understand)
We can see in (1) that the node which is about to be splayed is the right child of a left child and therefore we have to do a zig-zag. I can therefore understand what happens between (1) and (2), where the node being splayed has now taken the place of its parent. In my understanding, the entire zig-zag operation has taken place there. So the first splay is over, and we still need to splay the node until it is at the root of the tree.
I don't understand what happens between (2) and (3). In (2), the node being splayed is the left child of a left-child, so I expected a zig-zig operation whereby the node being splayed rotates around its grandparent, which is (20, Z). Instead, the slide shows a rotation with its parent, (10, A). Why? What I would have expected there is that our splaying node (8, N) does a zig-zig and thereby takes the places of (20, N) which is its grandparent, and also the root. Why is the parent involved instead?
In the resource where I found this example (my lecturer's slides), a zig-zag rotation is described as "rotate node with its parents, then rotate node with its grand-parent". Is that what happens here? Is that the reason why between (2) and (3), (8, N) rotates with (10, A) instead of (20, Z)?
I am very confused about this description, because then the zig-zig rotation is described as "rotate node with its grand-parent, then rotate node with its parent". However, everytime I have seen an example of zig-zig rotation, there is always only one rotation with the grand-parent of the node and that's it. I have never seen 2 rotations.
Then there is this other example:
In that example, the splay operation involves a zig-zig. As you can see, there is only 1 rotation. Then there is a second splay because the node being accessed is still not in a root position.
What I would have expected here is that:
Either the description of zig-zig and zig-zag provided are correct, and therefore there would have been 2 rotations in the second example: one around the grandparent of the node, then one around its parent.
Or, the description provided are wrong, so then the second example is correct, but the first is not as we rotated the node with its parent and not its grandparent whilst it was in a zig-zig position.
Can you let me know if any of these 2 examples is wrong, and which one? If none of them is wrong, where am I wrong?
Thank you for your help.
PS: As it is obvious that I am a student, I would just like to let you know that I do not ask this question in the context of an assignment, and therefore I am not cheating. I have, however, an exam this coming Monday and I hope to have any misunderstanding clarified before I sit the exam.
Splaying of a node x is sequence of splay steps until x becomes root of the tree. These steps are zig, zag and zig-zag.
For a node x, its parent p and p's parent g, zig-zag operation on node x is defined for a case where p is not the root and x is the right child of p and p is the left child of g: first rotate left x, then rotate right x. Your first example shows exactly that case: zig rotates left x = (8, X) and its parent p = (7, T), then zag rotates right (8, X) and g = (10, A). So, this example shows zig-zag on x, but the splaying itself is not done because x is not root yet (meaning more splaying steps is necessary).
zig-zig is defined for the case when both x and p are right children of their respective parents: first rotate left p, then rotate left x. The second picture of your second example shows the result of zig-zig on x = (40, X), p = (37, P), g = (35, R): first p is rotated left, then x is rotated left. Third picture of the second example shows additional zig operation on x (rotating left x since its parent p is the root) moving to the root and finishing splaying of x.
(All zig, zig-zig and zig-zag operations have their symmetrical counterparts).

About orientation in splay trees in Robert Sedgweick

I am reading about splay trees by Robert Sedgwick. Following is text snippet from section
In the root-insertion method, we accomplished our primary objective of bringing the newly inserted node to the root of the tree by using left and right rotations. In this section, we examine how we can modify root insertion such that the rotations balance the tree in a certain sense, as well.
Rather than considering (recursively) the single rotation that brings the newly inserted node to the top of the tree, we consider the two rotations that bring the node from a position as one of the grandchildren of the root up to the top of the tree. First, we perform one rotation to bring the node to be a child of the root. Then, we perform another rotation to bring it to the root. There are two essentially different cases, depending on whether or not the two links from the root to the node being inserted are oriented in the same way. . Splay BSTs are based on the observation that there is an alternative way to proceed when the links from the root to the node being inserted are oriented in the same way: Simply perform two rotations at the root.
Additional information is present at slide 4 at following link
http://www.cs.princeton.edu/courses/archive/spr04/cos226/lectures/balanced.4up.pdf
My question is
What does author mean by orientation here?
Request to given an example for orienations differ and orientation match.
Thanks
Orientation simply means left or right child.
A
/ \
B C
/ \
D E
E is an example of the same orientation case - C is the right child of A and E is again the right child of C. D is an example of differing orientations because D is the left child of C but C is the right child of A.
So you can describe the orientation of all the nodes with respect to the root node A as follows.
B left
C right
D right left
E right right
Suppose you are accessing node n, whose parent is p, and whose grandparent is g. Then the orientation is the same if both n and p are the left or right child of its parent.
So, for example, if p is the right child of g and n is the left child of p, the orientation is not the same. If p is the right child of g and n is the right child of p, the orientation is the same.

Regarding AVL rotations

I am reading about AVL trees in Data structures and algorithms by Mark Allen Wesis
Suppose the node to be rebalanced is X. There are 4 cases that we
might have to fix (two are the mirror images of the other two): An
insertion in the left subtree of the left child of X, An insertion in
the right subtree of the left child of X, An insertion in the left
subtree of the right child of X, or An insertion in the right subtree
of the right child of X.
Balance is restored by tree rotations.
Following are questions i have on above text snippet.
What does author mean by mirror images of other two?
What is symmetric case in single rotation and double rotation?
Thanks
Suppose the node being inserted is I. The book says there are 4 cases. Let's take the one where I is the left child of the left child of X:
X
/ \
? ?
/ \ / \
I ? ? ?
The "mirror" of this is when I is the right child of the right child of X:
X
/ \
? ?
/ \ / \
? ? ? I
The reason this is a "mirror" is that the rotations you have to do for both cases are the same, just with left and right reversed. The same goes for the other two cases where I is the left child of the right child of X and where I is the right child of the left child of X.
As for your second question, the idea is the same. In the symmetric case, (ie the mirror case), you do the same rotations, just with left and right reversed.

Delete in Binary Search tree?

I am reading through the binary tree delete node algorithm used in the book Data Structures and Algorithms: Annotated Reference with Examples
on page 34 , case 4(Delete node which has both right and left sub trees), following algorithm described in the book looks doesn't work, probably I may be wrong could someone help me what I am missing.
//Case 4
get largestValue from nodeToRemove.Left
FindParent(largestValue).Right <- 0
nodeToRemove.Value<-largestValue.Value
How does the following line deletes the largest value from sub tree FindParent(largestValue).Right <- 0
When deleting a node with two children, you can either choose its in-order successor node or its in-order predecessor node. In this case it's finding the the largest value in the left sub-tree (meaning the right-most child of its left sub-tree), which means that it is finding the node's in-order predecessor node.
Once you find the replacement node, you don't actually delete the node to be deleted. Instead you take the value from the successor node and store that value in the node you want to delete. Then, you delete the successor node. In doing so you preserve the binary search-tree property since you can be sure that the node you selected will have a value that is lower than the values of all the children in the original node's left sub-tree, and greater that than the values of all the children in the original node's right sub-tree.
EDIT
After reading your question a little more, I think I have found the problem.
Typically what you have in addition to the delete function is a replace function that replaces the node in question. I think you need to change this line of code:
FindParent(largestValue).Right <- 0
to:
FindParent(largestValue).Right <- largestValue.Left
If the largestValue node doesn't have a left child, you simply get null or 0. If it does have a left child, that child becomes a replacement for the largestValue node. So you're right; the code doesn't take into account the scenario that the largestValue node might have a left child.
Another EDIT
Since you've only posted a snippet, I'm not sure what the context of the code is. But the snippet as posted does seem to have the problem you suggest (replacing the wrong node). Usually, there are three cases, but I notice that the comment in your snippet says //Case 4 (so maybe there is some other context).
Earlier, I alluded to the fact that delete usually comes with a replace. So if you find the largestValue node, you delete it according to the two simple cases (node with no children, and node with one child). So if you're looking at pseudo-code to delete a node with two children, this is what you'll do:
get largestValue from nodeToRemove.Left
nodeToRemove.Value <- largestValue.Value
//now replace largestValue with largestValue.Left
if largestValue = largestValue.Parent.Left then
largestValue.Parent.Left <- largestValue.Left //is largestValue a left child?
else //largestValue must be a right child
largestValue.Parent.Right <- largestValue.Left
if largestValue.Left is not null then
largestValue.Left.Parent <- largestValue.Parent
I find it strange that a Data Structures And Algorithms book would leave out this part, so I am inclined to think that the book has further split up the deletion into a few more cases (since there are three standard cases) to make it easier to understand.
To prove that the above code works, consider the following tree:
8
/ \
7 9
Let's say that you want to delete 8. You try to find largestValue from nodeToRemove.Left. This gives you 7 since the left sub-tree only has one child.
Then you do:
nodeToRemove.Value <- largestValue.Value
Which means:
8.value <- 7.Value
or
8.Value <- 7
So now your tree looks like this:
7
/ \
7 9
You need to get rid of the replacement node and so you're going to replace largestValue with largestValue.Left (which is null). So first you find out what kind of child 7 is:
if largestValue = largestValue.Parent.Left then
Which means:
if 7 = 7.Parent.Left then
or:
if 7 = 8.Left then
Since 7 is 8's left child, need to replace 8.Left with 7.Right (largestValue.Parent.Left <- largestValue.Left). Since 7 has no children, 7.Left is null. So largestValue.Parent.Left gets assigned to null (which effectively removes its left child). So this means that you end up with the following tree:
7
\
9
The idea is to simply take the value from the largest node on the left hand side and move it to the node that is being deleted, i.e., don't delete the node at all, just replace it's contents. Then you prune out the node with the value you moved into the "deleted" node. This maintains the tree ordering with every node's value larger than all of it's left children and smaller than all of it's right children.
I think you may need to clarify what doesn't work.
I will try and explain the concept of deletion in a binary tree in case this helps.
Lets assume that you have a node in the tree that has two child nodes that you wish to delete.
in the tree below lets say that you want to delete node b
a
/ \
b c
/ \ / \
d e f g
When we delete a node we need to reattach its dependant nodes.
ie. When we delete b we need to reattach nodes d and e.
We know that the left nodes are less than the right nodes in value and that the parent nodes are between the left and right node s in value. In this case d < b and b < e. This is part of the definition of a binary tree.
What is slightly less obvious is that e < a. So this means that we can replace b with e. Now we have reattached e we need to reattach d.
As stated before d < e so we can attach e as the left node of e.
The deletion is now complete.
( btw The process of moving a node up the tree and rearranging the dependant nodes in this fashion is known as promoting a node. You can also promote a node without deleting other nodes.)
a
/ \
d c
\ / \
e f g
Note that there is another perfectly legitimate outcome of deleteing node b.
If we chose to promote node d instead of node e the tree would look like this.
a
/ \
e c
/ / \
d f g
If I understand the pseudo-code, it works in the general case, but fails in the "one node in the left subtree" case. Nice catch.
It effectively replaces the node_to_remove with largest_value from it's left subtree (also nulls the old largest_value node).
Note that in a BST, the left subtree of node_to_remove will be all be smaller than node_to_remove. The right subtree of node_to_remove will all be larger than node_to_remove. So if you take the largest node in the left subtree, it will preserve the invariant.
If this is a "one node in the subtree case", it'll destroy the right subtree instead. Lame :(
As Vivin points out, it also fails to reattach left children of largestNode.
It may make more sense when you look at the Wikipedia's take on that part of the algorithm:
Deleting a node with two children:
Call the node to be deleted "N". Do
not delete N. Instead, choose either
its in-order successor node or its
in-order predecessor node, "R".
Replace the value of N with the value
of R, then delete R. (Note: R itself
has up to one child.)
Note that the given algorithm chooses the in-order predecessor node.
Edit: what appears to be missing the possibility that R (to use Wikipedia's terminology) has one child. A recursive delete might work better.

Resources