AhmadLang / Java, How To Program, 2004
.pdf
2.Traverse the left subtree with a call to preorderHelper (line 76).
3.Traverse the right subtree with a call to preorderHelper (line 77).
The preorder traversal processes the value in each node as the node is visited. After processing the value in a given node, the preorder traversal processes the values in the left subtree, then the values in the right subtree. The preorder traversal of the tree in Fig. 17.19 is
27 13 6 17 42 33 48
Method postorderHelper (lines 104112) defines the steps for a postorder traversal:
1.Traverse the left subtree with a call to postorderHelper (line 109).
2.Traverse the right subtree with a call to postorderHelper (line 110).
3.Process the value in the node (line 111).
The postorder traversal processes the value in each node after the values of all that node's children are processed. The postorderTraversal of the tree in Fig. 17.19 is
6 17 13 33 48 42 27
[Page 845]
The binary search tree facilitates duplicate elimination. While building a tree, the insertion operation recognizes attempts to insert a duplicate value, because a duplicate follows the same "go left" or "go right" decisions on each comparison as the original value did. Thus, the insertion operation eventually compares the duplicate with a node containing the same value. At this point, the insertion operation can decide to discard the duplicate value (as we do in this example).
Searching a binary tree for a value that matches a key value is fast, especially for tightly packed (or balanced) trees. In a tightly packed tree, each level contains about twice as many elements as the previous level. Figure 17.19 is a tightly packed binary tree. A tightly packed binary search tree with n elements has log2n levels. Thus, at most log2n comparisons are required either to find a match or to
determine that no match exists. Searching a (tightly packed) 1000-element binary search tree requires at most 10 comparisons, because 210 > 1000. Searching a (tightly packed) 1,000,000-element binary search tree requires at most 20 comparisons, because 220 > 1,000,000.
The chapter exercises present algorithms for several other binary tree operations, such as deleting an item from a binary tree, printing a binary tree in a two-dimensional tree format and performing a level-order traversal of a binary tree. The level-order traversal visits the nodes of the tree row by row, starting at the root node level. On each level of the tree, a level-order traversal visits the nodes from left to right. Other binary tree exercises include allowing a binary search tree to contain duplicate values, inserting string values in a binary tree and determining how many levels are contained in a binary tree. Chapter 19 continues our discussion of data structures by presenting the data structures in the Java API.
[Page 845 (continued)]
17.10. Wrap-Up
In this chapter, you learned about type-wrapper classes, boxing and dynamic data structures that grow and shrink at execution time. You learned that each primitive type has a corresponding type-wrapper class in package java.lang. You also saw that Java can convert between primitive values and objects of the type-wrapper classes using J2SE 5.0's new feature called boxing.
You learned that linked lists are collections of data items that are "linked up in a chain." You also saw that an application can perform insertions and deletions anywhere in a linked list. You learned that the stack and queue data structures are constrained versions of lists. For stacks, you saw that insertions and deletions are made only at its top. For queues that represent waiting lines, you saw that insertions are made at the tail and deletions are made from the head. You also learned the binary tree data structure. You saw a binary search tree that facilitated high-speed searching and sorting of data and eliminating duplicate data items efficiently. Throughout the chapter, you learned how to create and package these data structures for reusability and maintainability.
In Chapter 18, Generics, we discuss J2SE 5.0's new feature called generics, which provides a mechanism for declaring classes and methods without specific type information so that the classes and methods can be used with many different reference types. Generics are used extensively in Java's built-in set of data structures, known as the Collections API. You will learn about collections in Chapter 19, Collections.
[Page 846]
Summary
Dynamic data structures can grow and shrink at execution time.
Linked lists are collections of data items "linked up in a chain"insertions and deletions can be made anywhere in a linked list.
Stacks are important in compilers and operating systemsinsertions and deletions are made only at one end of a stack, its top.
Queues represent waiting lines; insertions are made at the tail of a queue and deletions are made from the head.
Binary trees facilitate high-speed searching and sorting of data, eliminating duplicate data items efficiently, representing file-system directories and compiling expressions into machine language.
Type-wrapper classes (e.g., Integer, Double, Boolean) enable programmers to manipulate
primitive-type values as objects. Objects of these classes can be used in collections and data structures that can store only references to objectsnot primitive-type values.
J2SE 5.0 introduces two new conversions, the boxing conversion and the unboxing conversion. A
boxing conversion converts a value of a primitive type to an object of the corresponding typewrapper class. An unboxing conversion converts an object of a type-wrapper class to a value of the corresponding primitive type.
J2SE 5.0 performs boxing conversions and unboxing conversions automatically (called autoboxing and auto-unboxing).
A self-referential class contains a reference that refers to another object of the same class type. Self-referential objects can be linked together to form dynamic data structures.
The limit for dynamic memory allocation can be as large as the available physical memory in the
computer or the amount of available disk space in a virtual-memory system. Often, the limits are much smaller because the computer's available memory must be shared among many users.
If no memory is available, an OutOfMemoryError is thrown.
A linked list is accessed via a reference to the first node of the list. Each subsequent node is accessed via the link-reference member stored in the previous node.
By convention, the link reference in the last node of a list is set to null to mark the end of the list.
A node can contain data of any type, including objects of other classes.
A linked list is appropriate when the number of data elements to be stored is unpredictable. Linked lists are dynamic, so the length of a list can increase or decrease as necessary.
The size of a "conventional" Java array cannot be alteredit is fixed at creation time.
Linked lists can be maintained in sorted order simply by inserting each new element at the proper point in the list.
List nodes normally are not stored contiguously in memory. Rather, they are logically contiguous.
A stack is a last-in, first-out (LIFO) data structure. The primary methods used to manipulate a
stack are push and pop. Method push adds a new node to the top of the stack. Method pop removes a node from the top of the stack and returns the data object from the popped node.
Stacks have many interesting applications. When a method call is made, the called method must
know how to return to its caller, so the return address is pushed onto the program execution stack. If a series of method calls occurs, the successive return values are pushed onto the stack in last-in, first-out order so that each method can return to its caller. The program execution stack contains the space created for local variables on each invocation of a method. When the method returns to its caller, the space for that method's local variables is popped off the stack, and those variables are no longer available to the program.
[Page 847]
Stacks are used by compilers to evaluate arithmetic expressions and generate machine-language code to process the expressions.
The technique of implementing each stack method as a call to a List method is called delegationthe stack method invoked delegates the call to the appropriate List method.
A queue is similar to a checkout line in a supermarketthe first person in line is serviced first, and other customers enter the line only at the end and wait to be serviced.
Queue nodes are removed only from the head of the queue and are inserted only at the tail. For this reason, a queue is referred to as a first-in, first-out (FIFO) data structure.
The insert and remove operations for a queue are known as enqueue and dequeue.
Queues have many uses in computer systems. Most computers have only a single processor, so
only one application at a time can be serviced. Entries for the other applications are placed in a queue. The entry at the front of the queue is the next to receive service. Each entry gradually advances to the front of the queue as applications receive service.
A tree is a nonlinear, two-dimensional data structure. Tree nodes contain two or more links.
A binary tree is a tree whose nodes all contain two links. The root node is the first node in a tree.
Each link in the root node refers to a child. The left child is the first node in the left subtree, and the right child is the first node in the right subtree.
The children of a node are called siblings. A node with no children is called a leaf node.
A binary search tree (with no duplicate node values) has the characteristic that the values in any
left subtree are less than the value in the subtree's parent node, and the values in any right subtree are greater than the value in the subtree's parent node. A node can be inserted only as a leaf node in a binary search tree.
An inorder traversal of a binary search tree processes the node values in ascending order.
In a preorder traversal, the value in each node is processed as the node is visited. Then the values in the left subtree are processed, and then the values in the right subtree.
In a postorder traversal, the value in each node is processed after the values of its children.
The binary search tree facilitates duplicate elimination. As the tree is created, attempts to insert
a duplicate value are recognized, because a duplicate follows the same "go left" or "go right" decisions on each comparison as the original value did. Thus, the duplicate eventually is compared with a node containing the same value. The duplicate value can be discarded at this point.
Searching a binary tree for a value that matches a key value is also fast, especially for tightly
packed trees. In a tightly packed tree, each level contains about twice as many elements as the previous one. So a tightly packed binary search tree with n elements has log2n levels, and thus
at most log2n comparisons would have to be made either to find a match or to determine that no match exists. Searching a (tightly packed) 1000-element binary search tree requires at most 10 comparisons, because 210 > 1000. Searching a (tightly packed) 1,000,000-element binary search tree requires at most 20 comparisons, because 220 > 1,000,000.
[Page 847 (continued)]
Terminology
autoboxing auto-unboxing balanced tree
binary search tree binary tree
binary tree sort
Boolean class boxing conversion
Byte class
Character class child node children of a node
delegate a method call delete a node
[Page 848]
dequeue
Double class duplicate elimination
dynamic data structure enqueue
FIFO (first-in, first-out)
Float class head of a queue
inorder traversal of a binary tree insert a node
Integer class leaf node
left child left subtree
level-order traversal of a binary tree LIFO (last-in, first-out)
linear data structure linked list
Long class node
nonlinear data structure null reference
OutOfMemoryError
packed tree parent node pop
postorder traversal of a binary tree predicate method
preorder traversal of a binary tree program execution stack
push queue
recursive tree traversal algorithms right child
right subtree root node
self-referential class
Short class
stack
subtree
tail of a queue
top of a stack
traversal
tree
type-wrapper classes
unboxing conversion
visiting a node
[Page 848 (continued)]
Self-Review Exercises
17.1 Fill in the blanks in each of the following statements:
a.A self__________ class is used to form dynamic data structures that can grow and shrink at execution time.
b.A(n) __________ is a constrained version of a linked list in which nodes can be inserted and deleted only from the start of the list.
c.A method that does not alter a linked list, but simply looks at it to determine whether it is empty, is referred to as a(n) __________ method.
d.A queue is referred to as a(n) __________ data structure because the first nodes inserted are the first ones removed.
e.The reference to the next node in a linked list is referred to as a(n) __________.
f.Automatically reclaiming dynamically allocated memory in Java is called __________.
g.A(n) __________ is a constrained version of a linked list in which nodes can be inserted only at the end of the list and deleted only from the start of the list.
h.A(n) __________ is a nonlinear, two-dimensional data structure that contains nodes with two or more links.
i.A stack is referred to as a(n) __________ data structure because the last node inserted is the first node removed.
j. The nodes of a(n) __________ tree contain two link members.
k.The first node of a tree is the __________ node.
l.Each link in a tree node refers to a(n) __________ or __________ of that node.
m.A tree node that has no children is called a(n) __________ node.
n.The three traversal algorithms we mentioned in the text for binary search trees are
__________, __________and __________.
[Page 849]
o.Assuming that myArray contains references to Double objects, __________ occurs when the statement "double number = myArray[ 0 ];" executes.
p.Assuming that myArray contains references to Double objects, __________ occurs when the statement "myArray[ 0 ] = 1.25;" executes.
17.2 What are the differences between a linked list and a stack?
17.3 What are the differences between a stack and a queue?
17.4 Perhaps a more appropriate title for this chapter would have been "Reusable Data Structures." Comment on how each of the following entities or concepts contributes to the reusability of data structures:
a.classes
b.inheritance
c.composition
17.5 Manually provide the inorder, preorder and postorder traversals of the binary search tree of Fig. 17.20.
Figure 17.20. Binary search tree with 15 nodes.
[View full size image]
