Skip to content

Commit 1bbec44

Browse files
committed
18 March
1 parent 24ec910 commit 1bbec44

File tree

2 files changed

+116
-93
lines changed

2 files changed

+116
-93
lines changed

src/algorithms/explanations/AVLExp.md

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,104 @@
11
# AVL Trees
22

3+
4+
35
An AVL tree is **self-balancing** **binary search tree**.
46

57
Unlike the basic binary search tree, which can exhibit *O(n)* worst case behavior for certain inputs, the AVL tree is always balanced, so search will be *O(log n)*
68
regardless of the order of the input data.
79

810
### The Binary Search Tree Invariant
911

10-
A **binary tree (BST)** is either is either empty (`Empty`) or else it
12+
A **binary tree (BST)** is either is either empty (Empty) or else it
1113
it has a root node and two subtrees (which are binary trees, and can also be empty).
12-
The root node `t` has a key `t.key`. Ordinarily every node would also
13-
hold other data (`t.data`), which the user would like to find by
14-
searching for the key, `e.g.` search for Student ID Number (key) to find street address (data).
15-
16-
Since the `data` attribute has no impact on
14+
The root node t has a key t.key. Ordinarily every node would also
15+
hold other data (t.data), which the user would like to find by
16+
searching for the key, *e.g.* search for Student ID Number (key) to find street address (data). Since the
17+
data attribute has no impact on
1718
how insertion and search take place, we disregard it in this animation.
18-
1919

20-
Note that a newly inserted node will always appear as a leaf
20+
21+
Note that a newly inserted node
22+
will always appear as a leaf
2123
in the tree.
24+
2225
23-
In a binary search tree the **BST invariant** is always maintained:\
26+
In any binary search tree, the **BST invariant** is always maintained; that is,
2427
for each
25-
subtree `t`, with root key `t.key`, the left subtree, `t.left`,
26-
contains no node with key greater than `t.key`, and the right subtree,
27-
`t.right`, contains no node with key smaller than `t.key`.
28-
29-
### AVL tree balancing
28+
subtree t, with root key t.key, the left subtree, t.left,
29+
contains no node with key greater than t.key, and the right subtree,
30+
t.right, contains no node with key smaller than t.key.
3031

31-
An AVL tree is **balanced** when the difference in heights of the left and right subtrees is no greater than `1`.
3232

3333

34+
### Insertion and Tree Balancing
3435

35-
The AVL tree preserves the balance of the tree by (1) checking after every insertion to detect
36-
when the tree has become unbalanced
37-
and (2) performing one or more **rotation operations** to restore balance when necessary.
38-
The imbalance may be located at
39-
any node along the search path from the root of the tree to the newly inserted node, possibly the grandparent of the newly inserted node, or
40-
possibly
41-
considerably closer to the root of the tree.
4236

37+
**Insertion of a new item** into any binary tree (*e.g.* a BST or an AVL tree) requires
38+
(1) first the search to find the correct place to insert, then (2) the actual insertion.
4339

40+
In the **recursive implementation** of the AVL shown in *AIA*, the first stage,
41+
determining the insertion point, takes place
42+
during the recursive *calls* to the insert function, which accumulate on the machine stack.
4443

45-
### Imbalance configurations
4644

47-
When a new node is inserted in an AVL tree, the tree may become *temporarily* unbalanced.
48-
A temporarily unbalanced AVL tree takes on one of two **configurations**, *zig-zag* or *zig-zig*. The
49-
sequence of rotations depends on the configuration around the node where the imbalance is detected.
45+
The last recursive call *returns* when the new node has been inserted into the tree.
5046

47+
In the AVL tree, the height of the subtree rooted at each node is stored in the
48+
node.During *each* successive *return* from the call to insert,
49+
the **height of the is updated** and the **tree is checked for balance**.
50+
When a new node is inserted in an AVL tree, the tree may become *temporarily* unbalanced, that is
51+
the difference in heights of the left and right subtrees of *any* node is greater than 1.
5152

52-
The **zig-zig** configuration has two mirror-image cases: the child and grandchild nodes or subtrees of the unbalanced node are
53-
either (1) both left subtrees or (2) both right subtrees. The **zig-zag** configuration also has two mirror-image cases: the child and grandchild nodes or subtrees of the unbalanced node are
54-
either (1) a left subtree and a right subtree or (2) a right subtrees and a left subtree.
5553

5654

55+
If the tree has become unbalanced,
56+
balance will be restored using one or two **rotation**
57+
operations, which reduce the height of the unbalanced subtree, while still maintaining the BST invariant.
5758

58-
59+
### Imbalance configurations and rotations
5960

