Beruflich Dokumente
Kultur Dokumente
CHAPTER
Chapter Goals
N N N N N To learn how to use linked lists provided in the standard library To understand the implementation of linked lists To be able to program insertion and removal of list elements To understand how to traverse the elements that are stored in lists To learn about binary trees
649
650
Chapter 16.
LinkedList
Link
Dick
Link
Harry
Link
Romeo
Link
Tom null
Link
Juliet
16.1
651
the efciency of inserting or removing elements and you dont need element access in random order. The Java library provides a linked-list class. In this section you will learn how to use this class. In the next section you will peek under the hood and see how some of its key methods are implemented. The LinkedList class in the java.util package implements linked lists. This linked list remembers both the rst and the last link in the list. You have easy access to both ends of the list with the methods
void addFirst(Object obj) void addLast(Object obj) Object getFirst() Object getLast() Object removeFirst() Object removeLast()
How do you add and remove elements in the middle of the list? The list will not give you references to the links. If you had direct access to them and somehow messed them up, you would break the linked list. As you will see in the next section, where you implement some of the linked list operations yourself, keeping all links intact is not trivial. For your protection, the Java library supplies a ListIterator type. A list iterator encapsulates a position anywhere inside the linked list (see Figure 2). Conceptually, you should think of the iterator as pointing between two links, just as the cursor in a word processor points between two characters (see Figure 3). In the conceptual view, think of each link element as being like a letter in a word processor, and think of the iterator as being like the blinking cursor between letters.
LinkedList
Link
Dick
Link
Harry
Link
Romeo
Link
Tom null
ListIterator
652
Chapter 16.
Figure 3
Initial ListIterator position
After inserting J
You obtain a list iterator with the listIterator method of the LinkedList class:
LinkedList list = . . .; ListIterator iterator = list.listIterator();
Initially, the iterator points before the rst element. You can move the iterator position with the next method:
iterator.next();
The next method throws a NoSuchElementException if you are already past the end of the list. You should always call the method hasNext before calling nextit returns true if there is a next element.
if (iterator.hasNext()) iterator.next();
The next method returns the object of the link that it is passing. Therefore, you can traverse all elements in a linked list with the following loop:
while (iterator.hasNext()) { Object obj = iterator.next(); do something with obj }
Actually, the links of the LinkedList class store two links: one to the next element and one to the previous one. Such a list is called a doubly linked list. You can use the previous and hasPrevious methods of the iterator class to move the list position backwards. The add method adds an object after the iterator, and then moves the iterator position past the new element.
iterator.add("Juliet");
You can visualize insertion to be like typing text in a word processor. Each character is inserted after the cursor, and then the cursor moves past the inserted character (see Figure 3). Most people never pay much attention to thisyou may want to try it out and watch carefully how your word processor inserts characters.
16.1
653
The remove method removes and returns the object that was returned by the last call to next or previous. For example, the following loop removes all objects that fulll a certain condition:
while (iterator.hasNext()) { Object obj = iterator.next(); if (obj fullls condition) iterator.remove(); }
You have to be careful when calling remove. It can be called only once after calling next or previous, and you cannot call it immediately after a call to add. If you call the method improperly, it throws an IllegalStateException. Here is a sample program that inserts elements into a list and then iterates through the list, adding and removing elements. Finally, the entire list is printed. The comments indicate the iterator position. Program ListTest1.java
import java.util.LinkedList; import java.util.ListIterator; public class ListTest1 { public static void main(String[] args) { LinkedList staff = new LinkedList(); staff.addLast("Dick"); staff.addLast("Harry"); staff.addLast("Romeo"); staff.addLast("Tom"); // | in the comments indicates the iterator position ListIterator iterator = staff.listIterator(); // DHRT iterator.next(); // DHRT iterator.next(); // DHRT // add more elements after second element iterator.add("Juliet"); // DHJRT iterator.add("Nina"); // DHJNRT iterator.next(); // DHJNRT // remove last traversed element iterator.remove(); // DHJNT // print all elements
654
Chapter 16.
The LinkedList class holds a reference first to the rst link (or null, if the list is completely empty).
class LinkedList { public LinkedList() { first = null; } public Object getFirst() { if (first == null) throw new NoSuchElementException(); return first.data; } . . . private Link first; }
16.2
655
LinkedList
first
Link
data next Dick
Link
newLink data next Amy
Now let us turn to the addFirst operation (see Figure 4). When a new link is added to the list, it becomes the head of the list, and the link that was the old list head becomes its next link:
class LinkedList { . . . public void addFirst(Object obj) { Link newLink = new Link(); newLink.data = obj; newLink.next = first; first = newLink; } . . . }
Removing the rst element of the list works as follows. The data of the rst link is saved and later returned as the method result. The successor of the rst link becomes the rst link of the shorter list (see Figure 5). Then there are no further references to the old link, and the garbage collector will eventually recycle it.
class LinkedList { . . . public Object removeFirst() { if (first == null) throw new NoSuchElementException(); Object obj = first.data; first = first.next; return obj; } . . . }
Next, let us turn to the iterator class. In the standard Java library, ListIterator is an interface and the listIterator method returns an object of an inner class
656
Chapter 16.
LinkedList
first
Link
data next Dick
Link
data next Harry
Each iterator object has a reference position to the last visited link. We also store a reference to the last link before that. We will need that reference to adjust the links properly in the remove operation. The next method is simple. The position reference is advanced to position. next, and the old position is remembered in previous. There is a special case, howeverif the iterator points before the rst element of the list, then the old position is null and must be set to first.
16.2
657
public class Iterator { . . . public Object next() { if (position == null) { position = first; return getFirst(); } else { if (position.next == null) throw new NoSuchElementException(); previous = position; // remember for remove position = position.next; return position.data; } } . . . }
The next method is supposed to be called only when the iterator is not yet at the end of the list. The iterator is at the end if the list is empty (that is, first == null) or if there is no element after the current position (position.next == null).
public class Iterator { . . . public boolean hasNext() { if (position == null) return first != null; else return position.next != null; } . . . }
Removing an element from the middle of the list is more involved. If the previous reference is null, then this call to remove does not immediately follow a call to next, and we throw an IllegalStateException. Otherwise, we set the successor of the previous element to its successor, thereby eliminating it (see Figure 6).
public class Iterator { . . . public void remove() { if (position == first) removeFirst(); else { if (previous == null) throw new IllegalStateException(); previous.next = position.next; position = previous; }
658
Chapter 16.
LinkedList
Link
data next Dick
Link
data next Harry
Link
data next Romeo
ListIterator
previous position
According to the denition of the remove method, it is illegal to call remove twice in a row. Therefore, the remove method sets the previous reference to null. Finally, the most complex operation is the addition of a link. You insert the new link after the current position, and set the successor of the new link to the successor of the current position (see Figure 7).
public class Iterator { . . . public void add(Object obj) { if (position == null) addFirst(obj); else
16.2
659
LinkedList
Link
Dick
Link
Harry
Link
Romeo
ListIterator
previous position newLink
Link
Juliet
Link newLink = new Link(); newLink.data = obj; newLink.next = position.next; position.next = newLink; position = newLink; previous = null;
} } . . . }
Here is a program that consists of the same test stub as in the previous section and the complete implementation of our linked-list class.
660
Chapter 16.
Program ListTest2.java
import java.util.NoSuchElementException; public class ListTest2 { public static void main(String[] args) { LinkedList staff = new LinkedList(); staff.addFirst("Tom"); staff.addFirst("Romeo"); staff.addFirst("Harry"); staff.addFirst("Dick"); // in the comments indicates the iterator position LinkedList.Iterator iterator = staff.listIterator(); // DHRT iterator.next(); // DHRT iterator.next(); // DHRT // add more elements after second element iterator.add("Juliet"); // DHJRT iterator.add("Nina"); // DHJNRT iterator.next(); // DHJNRT // remove last traversed element iterator.remove(); // DHJNT // print all elements iterator = staff.listIterator(); while (iterator.hasNext()) System.out.println(iterator.next()); } } /**
A linked list is a sequence of links with efcient element insertion and removal.
*/ class LinkedList { /**
Returns the rst element in the linked list. @return the rst element in the linked list
*/
16.2
661
public Object getFirst() { if (first == null) throw new NoSuchElementException(); return first.data; } /**
Removes the rst element in the linked list. @return the removed element
*/ public Object removeFirst() { if (first == null) throw new NoSuchElementException(); Object obj = first.data; first = first.next; return obj; } /**
Adds an element to the front of the linked list. @param obj the object to add
*/ public void addFirst(Object obj) { Link newLink = new Link(); newLink.data = obj; newLink.next = first; first = newLink; } /**
Returns an iterator for iterating through this list. @return an iterator for iterating through this list
*/ public Iterator listIterator() { return new Iterator(); } private Link first; private class Link { public Object data; public Link next; } public class Iterator { /**
662
Chapter 16.
Moves the iterator past the next element. @return the traversed element
*/ public Object next() { if (position == null) { position = first; return getFirst(); } else { if (position.next == null) throw new NoSuchElementException(); previous = position; // remember for remove position = position.next; return position.data; } } /**
Tests whether there is an element after the iterator position. @return true if there is an element after the iterator position
*/ public boolean hasNext() { if (position == null) return first != null; else return position.next != null; } /**
Adds an element before the iterator position and moves the iterator past the inserted element. @param obj the object to add
*/ public void add(Object obj) { if (position == null) addFirst(obj); else { Link newLink = new Link(); newLink.data = obj; newLink.next = position.next; position.next = newLink; position = newLink; previous = null; } }
16.2
663
/**
Removes the last traversed element. This method may be called only after a call to the next() method.
*/ public void remove() { if (position == first) removeFirst(); else { if (previous == null) throw new IllegalStateException(); previous.next = position.next; position = previous; } previous = null; } private Link position; private Link previous; } }
This concludes our discussion about linked lists. You now know how to use the
LinkedList class in the Java library, and you have had a peek under the hood to
664
Chapter 16.
The tree in Figure 8 has this property. To verify the binary search property, you must check each node. Consider the node Juliet. All descendants to the left have data before Juliet. All descendants on the right have data after Juliet. Move on to Eve. There is a single descendant to the left, with data Adam before Eve, and a single descendant to the right, with data Harry after Eve. Check the remaining nodes in the same way. Figure 9 shows a binary tree that is not a binary search tree. Look carefullythe root node passes the test, but its two children do not. Let us implement these tree classes. Just as you needed classes for lists and their links, you need a class for the tree, containing a reference to the root node, and a separate class for the nodes. Each node contains two references (to the left and right child node) and a data eld. At the fringes of the tree, one or two of the child references are null. The data variable has type Comparable, not Object, because you must be able to compare the values in a binary search tree in order to place them into the correct position.
class Tree { public Tree(){ . . . } public void insert(Comparable obj) { . . . } public void print() { . . . }
16.3
665
Tree
Node
Juliet
Node
Eve
Node
Romeo null
Node
Adam null null
Node
Harry null null
Node
Tom null null
private Node root; private class Node { public void insertNode(Node newNode) { . . . } public void printNodes() { . . . } public Comparable data; public Node left; public Node right; } }
666
Chapter 16.
Tree
Node
Juliet
Node
Adam
Node
Romeo
Node
Eve null null
Node
Harry null null
Node
Tom null null
If you encounter a non-null node pointer, look at its data value. If the data value of that node is larger than the one you want to insert, continue the process with the left subtree. If the existing data value is smaller, continue the process with the right subtree. If you encounter a null node pointer, replace it with the new node.
For example, consider the tree in Figure 10. We want to insert a new element Romeo into it.
16.3
667
Tree
Node
Juliet
Node
Dick
Node
Tom null null
Node
Harry null null
Start with the root, Juliet. Romeo comes after Juliet, so you move to the right subtree. You encounter the node Tom. Romeo comes before Tom, so you move to the left subtree. But there is no left subtree. Hence you insert a new Romeo node as the left child of Tom (see Figure 11). You should convince yourself that the resulting tree is still a binary search tree. When Romeo is inserted, it must end up as a right descendant of Julietthat is what the binary search tree condition means for the root node Juliet. The root node doesnt care where in the right subtree the new node ends up. Moving along to Tom, the right child of Juliet, all it cares about is that the new node Romeo ends up
668
Chapter 16.
Tree
Node
Juliet
Node
Dick
Node
Tom null
Node
Harry null null
Node
Romeo null null
somewhere on its left. There is nothing to its left, so Romeo becomes the new left child, and the resulting tree is again a binary search tree. Here is the code for the insert method of the Tree class:
class Tree { . . . public void insert(Comparable obj) { Node newNode = new Node(); newNode.data = obj; newNode.left = null;
16.3
669
If the tree is empty, simply set its root to the new node. Otherwise, you know that the new node must be inserted somewhere within the nodes, and you can ask the root node to perform the insertion. That node object calls the insertNode method of the Node class, which checks whether the new object is less than the object stored in the node. If so, the element is inserted in the left subtree; if not, it is inserted in the right subtree:
private class Node { . . . public void insertNode(Node newNode) { if (newNode.data.compareTo(data) < 0) { if (left == null) left = newNode; else left.insertNode(newNode); } else { if (right == null) right = newNode; else right.insertNode(newNode); } } . . . }
Let us trace the calls to insertNode when inserting Romeo into the tree in Figure 10. The rst call to insertNode is
root.insertNode(newNode)
Since root points to Juliet, you compare Juliet with Romeo and nd that you must call
root.right.insertNode(newNode) root.right is Tom. Compare the data values again (Tom vs. Romeo) and nd that you must now move to the left. Since root.right.left is null, set root.right.left to newNode, and the insertion is complete (see Figure 11). Now that the data are inserted in the tree, what can you do with them? It turns out to be surprisingly simple to print all elements in sorted order. You know that all data in the left subtree of any node must come before the node and before all data in the right subtree. That is, the following algorithm will print the elements in sorted order:
1. 2. 3.
Print the left subtree. Print the data. Print the right subtree.
670
Chapter 16.
Lets try this out with the tree in Figure 11. The algorithm tells us to 1. 2. 3. Print the left subtree of Juliet; that is, Dick and children. Print Juliet. Print the right subtree of Juliet; that is, Tom and children.
How do you print the subtree starting at Dick? 1. 2. 3. Print the left subtree of Dick. There is nothing to print. Print Dick. Print the right subtree of Dick, that is, Harry.
The right subtree of Juliet is the subtree starting at Tom. How is it printed? Again, using the same algorithm: 1. Print the left subtree of Tom, that is, Romeo. 2. Print Tom. 3. Print the right subtree of Tom. There is nothing to print.
Now put it all together: the left subtree, Juliet, and the right subtree:
Dick Harry Juliet Romeo Tom
The tree is printed in sorted order. Let us implement the print method. You need a worker method printNodes of the Node class:
private class Node { . . . public void printNodes() { if (left != null) left.printNodes(); System.out.println(data);
16.3
671
To print the entire tree, start this recursive printing process at the root, with the following method of the Tree class.
class Tree { . . . public void print() { if (root != null) root.printNodes(); } . . . }
Here is a complete program to insert data into a tree and to print them out in sorted order: Program TreeTest.java
public class TreeTest { public static void main(String[] args) { Tree staff = new Tree(); staff.insert("Romeo"); staff.insert("Juliet"); staff.insert("Tom"); staff.insert("Dick"); staff.insert("Harry"); staff.print(); } } /**
This class implements a binary search tree whose nodes hold objects that implement the Comparable interface.
*/ class Tree { /**
672
Chapter 16.
/**
Inserts a new node into the tree. @param obj the object to insert
*/ public void insert(Comparable obj) { Node newNode = new Node(); newNode.data = obj; newNode.left = null; newNode.right = null; if (root == null) root = newNode; else root.insertNode(newNode); } /**
Inserts a new node as a descendant of this node. @param newNode the node to insert
*/ public void insertNode(Node newNode) { if (newNode.data.compareTo(data) < 0) { if (left == null) left = newNode; else left.insertNode(newNode); } else { if (right == null) right = newNode; else right.insertNode(newNode); } } /**
16.3
673
Unlike a linked list or an array, a binary tree has no insert positions. You cannot select the position where you would like to insert an element into a binary search tree. The data structure is self-organizing; that is, each element nds its own place. Deleting an element from a binary search tree is a little more complicated, because the children of the deleted node must be rearranged. We will leave that topic to a course on data structures. Now that you have implemented this complex data structure, you may well wonder whether it is any good. Like links in a list, nodes are allocated one at a time. No existing elements need to be moved when a new element is inserted in the tree; that is an advantage. How fast insertion is, however, depends on the shape of the tree. If the tree is balancedthat is, if each node has approximately as many children on the left as on the rightthen insertion is very fast, because about half of the nodes are eliminated in each step. On the other hand, if the tree happens to be unbalanced, then insertion can be slowno faster than insertion into a linked list. (See Figure 12.) If new elements are fairly random, the resulting tree is likely to be well balanced. However, if the incoming elements happen to be already in sorted order, then the resulting tree is completely unbalanced. Each new element is inserted at the end, and the entire tree must be traversed every time to nd that end! Binary search trees work well for random data, but if you suspect that the data in your application might be sorted or have long runs of sorted data, you should not use a binary search tree. There are more sophisticated tree structures whose methods keep trees balanced at all times. To learn more about those advanced data structures, you may want to enroll in a course about data structures.
674
N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N
Chapter 16.
Tree
Node
Tom null
Node
Dick null null
Node
Harry null
Node
Romeo null null
them. In most countries that is illegal. Most governments provide legal protection, such as copyright laws and patents, to encourage the development of new products. Countries that tolerate widespread piracy have found that they have an ample cheap supply of foreign software, but that no local manufacturer is stupid enough to design good software for their own citizens, such as word processors in the local script or nancial programs adapted to the local tax laws.
675
N N N N N N N N N N N N N N
When a mass market for software rst appeared, vendors were enraged by the money they lost through piracy. They tried to ght back by various schemes to ensure that only the legitimate owner could use the software. Some manufacturers used key disks: oppy disks with a special pattern of holes burned in by a laser, which couldnt be copied. Others used dongles: devices that are attached between the computer and a printer port. Legitimate users hated these measures. They paid for the software, but they had to suffer through the inconvenience of inserting a key disk every time they started the software or having a meters worth of dongles stick out from the back of their computer. In the United States, market pressures forced vendors to give up on these copy protection schemes, but they are still commonplace in other parts of the world. Because it is so easy and inexpensive to pirate software, and the chance of being found out is minimal, you have to make a moral choice for yourself. If a package that you would really like to have is too expensive for your budget, do you steal it, or do you stay honest and get by with a more affordable product?
Chapter Summary
Linked lists permit faster insertion and removal in the middle of a data set than arrays and vectors do. 2. The links of a linked list are connected by object references. Each link contains a reference that either is null or species the location of the successor link. 3. Positions inside a linked list are specied with an iterator position. 4. Inserting and removing elements from a linked list involves rearranging the links of the surrounding elements. 5. 6. Tree structures can signicantly speed up the storage and retrieval of sorted data. The simplest of such tree structures is the binary search tree. A binary search tree is a self-organizing data structure. You insert elements into the tree, not into a particular position. The insertion algorithm nds an appropriate position for the new element. 1.
676
Chapter 16.
Review Exercises
Exercise R16.1. Explain what the following code prints. Draw pictures of the linked list after each step. Just draw the forward links, as in Figure 1.
LinkedList staff = new LinkedList(); staff.addFirst("Harry"); staff.addFirst("Dick"); staff.addFirst("Tom"); System.out.println(staff.removeFirst()); System.out.println(staff.removeFirst()); System.out.println(staff.removeFirst());
Exercise R16.2. Explain what the following code prints. Draw pictures of the linked list after each step. Just draw the forward links, as in Figure 1.
LinkedList staff = new LinkedList(); staff.addFirst("Harry"); staff.addFirst("Dick"); staff.addFirst("Tom"); System.out.println(staff.removeLast()); System.out.println(staff.removeFirst()); System.out.println(staff.removeLast());
Exercise R16.3. Explain what the following code prints. Draw pictures of the linked list after each step. Just draw the forward links, as in Figure 1.
LinkedList staff = new LinkedList(); staff.addFirst("Harry"); staff.addLast("Dick"); staff.addFirst("Tom"); System.out.println(staff.removeLast()); System.out.println(staff.removeFirst()); System.out.println(staff.removeLast());
Review Exercises
677
Exercise R16.4. Explain what the following code prints. Draw pictures of the linked list and the iterator position after each step.
LinkedList staff = new LinkedList(); ListIterator iterator = staff.listIterator(); iterator.add("Tom"); iterator.add("Dick"); iterator.add("Harry"); iterator = staff.listIterator(); if (iterator.next().equals("Tom")) iterator.remove(); while (iterator.hasNext()) System.out.println(iterator.next());
Exercise R16.5. Explain what the following code prints. Draw pictures of the linked list and the iterator position after each step.
LinkedList staff = new LinkedList(); ListIterator iterator = staff.listIterator(); iterator.add("Tom"); iterator.add("Dick"); iterator.add("Harry"); iterator = staff.listIterator(); iterator.next(); iterator.next(); iterator.add("Romeo"); iterator.next(); iterator.add("Juliet"); iterator = staff.listIterator(); iterator.next(); iterator.remove(); while (iterator.hasNext()) System.out.println(iterator.next());
Exercise R16.6. The linked-list class in the Java library supports operations addLast and removeLast. To carry out these operations efciently, the LinkedList class has an added reference last to the last node in the linked list. Draw a before/after diagram of the changes of the links in a linked list under the addLast and removeLast methods. Exercise R16.7. The linked-list class in the Java library supports bidirectional iterators. To go backwards efciently, each Link has an added reference, previous, to the predecessor node in the linked list. Draw a before/after diagram of the changes of the links in a linked list under the addFirst and removeFirst methods that shows how the previous links need to be updated. Exercise R16.8. What advantages do lists have over arrays? What disadvantages do they have?
678
Chapter 16.
Exercise R16.9. Suppose you needed to organize a collection of telephone numbers for a company division. There are currently about 6,000 employees, and you know that the phone switch can handle at most 10,000 phone numbers. You expect several hundred lookups against the collection every day. Would you use an array or a linked list to store the information? Exercise R16.10. Suppose you needed to keep a collection of appointments. Would you use a linked list or an array of Appointment objects? Exercise R16.11. What is the difference between a binary tree and a binary search tree? Give examples of each. Exercise R16.12. What is the difference between a balanced and an unbalanced tree? Give examples of each. Exercise R16.13. The following elements are inserted into a binary search tree. Draw the resulting tree after each insertion.
Adam Eve Romeo Juliet Tom Dick Harry
Exercise R16.14. Insert the elements of the preceding exercise in opposite order. Then determine how the Tree.print method prints out both the tree from the preceding exercise and this tree. Explain how the printouts are related. Exercise R16.15. Consider the following tree. In which order are the nodes printed by the Tree.print method?
1 2 4 7 8 5 9 3 6 10
Programming Exercises
679
Programming Exercises
Exercise P16.1. Using just the public interface of the linked-list class, write a method
public static void downsize(LinkedList staff)
that removes every second employee from a linked-list. Exercise P16.2. Using just the public interface of the linked list class, write a method
public static void reverse(LinkedList staff)
that reverses the entries in a linked list. Exercise P16.3. Add a method reverse() to our implementation of the LinkedList class that reverses the links in a list. Implement this method by directly rerouting the links. Exercise P16.4. Write a method draw to display a linked list graphically. Draw each element of the list as a box, and indicate the links with arrows. Exercise P16.5. Add a method size() to our implementation of the LinkedList class that computes the number of elements in the list, by following links and counting the elements until the end of the list is reached. Exercise P16.6. Add a currentSize eld to our implementation of the LinkedList class. Modify the add and remove methods of both the linked list and the list iterator to update the currentSize eld so that it always contains the correct size. Change the size() method of the preceding exercise to simply return the value of this instance variable. Exercise P16.7. Write a class Polynomial that stores a polynomial such as p (x ) 5x 10 9x 7 x 10 Store it as a linked list of terms. A term contains the coefcient and the power of x . For example, you would store p (x ) as (5, 10), (9, 7), (1, 1), (10, 0) Supply methods to add, multiply, and print polynomials. For example, the polynomial p can be constructed as
Polynomial p = new Polynomial(); p.insert(-10, 0); p.insert(-1, 1); p.insert(9, 7); p.insert(5, 10);
680
Chapter 16.
Then compute p (x ) p (x ).
Polynomial q = p.multiply(p); q.print();
Exercise P16.8. Design a data structure Set that can hold a set of integers. Hide the private implementation: a linked list of Integer objects. Provide the following methods:
N N N N
Exercise P16.9. Enhance the set class from the previous example by supplying an iterator object that supports only the hasNext/next methods.
SetIterator iterator = mySet.setIterator(); while (iterator.hasNext()) System.out.println(iterator.next());
Note that the next method returns an int, not an object. For that reason, you cannot simply return a list iterator. Exercise P16.10. Enhance the set class from the previous examples by supplying methods
Set union(Set other) Set intersection(Set other)
that compute the union and intersection of two sets. Exercise P16.11. Implement the sieve of Eratosthenes: a method for computing prime numbers, known to the ancient Greeks. Choose an n . This method will compute all prime numbers up to n . First insert all numbers from 2 to n into a set. Then erase all multiples of 2 (except 2); that is, 4, 6, 8, 10, 12, . . . . Erase all multiples of 3; that is, 6, 9, 12, 15, . . . . Go up to n . The remaining numbers are all primes. Of course, you should use only the public interface of the set data structure. Exercise P16.11. Implement the sieve of Eratosthenes: a method for computing prime numbers known to the ancient Greeks. Choose an n . This method will compute all prime numbers up to n . First insert all numbers from 1 to n into a set. Then erase all multiples of 2 (except 2); that is, 4, 6, 8, 10, 12, .... Erase all multiples of 3, that is, 6, 9, 12, 15, .... Go up to n . The remaining numbers are all primes. Of course, you should use only the public interface of the set structure.
Programming Exercises
681
Exercise P16.12. Design an IntTree class that stores just integers, not objects. Support the same methods as the Tree class in the book. Exercise R16.13. Write a method of the Tree class
Comparable smallest()
that returns the smallest element of a tree. You will also need to add a method to the Node class. Exercise P16.14. Change the print method to print the tree as a tree shape. You can print the tree sideways. Extra credit if you instead display the tree graphically, with the root node centered on the top. Exercise P16.15. The print method of the tree class prints a tree according to the following algorithm: Print the left subtree Print the current node Print the right subtree This is called inorder traversal. There are two other traversal schemes, namely preorder traversal, Print the current node Print the left subtree Print the right subtree and postorder traversal, Print the left subtree Print the right subtree Print the current node Write a program that builds a tree of strings from user input and then prints the users choice of preorder, inorder, or postorder traversal.