CPS 100E, Fall 1996 Lab 10

AVL Trees, Queues, and Animation....

(You may find it easier to read this lab using Netscape or another browser, the URL is http://www.cs.duke.edu/~ola/courses/cps100e/lab/lab10.html)

The goals of this lab include doing the specific tasks outlined below and understanding general concepts behind the tasks.


Last week, we studied binary search trees. We said that operations such as insertion, search, and delete could be done in O(log(n)) time. Well, this is true in the average case, but not in the worst case i.e. when we insert the words of the tree in the following order:

bat cat dog frog monkey moose zebra To fix this problem, we will modify the binary search tree at all times the tree is balanced. By balanced, we mean that there are no nodes that are "too deep" in the tree. In this lab, we will study one of the simplest types of balanced trees: the AVL tree. AVL trees are balanced by height. (i.e. a node's left subtree and a node's right subtree differ by at most 1.)

Lab 10 table of contents

[ Introduction to Lab | Compiling/Running usetree | Testing Functionality of usetree ]

[ Modifications to Classes | Submit ]

Introduction to Lab

In this lab, we will be working with modified versions of the TreeList class, and the Display class from the previous lab. The new TreeList class automatically checks to see if the tree needs to be rebalanced (and does the necessary balancing) when you insert or delete from the tree. As in the last lab, the Display class issues commands to the animator, samba, so that you can physically see what each operation on the tree is doing.

The first part of the lab will once again give you the chance to experiment with the AVL tree using samba and see that the tree remains balanced.

In the second part of the lab, we will modify the TreeList and Display classes so that you can visualize the four "rotations" that are used to balance the AVL tree. To do this

back to lab contents

Compiling/Running usetree

In this section of the lab you'll copy files and then compile and run the usetree program using the samba animator.

First change into your cps100e subdirectory (type pwd to verify where you are). Create a lab10 subdirectory by typing mkdir lab10 and change into this subdirectory (be sure to check that you're in the lab10 subdirectory.) Now copy the files for the lab (don't forget the . when copying).

cp ~ola/cps100e/lab10/* .

You should see the files listed below (these are links to the files in case you use Netscape, and for users outside of Duke).

Be sure you're in the lab10 subdirectory, and check to see that all files are there (type ls). Then, from an xterm window (at the prompt [1] ola@teer8% or similar) compile the first version of the program by typing: make usetree. This should compile several files and link them together with the library libtapestry.a. Now run the program by typing: usetree | samba at the prompt. Two Samba windows should pop up. Move the window that is named Tree_0 somewhere out of the way, but keep it visible. This is where the animation will take place. Click on the start button in the Polka Control Panel window. Then go back to the xterm window and use the menus to run usetree. When you are finished, you must quit usetree (by typing 'q' and hitting the return key) and quit samba by clicking on the Quit button in the Polka Control Panel window.

back to lab contents


Testing Functionality of usetree

In this part of the lab, you will read a tree from a file, you will observe what happens when you insert nodes into the tree, delete nodes from a tree, and search for a node in a tree. You will use options from the usetree menu to do this.

Do the following operations:

Notice that the tree remains balanced at all times.

back to lab contents


Modifications to Classes

One can see after each insertion/deletion that the tree remains balanced. However, the rotations occur so quickly, you cannot see what is actually going on during a balancing operation. To fix this you will make four changes described briefly below and in more detail in the following sections.

  1. Implement the DoColorTree member function within the Display class. This function sets every node in the tree/subtree pointed at by the input parameter (root) to the color that is passed into this function.

  2. Modify the DoBalance member function of the TreeList class to use the ColorTree and SetNodeColor member functions of the Display class. This will help to show which nodes/subtrees are moving during the rotation.

  3. Implement the CopyTree member of the TreeList class. This will give us a means to view the tree before and after the rotation at the same time.

  4. Implement a function DisplayQueue that will be used to show an inorder traversal of a tree. This is extra credit.

DoColorTree

Implement the DoColorTree member function of the Display class. The Declaration looks like the following:

void Display::DoColorTree(TreeNode * root, displayColor color) // postcondition: subtree that starts at root is colored to "color" { // You get to fill in this function } You should use the SetNodeColor member function to set the current node's color to the given color. Then, you should make recursive calls for both of the node's subtrees. Make sure you check for pointers that are equal to 0.

DoBalance

In this section of the lab, we will make use of the ColorTree and SetNodeColor member functions of the Display class to show which nodes will be moving when the tree is rebalanced. To do this, we will add code to the DoBalance member function of the TreeList class. There are 4 possible rotations: LeftRotation, DoubleLeftRotation, RightRotation, and DoubleRightRotation. We will discuss them each in turn. For each type of rotation, you will do the following:

  1. Divide the tree/subtree into 3 sets. Each set will have a different color. The first set will consist of the node that will end up being the root after the rotation. The second set will end up being the left subtree of the new root after the rotation, and the third set will be the right subtree of the new root after the rotation.

  2. After changing the colors of the proper subtrees, call the Pause function so that samba waits for the user to hit the return key before the rotation occurs. This should happen before the call to myDisplay.RedrawTree

  3. After the call to myDisplay.RedrawTree, you should call Pause again.

  4. Finally, call the ColorTreeDefault member function of the Display class to change the entire tree/subtree back to its original color.

Case I: Left Rotation

*

Before the rotation, the tree will look similar to the tree on the left hand side of the above figure. After the rotation, it will look like the tree on the right hand side of the figure. You will use 3 colors for this case.

Case II: Double Left Rotation

*

As in Case I, the left hand side shows the tree before the rotation, and the right hand side shows the tree after the rotation.

Case III: Double Right Rotation

*

For the double right rotation, you will partition the tree as follows:

Case IV: Right Rotation

*

For the right rotation, you will partition the tree as follows:

After you get this part of the lab to work, you should start with an empty tree, and comprise a list of at least 16 insertions that cause as many rotations as you can. You should cause at least one of each kind of rotation to occur. Put the list of additions in your README file annotating insertions that cause rotations. For example:

monkey gorilla bear (caused LeftRotation)

CopyTree

In this part of the lab, you will implement the CopyTree member function. This function had the following prototype

void TreeList::CopyTree (TreeNode * root, TreeNode * & newTree, Display & newDisplay) This function should do the following if root!=0
  1. Create a copy of the root node
  2. Display the copy using the DisplayNode member function of the Display class
  3. Move the node to the proper place by calling the MoveNode member function of the Display class
  4. Make recursive calls for each of its children.

To test this function change the BalanceTree member function of the TreeList class to look like the following.

void TreeList::BalanceTree(TreeNode * & root) // postcondition: tree is balanced { if (root == 0) return; if (NeedBalance(root)) { Display display(cout); // A new window for displaying the copy // of the tree TreeNode * newTree; // new tree display.UpdatelevelCount(ComputeHeight(myTree)-1); // set height CopyTree(myTree, newTree, display); DoBalance(root); DeleteTree(newTree); // delete the tree } }

This will give you a snap shot of the tree before the rotation occurs. After you see the tree rotated, you will want to hit the Close button in the new window so that your screen does not get too cluttered.

DisplayQueue: EXTRA CREDIT

Implement the function DisplayQueue in tree.cc. It takes two parameters: Queue<TreeNode *> queue, a queue of pointers to TreeNode structures, and Display & display, the object that issues the samba commands for the tree. This will be very similar to the DisplayStack function that you wrote last week, except this time, you will use queues instead of stacks.

back to lab contents

Submitting The Lab

To submit assignments you'll run the command below, but substitute your section number (1, 2, or 3) for N.
    submit100e lab10.N README tree.cc display.cc

You can enter the files in any order.

Remember that every assignment must have a README file submitted with it (please use all capital letters). Include your name, the date, and an estimate of how long you worked on the assignment in the README file. You must also include a list of names of all those people with whom you collaborated on the assignment.

You also must turn in the inlab questions either by turning in the sheet during lab or by submitting the answers with your README.