60-
Balance will be restored, using one or two **rotation**
61-
operations (see below).
61+
The exact sequence of rotations depends on the configuration around the
62+
node where the imbalance has been detected.
6263

63-
### Insertion and rotation
64+
There are four possible configurations at the node where an imbalance has been detected:
65+
(1) *left-left*, where the where the child and grandchild nodes or subtrees of the unbalanced node are
66+
either both left subtrees, and (2) its mirror image and *right-right*, where the child and grandchild are both right
67+
subtrees; (3) *left-right*, where there is a left child, with a right subtree as the grandchild, and (4) its mirror image
68+
*right-left*, where the the right child of the unbalanced node has a left (grand)child.
6469

70+
The *left-left* imbalance is restored by a single rotation around the edge between the node
71+
where the imbalance is detected and its (left) child. Try inserting items 30, 20, then 10 into an AVL tree in *AIA*. You
72+
will see that the rotation restores balance, and at the same time maintains the binary search invariant. Similarly for
73+
the *right-right* configuration; try inserting 10, 20, then 30 into the *AIA* AVL tree.
6574

6675

6776

6877

69-
**Insertion of a new item** into any binary tree requires (1) first the search to find the correct place to insert, then (2) the actual insertion.
78+
If you try a larger tree
79+
XXX Lee -- we should come up with a sample tree here, to show imbalance up the tree from the new insert
80+
XXX Lee -- we can put URLs here, as you suggested. Should we do that for the really simple ones above?
7081

71-
In the **recursive implementation** shown in *AIA*, the first stage, determining
72-
the insertion point takes place
73-
during the *"wind up"* stage of the algorithm, where successive recursive *calls to `insert`* are made and accumulate on the machine stack. Search does not
74-
affect the balance of the tree. During the second stage, however, an imbalance may be introduced into the tree when the new node is actually inserted. The imbalance may be close to the new node, or may be
75-
considerably farther up the tree toward the root, along the search path. Therefore, during each successive *return* from the call to `insert`
76-
in the "unwind" stage of the algorithm, the height of the node is updated and the tree is checked for balance.
82+
As you can see, while
83+
**rotation** is a **local operation**, involving only 6 pointer reassignments,
84+
it can affect the balance of the tree overall.
7785

78-
When an imbalance is detected, `i.e.` whenever the heights of the subtrees rooted at this node vary by more than `1`,
79-
a rotation
80-
or rotations are performed in order to bring the tree back into balance. **Rotation** is a **local operation**, involving only 6 pointer reassignments,
81-
yet it affects the balance of the tree overall.
86+
The *left-right* and *right-left* configurations require a double rotation. For the *left-right* configuration,
87+
first a left rotation at the edge between the child and grandchild of the node, and then a right rotation
88+
at the edge between the node and its now left child (previously grandchild). The *right-left* configuration requires
89+
first a right rotation between the child and grandchild, then a left rotation around the node and its (new) right child.
90+
You can see how these work by inserting 30,10, then 20 into AIA (*left-right*) and 10, 30, 20 (*right-left*).
8291

83-
Details of the **rotation**, **single** and **double** rotation are found in the AIA tab `More` for this algorithm.
8492

85-
8693

8794

95+
XXX Lee -- put these exercises here? or integrated into the text, as I've done for left-left above?
96+
Only one place, not both
8897

89-
_**Suggested exercises in AIA**_
98+
_**Suggested exercises in AIA**_
99+
XXX Lee - I haven't reviewed these recently, waiting for us to agree on desired format first.
100+
XXX In any case, will be rewritten to obliterate zig-zag and friend
90101

91-
To **zig-zig and zig-zag configurations** and **rotation corrections** in AIA:
92102

93103
-For a left-left zig-zig configuration, enter 50, 40, then with the code expanded enter 30, step by step, to see the temporary left-left zig-zig imbalance, followed by a single rotation.\
94104
-For right-right zig-zig and single rotation, enter 30, 40, then slowly 50.\

