AhmadLang / Java, How To Program, 2004
.pdf
12 2 6 4 10 8 37 89 68 45
Starting from the left, but beginning with the element after 10, compare each element with 37 until an element greater than 37 is foundthen swap 37 and that element. There are no more elements greater than 37, so when we compare 37 with itself, we know that 37 has been placed in its final location of the sorted array. Every value to the left of 37 is smaller than it, and every value to the right of 37 is larger than it.
Once the partition has been applied on the previous array, there are two unsorted subarrays. The subarray with values less than 37 contains 12, 2, 6, 4, 10 and 8. The subarray with values greater than 37 contains 89, 68 and 45. The sort continues recursively with both subarrays being partitioned in the same manner as the original array.
Based on the preceding discussion, write recursive method quickSortHelper to sort a one-dimensional integer array. The method should receive as arguments a starting index and an ending index on the original array being sorted.
[Page 817]
Chapter 17. Data Structures
Much that I bound, I could not free;
Much that I freed returned to me.
Lee Wilson Dodd
'Will you walk a little faster?' said a whiting to a snail,
'There's a porpoise close behind us, and he's treading on my tail.'
Lewis Carroll
There is always room at the top.
Daniel Webster
Push onkeep moving.
Thomas Morton
I'll turn over a new leaf.
Miguel de Cervantes
OBJECTIVES
In this chapter you will learn:
To form linked data structures using references, self-referential classes and recursion.
The type-wrapper classes that enable programs to process primitive data values as objects.
To use autoboxing to convert a primitive value to an object of the corresponding type-wrapper class.
To use auto-unboxing to convert an object of a type-wrapper class to a primitive value.
To create and manipulate dynamic data structures, such as linked lists, queues, stacks and binary trees.
Various important applications of linked data structures.
How to create reusable data structures with classes, inheritance and composition.
[Page 818]
Outline
17.1 Introduction
17.2 Type-Wrapper Classes for Primitive Types
17.3 Autoboxing and Auto-Unboxing
17.4 Self-Referential Classes
17.5 Dynamic Memory Allocation
17.6 Linked Lists
17.7 Stacks
17.8 Queues
17.9 Trees
17.10 Wrap-Up
Summary
Terminology
Self-Review Exercises
Answers to Self-Review Exercises Exercises
Special Section: Building Your Own Compiler
[Page 818 (continued)]
17.1. Introduction
In previous chapters, we have studied fixed-size data structures such as one-dimensional and multidimensional arrays. This chapter introduces dynamic data structures that 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 systems; insertions and deletions are made only at one end of a stackits top. Queues represent waiting lines; insertions are made at the back (also referred to as the tail) of a queue and deletions are made from the front (also referred to as the head). Binary trees facilitate high-speed searching and sorting of data, eliminating duplicate data items efficiently, representing file-system directories, compiling expressions into machine language and many other interesting applications.
We will discuss each of these major types of data structures and implement programs that create and manipulate them. We use classes, inheritance and composition to create and package these data structures for reusability and maintainability. In Chapter 19, Collections, we discuss Java's predefined classes that implement the data structures discussed in this chapter.
The examples presented here are practical programs that can be used in advanced courses and in industrial applications. The exercises include a rich collection of useful applications.
This chapter's examples manipulate primitive values for simplicity. However, most of the data-structure implementations in this chapter store only Objects. J2SE 5.0 has added a new feature, called boxing, that allows primitive values to be converted to and from objects for use in cases like this. The objects that represent primitive values are instances of Java's so-called type-wrapper classes in package java.lang. We discuss these classes and boxing in the next two sections, so we can use them in this chapter's examples.
We encourage you to attempt the major project described in the special section entitled Building Your Own Compiler. You have been using a Java compiler to translate your Java programs to bytecodes so that you could execute these programs on your computer. In this project, you will actually build your own compiler. It will read a file of statements written in a simple, yet powerful high-level language similar to early versions of the popular language BASIC. Your compiler will translate these statements into a file of Simpletron Machine Language (SML) instructionsSML is the language you learned in the Chapter 7 special section, Building Your Own Computer. Your Simpletron Simulator program will then execute the SML program produced by your compiler! Implementing this project by using an objectoriented approach will give you a wonderful opportunity to exercise most of what you have learned in this book. The special section carefully walks you through the specifications of the high-level language and describes the algorithms you will need to convert each high-level language statement into machinelanguage instructions. If you enjoy being challenged, you might attempt the many enhancements to both the compiler and the Simpletron Simulator suggested in the exercises.
[Page 819]
[Page 819 (continued)]
17.2. Type-Wrapper Classes for Primitive Types
Each primitive type (listed in Appendix D, Primitive Types) has a corresponding type-wrapper class (in package java.lang). These classes are called Boolean, Byte, Character, Double, Float,
Integer, Long and Short. Each type-wrapper class enables you to manipulate primitive-type values as objects. Many of the data structures that we develop or reuse in Chapters 1719 manipulate and share Objects. These classes cannot manipulate variables of primitive types, but they can manipulate objects of the type-wrapper classes, because every class ultimately derives from Object.
Each of the numeric type-wrapper classesByte, Short, Integer, Long, Float and Doubleextends class Number. Also, the type-wrapper classes are final classes, so you cannot extend them.
Primitive types do not have methods, so the methods related to a primitive type are located in the corresponding type-wrapper class (e.g., method parseInt, which converts a String to an int value, is located in class Integer). If you need to manipulate a primitive value in your program, first refer to the documentation for the type-wrapper classesthe method you need might already be declared.
[Page 820 (continued)]
17.4. Self-Referential Classes
A self-referential class contains an instance variable that refers to another object of the same class type. For example, the declaration
class Node |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
private |
int |
data; |
|
|
|
|
|
|
|
private Node nextNode; // reference to next linked node |
|||||||||
public |
Node( |
int data |
) |
{ |
/* |
constructor |
body */ } |
||
public |
void |
setData( |
int data ) |
{ |
/* |
method |
body |
*/ |
} |
public |
int getData() |
|
{ |
/* |
method |
body |
*/ |
} |
|
public |
void |
setNext( Node next ) { /* method body |
*/ |
} |
|||||
public |
Node |
getNext() |
|
{ |
/* |
method |
body |
*/ |
} |
} // end class |
Node |
|
|
|
|
|
|
|
|
declares class Node, which has two private instance variablesinteger data and Node reference nextNode. Field nextNode references a Node object, an object of the same class being declared herehence, the term "self-referential class." Field nextNode is a linkit "links" an object of type Node to another object of the same type. Type Node also has five methods: a constructor that receives an Integer to initialize data, a setData method to set the value of data, a getdata method to return the value of data, a setNext method to set the value of nextNode and a getNext method to return a reference to the next node.
Programs can link self-referential objects together to form such useful data structures as lists, queues, stacks and trees. Figure 17.1 illustrates two self-referential objects linked together to form a list. A backslashrepresenting a null referenceis placed in the link member of the second self-referential object to indicate that the link does not refer to another object. Note the backslash is illustrative; it does not correspond to the backslash character in Java. Normally, a null reference indicates the end of a data structure. There are other ways to represent the end of a data structure that are beyond the scope of this text.
[Page 821]
Figure 17.1. Self-referential-class objects linked together.
[View full size image]
[Page 821 (continued)]
17.5. Dynamic Memory Allocation
Creating and maintaining dynamic data structures requires dynamic memory allocationthe ability for a program to obtain more memory space at execution time to hold new nodes and to release space no longer needed. Remember that Java programs do not explicitly release dynamically allocated memory. Rather, Java performs automatic garbage collection of objects that are no longer referenced in a program.
The limit for dynamic memory allocation can be as large as the amount of 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 applications.
The declaration and class-instance creation expression
Node nodeToAdd = new Node( 10 ); // 10 is nodeToAdd's data
allocates the memory to store a Node object and returns a reference to the object, which is assigned to nodeToAdd. If insufficient memory is available, the expression throws an OutOfMemoryError.
The following sections discuss lists, stacks, queues and trees that all use dynamic memory allocation and self-referential classes to create dynamic data structures.
Linked list nodes normally are not stored contiguously in memory. Rather, they are logically contiguous. Figure 17.2 illustrates a linked list with several nodes. This diagram presents a singly linked listeach node contains one reference to the next node in the list. Often, linked lists are implemented as doubly linked listseach node contains a reference to the next node in the list and a reference to the previous node in the list. Java's LinkedList class is a doubly linked list implementation.
Figure 17.2. Linked list graphical representation.
[View full size image]
Performance Tip 17.4
Normally, the elements of an array are contiguous in memory. This allows immediate access to any array element, because its address can be calculated directly as its offset from the beginning of the array. Linked lists do not afford such immediate access to their elementsan element can be accessed only by traversing the list from the front (or from the back in a doubly linked list).
The program of Fig. 17.3Fig. 17.5 uses an object of our List class to manipulate a list of miscellaneous objects. The program consists of four classesListNode (Fig. 17.3, lines 637), List (Fig. 17.3, lines 40147),
EmptyListException (Fig. 17.4) and ListTest (Fig. 17.5). The List, ListNode and EmptyListException classes are placed in package com.deitel.jhtp6.ch17, so they can be reused throughout this chapter. Encapsulated in each List object is a linked list of ListNode objects. [Note: Many of the classes in this chapter are declared in the package com.deitel.jhtp6.ch17. Each such class should be compiled with the -d command-line option to javac. When compiling the classes that are not in this package and when running the programs, be sure to use the - classpath option to javac and java, respectively.]
[Page 823]
Figure 17.3. ListNode and List class declarations.
(This item is displayed on pages 823 - 826 in the print version)
1 |
// |
Fig. |
17. |
3: List.java |
2 |
// |
ListNode |
and List class definitions. |
|
3 |
package |
com.deitel.jhtp6.ch17; |
||
4 |
|
|
|
|
5 |
// |
class |
to |
represent one node in a list |
6class ListNode
7{
8 |
// package access members; List can access these directly |
9 |
Object data; |
10 |
ListNode nextNode; |