src/algorithms/extra-info/AVLInfo.md

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,22 @@ a:hover{
2121
Geeks for Geeks Link:
2222
<a href="https://www.w3schools.com/dsa/dsa_data_avltrees.php" target="_blank">AVL Tree</a>
2323

24-
---------------------------------------------------------------
25-
26-
2724
Insert detailed information about rotations here.
2825

26+
Rework the following original:
27+
2928
# Rotation in AVL trees
3029

31-
When examining any particular subtree of an AVL tree in AIA, the node we use the following **node numbering scheme** which preserves the binary search invariant, that is, node t1 (with value 1) is always to the left of node t2 (value 2), node t2 is always to the left of node t3 (value 3), node t4 is (value 4) always to the right of node t3. Importantly, note also that some of these nodes **may be empty**, and are shown for completeness.
30+
### Node numbering convention
3231

33-
**Lee -- We should talk about whether this numbering makes things more difficult for a student to understand, or easier.**
32+
When examining any particular subtree of an AVL tree in *AIA*, we use the following **node numbering scheme** in *AIA*. The nodes are
33+
labelled `tX`, where `X` is a numeric value, and the binary search invariant is , that is, node t1 (with value 1) is always to the left of node t2 (value 2), node t2 is always to the left of node t3 (value 3), node t4 is (value 4) always to the right of node t3. Importantly, note also that some of these nodes **may be empty**, and are shown in the diagrams here for completeness. Note also that generally nodes in *AIA* are identified only by their value; we introduce the numbers tX only when showing rotation.
34+
35+
3436

3537
A full and completely balanced tree, rooted at node would thus be:
36-
//Comment: need to have empty spaces at the left of this diagram for it to render correctly.
38+
39+
[Comment: need to have empty spaces at the left of this diagram for it to render correctly.]: #)
3740

3841

3942
@@ -43,67 +46,77 @@ A full and completely balanced tree, rooted at node would thus be:
4346
/ \ / \
4447
t1 t3 t5 t7
4548

46-
The above tree would still be balanced, according to the AVL criterion for balance, if certain nodes or combinations of nodes are empty, for example, t1 or t3 or t5 , or various combinations, such as t1 & t3, or t3 & t5, and so on. The combination t1&t2&t3 would not be allowed, however, as then the tree rooted at t4 would have a left subtree of height 0, and a right subtree with height 2.
49+
Even if *some* nodes or combinations of nodes were empty, the above tree would still be balanced according to AVL criteria. For example, t1 or t3, or both could be removed, but note that removal of t1 and t2 and t3 would leave the tree unbalanced.
4750

51+
## Correcting the temporarily unbalanced tree
4852

49-
Trees with t1 or t3 or t5 empty, or various combinations, such as t1 & t3, or t3 & t5, and so on, empty would still be balanced, according to the AVL criterion of having a difference in height between two subtrees of no more than 1.
53+
Adding a new node may increase the height of some nodes that are closer to the root along the search path. We show here
54+
how a rotation operation, which consists of only a few local pointer reassignments, used to restore the balance of the AVL tree. Importantly,
55+
although the rotation operation is local, it restores the balance at all the preceding nodes in the search path.
5056

5157

58+
In the simplest terms, an edge rotation in a tree is exactly what you would imaging, looking at it visually, and preserves the BST invariant:
5259

53-
In the diagrams below, t6 is the node where the imbalance is noted.
60+
Right rotation:
5461

55-
As shown in the diagram below, t6 is the node at which the imbalance has been noted, and t2 is its left child. The clockwise rotation to restore balance makes t2 the parent of t6, while t6 is the *right* child of t2. Additionally, since t2 already had t4 as its right child, t4 is moved to become the left child of t6. Note that theBST invariant is preserved: t4, is bigger than t2, and is also smaller than t6. The rotation reduces the distance from the root to t1 (where the new node was added), so the tree is no
62+
FIX THIS!!
63+
64+
t6 t2 t2 t6
65+
/ Right Rotation \ and \ Left Rotation /
66+
t2 - - - - - - - > t6 t6 - - - - - - - > t2
5667

68+
Complications arise with how to handle child nodes. For example, in the Right Rotation above, what if t2 already has
69+
a right child, making it not so simple to assign t6 as its right child? Similarly, how do we leave the rotated node
70+
linked to the rest of the tree, if the ancestor of t6 is now t2?
71+
72+
When a new node temporarily unbalances an AVL, the tree can be in one of two configurations, each of which has a mirror image.
73+
The _*left-left*_ case and _*right-right*_ case are mirror images corrected by a single rotation, while the *left-right* and *right-left*
74+
case are mirror images corrected by a double rotation.
75+
76+
## Left-left and Right-right cases (single rotation)
5777

78+
79+
Below we show a temporarily unbalanced AVL tree, where t6 has been identified as the node where
80+
an imbalance is first noted and (as above for Right Rotation) t2 is its left child. Note that some of the nodes may be
81+
`empty`.
5882

83+
First we look at the *left-left* case, where the newly added node is inserted into the subtree rooted at `t1`. The tree is unbalanced at `t6`,
84+
since its left subtree now has a height of 3, while its right subtree has a height of 1.
5985

6086

61-
, as explained in the diagram The 6 and 4 nodes and the edge between them rotate cloc kwise, and
62-
the 5 node changes parents from 4 to 6. This reduces the distance from
63-
the root to the 1 (where the new node was added), restoring the balance
64-
(the distance to the node rooted at 7 is increased but this does not
65-
cause the AVL tree balance condition to be violated). Right rotation is
66-
done by calling rightRotate(t6), where t6 is the tree rooted at 6.
6787

68-
![Alt text if image doesn't open: AVL-left-left](images/AVL/AVL-left-left.jpg){width=120,height=50} This picture is from Greek for Geeks, and is only a placeholder to show proof of concept inserting diagrams, and to check things like size and cropping.
69-
88+
To restore balance in this *left-left* case, we perform a *Right Rotation* around the node where the imbalance is detected, `t6` in this case.
89+
Node t2 is made the parent of t6, while t6 is now the *right* child of t2. Additionally, since t2 already had t4 as its right child, but now needs to
90+
t4 is moved to become the *left* child of t6, which nicely preserves the BST invariant. This subtree is now rooted at t2, instead of t6, and is
91+
therefore linked into the rest of the tree from this new root.
92+
The rotation reduces the distance from the root to t1 (where the new node was added), so the tree is now:
7093

71-
![Alt text if image doesn't open: AVL-left-left](Linda Stern/GitHub/algorithms-in-action.github.io/src/algorithms/explanationsimag/images/AVL/AVL-left-left.jpg){width=120,height=50} This picture is from Greek for Geeks, and is only a placeholder to show proof of concept inserting diagrams, and to check things like size and cropping.
72-
73-
Test comment
94+
/ /
95+
t6 t2
96+
/ \ Right Rotation / \
97+
t2 t7 - - - - - - - > t1 t6
98+
/ \ < - - - - - - - / \
99+
t1 t4 Left Rotation t4 t7
74100

75-
[This shouldn't be seen if the comment signal is correct]: #)
76101

77-
**Check whether the numbering here is still the same in the animation**
78-
**Note I have added a link to the parent of t6 -- check, since the pointer to the left child of this anonymous node needs to be changed, have we given it a number?**
102+
Conversely, for the *right-right* case, looking at t7 as the direct parent of the new node, and t2 as the point at which the
103+
imbalance is first noted: t7 is the right child of right child `t6`, and we would perform a *Left Rotation*, and shown in the
104+
same diagram, going from right to left, and implemented as function `leftRotate` in AIA.
79105

80-
**Lee - is t4 empty in this case? If not, then the tree would already have been unbalanced previously, when t4 was added??**
81106

82-
```
83-
/ /
84-
t6 t2
85-
/ \ Right Rotation / \
86-
t2 7 - - - - - - - > 1 t6
87-
/ \ < - - - - - - - / \
88-
1 t4 Left Rotation t4 7
89-
```
90107

91-
**9 Jan 4PM I haven't gone beyond this**
108+
## The left-right and right-left cases (double rotation)
92109

110+
*I think these diagrams are not consistent with the diagrams in the left-left/right-right section above*
111+
*Think about it!*
93112

94-
## The right-right case
113+
Again, these two cases, left-right and right-left, are symmetrical.
95114

96-
The right-right case is the exact opposite. If the tree on the right in
97-
the diagram above is too unbalanced due to insertion into the subtree
98-
rooted at 7, we can call rightRotate(t2) to lift that subtree and lower
99-
the 1 subtree.
115+
The diagram below illustrates a *left-right* situation, where insertion of a new node into the subtree rooted in node t4 introduces an imbalance into the tree
116+
that is first noted at node t6. The insertion has been into the *right* subtree (rooted at t4) of a *left* subtree (t2) of `t6`, the node at
117+
which the dimbalance was first detected. This situation is corrected by a left rotation at node t2, followed by a right rotation at node t6`, shortening the distance between the new node and the root and rebalancing the tree. Note that the first rotation turns the left-right configuration to a left-left situation, and the second rotation simply follows as in an outright left-left imbalance.
100118

101-
## The left-right case (double rotation)
102119

103-
If the new key was added to the right child of the left child (the
104-
left-right case) and the resulting tree is too unbalanced, the balance can be
105-
restored with a left rotation at node 2 followed by a right rotation at
106-
node 6.
107120
```
108121
6 Rotate 6 Rotate 4
109122
/ \ left at 2 / \ right at 6 / \
@@ -122,7 +135,7 @@ the root of 3, 5 and 7 are changed by one, affecting the overall balance.
122135

123136
If the new key was added to the left child of the right child (the
124137
right-left case) and the resulting tree is too unbalanced, it is a mirror
125-
image of the left-right case:
138+
image of the left-right case. Insertion into the subtree rooted at `t4`, which is the left child of `t6`, while `t6` is the right child of `t2`, where the imbalance is first detected:
126139

127140
```
128141
2 Rotate 2 Rotate 4

0 commit comments

Comments
 (0)