Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

AhmadLang / Java, How To Program, 2004

.pdf
Скачиваний:
626
Добавлен:
31.05.2015
Размер:
51.82 Mб
Скачать

11

12// constructor creates a ListNode that refers to object

13ListNode( Object object )

14{

15this ( object, null );

16} // end ListNode one-argument constructor

17

18// constructor creates ListNode that refers to

19// Object and to next ListNode

20ListNode( Object object, ListNode node )

21{

22data = object;

23nextNode = node;

24} // end ListNode two-argument constructor

25

26// return reference to data in node

27Object getObject()

28{

29return data; // return Object in this node

30} // end method getObject

31

32// return reference to next node in list

33ListNode getNext()

34{

35return nextNode; // get next node

36} // end method getNext

37} // end class ListNode

38

39// class List definition

40public class List

41{

42private ListNode firstNode;

43private ListNode lastNode;

44private String name; // string like "list" used in printing

46// constructor creates empty List with "list" as the name

47public List()

48{

49this( "list" );

50} // end List no-argument constructor

52// constructor creates an empty List with a name

53public List( String listName )

54{

55name = listName;

56firstNode = lastNode = null;

57} // end List one-argument constructor

59// insert Object at front of List

60public void insertAtFront( Object insertItem )

61

{

62

if ( isEmpty() ) // firstNode and lastNode refer to same object

63firstNode = lastNode = new ListNode( insertItem );

64else // firstNode refers to new node

65firstNode = new ListNode( insertItem, firstNode );

66} // end method insertAtFront

67

68// insert Object at end of List

69public void insertAtBack( Object insertItem )

70{

71 if ( isEmpty() ) // firstNode and lastNode refer to same Object

72firstNode = lastNode = new ListNode( insertItem );

73else // lastNode's nextNode refers to new node

74lastNode = lastNode.nextNode = new ListNode( insertItem );

75} // end method insertAtBack

76

77// remove first node from List

78public Object removeFromFront() throws EmptyListException

79{

80if ( isEmpty() ) // throw exception if List is empty

81throw new EmptyListException( name );

82

83 Object removedItem = firstNode.data; // retrieve data being removed 84

85 // update references firstNode and lastNode

86if ( firstNode == lastNode )

87firstNode = lastNode = null;

88else

89firstNode = firstNode.nextNode;

91return removedItem; // return removed node data

92} // end method removeFromFront

94// remove last node from List

95public Object removeFromBack() throws EmptyListException

96{

97if ( isEmpty() ) // throw exception if List is empty

98throw new EmptyListException( name );

99

100 Object removedItem = lastNode.data; // retrieve data being removed 101

102// update references firstNode and lastNode

103if ( firstNode == lastNode )

104firstNode = lastNode = null;

105else // locate new last node

106{

107ListNode current = firstNode;

108

109// loop while current node does not refer to lastNode

110while ( current.nextNode != lastNode )

111

current = current.nextNode;

112

 

113lastNode = current; // current is new lastNode

114current.nextNode = null;

115} // end else

116

117return removedItem; // return removed node data

118} // end method removeFromBack

119

120// determine whether list is empty

121public boolean isEmpty()

122{

123return firstNode == null; // return true if List is empty

124} // end method isEmpty

125

126// output List contents

127public void print()

128{

129if ( isEmpty() )

130{

131System.out.printf( "Empty %s\n", name );

132return;

133} // end if

135System.out.printf( "The %s is: ", name );

136ListNode current = firstNode;

138// while not at end of list, output current node's data

139while ( current != null )

140{

141System.out.printf( "%s ", current.data );

142current = current.nextNode;

143} // end while

144

145System.out.println( "\n" );

146} // end method print

147} // end class List

Figure 17.4. EmptyListException class declaration.

(This item is displayed on page 826 in the print version)

1// Fig. 17.4: EmptyListException.java

2// Class EmptyListException definition.

3package com.deitel.jhtp6.ch17;

4

5public class EmptyListException extends RuntimeException

6{

7// no-argument constructor

8public EmptyListException()

9{

10this( "List" ); // call other EmptyListException constructor

11} // end EmptyListException no-argument constructor

12

13// one-argument constructor

14public EmptyListException( String name )

15{

16super( name + " is empty" ); // call superclass constructor

17} // end EmptyListException one-argument constructor

18} // end class EmptyListException

Figure 17.5. Linked list manipulations.

(This item is displayed on pages 827 - 828 in the print version)

1 // Fig. 17.5: ListTest.java

2 // ListTest class to demonstrate List capabilities.

3import com.deitel.jhtp6.ch17.List;

4import com.deitel.jhtp6.ch17.EmptyListException;

6public class ListTest

7{

8public static void main( String args[] )

9{

10List list = new List(); // create the List container

12// insert integers in list

13list.insertAtFront( -1 );

14list.print();

15list.insertAtFront( 0 );

16list.print();

17list.insertAtBack( 1 );

18list.print();

19list.insertAtBack( 5 );

20list.print();

21

22// remove objects from list; print after each removal

23try

24{

25Object removedObject = list.removeFromFront();

26System.out.printf( "%s removed\n", removedObject );

27list.print();

28

29removedObject = list.removeFromFront();

30System.out.printf( "%s removed\n", removedObject );

31list.print();

32

33removedObject = list.removeFromBack();

34System.out.printf( "%s removed\n", removedObject );

35list.print();

36

37removedObject = list.removeFromBack();

38System.out.printf( "%s removed\n", removedObject );

39list.print();

40} // end try

41catch ( EmptyListException emptyListException )

42{

43emptyListException.printStackTrace();

44} // end catch

45} // end main

46} // end class ListTest

The list is: -1

The list is: 0 -1

The list is: 0 -1 1

The list is: 0 -1 1 5

0 removed

The list is: -1 1 5

-1 removed

The list is: 1 5

5 removed

The list is: 1

1 removed Empty list

Class ListNode (Fig. 17.3, lines 637) declares package-access fields data and nextNode. The data field is an Object reference, so it can refer to any object. ListNode member nextNode stores a reference to the next ListNode object in the linked list (or null if the node is the last one in the list).

[Page 826]

Lines 4243 of class List (Fig. 17.3, lines 40147) declare references to the first and last ListNodes in a List (firstNode and lastNode, respectively). The constructors (lines 4750 and 5357) initialize both references to null. The most important methods of class List are insertAtFront (lines 6066), insertAtBack (lines 6975), removeFromFront (lines 7892) and removeFromBack (lines 95118). Method isEmpty (lines 121124) is a predicate method that determines whether the list is empty (i.e., the reference to the first node of the list is null). Predicate methods typically test a condition and do not modify the object on which they are called. If the list is empty, method isEmpty returns TRue; otherwise, it returns false. Method print (lines 127146) displays the list's contents. A detailed discussion of List's methods follows Fig. 17.5.

Method main of class ListTest (Fig. 17.5) inserts objects at the beginning of the list using method insertAtFront, inserts objects at the end of the list using method insertAtBack, deletes objects from the front of the list using method removeFromFront and deletes objects from the end of the list using method removeFromBack. After each insert and remove operation, ListTest calls List method print to display the current list contents. If an attempt is made to remove an item from an empty list, an EmptyListException (Fig. 17.4) is thrown, so the method calls to removeFromFront and removeFromBack are placed in a try block that is followed by an appropriate exception handler. Notice in lines 13, 15, 17 and 19 that the applications passes literal primitive int values to methods insertAtFront and insertAtBack, even though each of these methods was declared with a parameter of type Object (Fig. 17.3, lines 60 and 69). In this case, the JVM autoboxes each literal value in an Integer object and that object is actually inserted into the list. This, of course, is allowed because Object is an indirect superclass of Integer.

[Page 827]

[Page 828]

Now we discuss each method of class List (Fig. 17.3) in detail and provide diagrams showing the reference manipulations performed by methods insertAtFront, insertAtBack, removeFromFront and removeFromBack. Method insertAtFront (lines 6066 of Fig. 17.3) places a new node at the front of the list. The steps are:

1.Call isEmpty to determine whether the list is empty (line 62).

2.If the list is empty, assign firstNode and lastNode to the new ListNode that was initialized with insertItem (line 63). The ListNode constructor at lines 1316 calls the ListNode constructor at lines 2024 to set instance variable data to refer to the insertItem passed as an argument and to set reference nextNode to null, because this is the first and last node in the list.

3.If the list is not empty, the new node is "linked" into the list by setting firstNode to a new ListNode object and initializing that object with insertItem and firstNode (line 65). When the ListNode constructor (lines 2024) executes, it sets instance variable data to refer to the insertItem passed as an argument and performs the insertion by setting the nextNode reference of the new node to the ListNode passed as an argument, which previously was the first node.

In Fig. 17.6, part (a) shows a list and a new node during the insertAtFront operation and before the program links the new node into the list. The dotted arrows in part (b) illustrate Step 3 of the insertAtFront operation that enables the node containing 12 to become the new first node in the list.

Figure 17.6. Graphical representation of operation insertAtFront.

(This item is displayed on page 829 in the print version)

[View full size image]

Method insertAtBack (lines 6975 of Fig. 17.3) places a new node at the back of the list. The steps are:

1.Call isEmpty to determine whether the list is empty (line 71).

2.If the list is empty, assign firstNode and lastNode to the new ListNode that was initialized with insertItem (line 72). The ListNode constructor at lines 1316 calls the constructor at lines 2024 to set instance variable data to refer to the insertItem passed as an argument and to set reference nextNode to null.

[Page 829]

3.If the list is not empty, line 74 links the new node into the list by assigning to lastNode and lastNode.nextNode the reference to the new ListNode that was initialized with insertItem. ListNode's constructor (lines 1316), sets instance variable data to refer to the insertItem passed as an argument and sets reference nextNode to null, because this is the last node in the list.

In Fig. 17.7, part (a) shows a list and a new node during the insertAtBack operation and before the program links the new node into the list. The dotted arrows in part (b) illustrate Step 3 of method insertAtBack, which adds the new node to the end of a list that is not empty.

Figure 17.7. Graphical representation of operation insertAtBack.

[View full size image]

[Page 830]

Method removeFromFront (lines 7892 of Fig. 17.3) removes the first node of the list and returns a reference to the removed data. The method throws an EmptyListException (lines 8081) if the list is empty when the program calls this method. Otherwise, the method returns a reference to the removed data. The steps are:

1.Assign firstNode.data (the data being removed from the list) to reference removedItem (line 83).

2.If firstNode and lastNode refer to the same object (line 86), the list has only one element at this time. So, the method sets firstNode and lastNode to null (line 87) to remove the node from the list (leaving the list empty).

3.If the list has more than one node, then the method leaves reference lastNode as is and assigns the value of firstNode.nextNode to firstNode (line 89). Thus, firstNode references the node that was previously the second node in the list.

4.Return the removedItem reference (line 91).

In Fig. 17.8, part (a) illustrates the list before the removal operation. The dashed lines and arrows in part

(b) show the reference manipulations.

Figure 17.8. Graphical representation of operation removeFromFront.

[View full size image]

Method removeFromBack (lines 95118 of Fig. 17.3) removes the last node of a list and returns a reference to the removed data. The method throws an EmptyListException (lines 9798) if the list is empty when the program calls this method. The steps are:

1.Assign lastNode.data (the data being removed from the list) to removedItem (line 100).

[Page 831]

2.If the firstNode and lastNode refer to the same object (line 103), the list has only one element at this time. So, line 104 sets firstNode and lastNode to null to remove that node from the list (leaving the list empty).

3.If the list has more than one node, create the ListNode reference current and assign it firstNode (line 107).

4.Now "walk the list" with current until it references the node before the last node. The while loop (lines 110111) assigns current.nextNode to current as long as current.nextNode (the next node in the list) is not lastNode.

5.After locating the second-to-last node, assign current to lastNode (line 113) to update which node is last in the list.

6.Set the current.nextNode to null (line 114) to remove the last node from the list and terminate the list at the current node.

7.Return the removedItem reference (line 117).

In Fig. 17.9, part (a) illustrates the list before the removal operation. The dashed lines and arrows in part

(b) show the reference manipulations.

Figure 17.9. Graphical representation of operation removeFromBack.

[View full size image]

Method print (lines 127146) first determines whether the list is empty (lines 129133). If so, print displays a message indicating that the list is empty and returns control to the calling method. Otherwise, print outputs the list's data. Line 136 creates ListNode current and initializes it with firstNode. While current is not null, there are more items in the list. Therefore, line 141 outputs a string representation of current.data. Line 142 moves to the next node in the list by assigning the value of reference current.nextNode to current. This printing algorithm is identical for linked lists, stacks and queues.

[Page 832]

17.7. Stacks

A stack is a constrained version of a linked listnew nodes can be added to and removed from a stack only at the top. [Note: A stack does not have to be implemented using a linked list.] For this reason, a stack is referred to as a last-in, first-out (LIFO) data structure. The link member in the bottom (i.e., last) node of the stack is set to null to indicate the bottom of the stack.

The primary methods for manipulating a stack are of the stack. Method pop removes a node from the node.

push and pop. Method push adds a new node to the top top of the stack and returns the data from the popped

Stacks have many interesting applications. For example, when a program calls a method, the called method must know how to return to its caller, so the return address of the calling method is pushed onto the program execution stack. If a series of method calls occurs, the successive return addresses are pushed onto the stack in last-in, first-out order so that each method can return to its caller. Stacks support recursive method calls in the same manner as they do conventional nonrecursive method calls.

The program execution stack also contains the memory for local variables on each invocation of a method during a program's execution. When the method returns to its caller, the memory for that method's local variables is popped off the stack, and those variables are no longer known to the program. If the local variable is a reference, the reference count for the object to which it referred is decremented by 1. If the reference count becomes zero, the object can be garbage collected.

Compilers use stacks to evaluate arithmetic expressions and generate machine-language code to process the expressions. The exercises in this chapter explore several applications of stacks, including using them to develop a complete working compiler. Also, package java.util contains class Stack (see Chapter 19) for implementing and manipulating stacks that can grow and shrink during program execution.

We take advantage of the close relationship between lists and stacks to implement a stack class by reusing a list class. We demonstrate two different forms of reusability. First, we implement the stack class by extending class List of Fig. 17.3. Then we implement an identically performing stack class through composition by including a reference to a List object as a private instance variable of a stack class. The list, stack and queue data structures in this chapter are implemented to store Object references to encourage further reusability. Thus, any object type can be stored in a list, stack or queue.

Stack Class That Inherits from List

The application of Fig. 17.10 and Fig. 17.11 creates a stack class by extending class List of Fig. 17.3. We want the stack to have methods push, pop, isEmpty and print. Essentially, these are the methods insertAtFront, removeFromFront, isEmpty and print of class List. Of course, class List contains other methods (such as insertAtBack and removeFromBack) that we would rather not make accessible through the public interface to the stack class. It is important to remember that all methods in the public interface of class List class also are public methods of the subclass StackInheritance (Fig. 17.10). When we implement the stack's methods, we have each StackInheritance method call the appropriate List methodmethod push calls insertAtFront and method pop calls removeFromFront. Clients of class StackInheritance can call methods isEmpty and print because they are inherited from List. Class StackInheritance is declared as part of package com.deitel.jhtp6.ch17 for reuse purposes. Note that StackInheritance does not import List, because both classes are in the same package.

[Page 833]

Figure 17.10. StackInheritance extends class List.

1// Fig. 17.10: StackInheritance.java

2// Derived from class List.

3package com.deitel.jhtp6.ch17;

4

5public class StackInheritance extends List

6{

7// no-argument constructor

8public StackInheritance()

9{

10super ( "stack" );

11} // end StackInheritance no-argument constructor

13// add object to stack

14public void push( Object object )

15{

16insertAtFront( object );

17} // end method push

18

19// remove object from stack

20public Object pop() throws EmptyListException

21{

22return removeFromFront();

23} // end method pop

24} // end class StackInheritance

Figure 17.11. Stack manipulation program.

(This item is displayed on pages 833 - 834 in the print version)

1// Fig. 17.11: StackInheritanceTest.java

2// Class StackInheritanceTest.

3import com.deitel.jhtp6.ch17.StackInheritance;

4import com.deitel.jhtp6.ch17.EmptyListException;

6public class StackInheritanceTest

7{

8public static void main( String args[] )

9{

10StackInheritance stack = new StackInheritance();

12// use push method

13stack.push( -1 );

14stack.print();

15stack.push( 0 );

16stack.print();

17stack.push( 1 );

18stack.print();

19stack.push( 5 );

20stack.print();

22// remove items from stack

23try

24{

25Object removedObject = null;

27while ( true )

28{

29

removedObject = stack.pop(); // use pop method

30

System.out.printf( "%s popped\n", removedObject );

31

stack.print();

32} // end while

33} // end try

34catch ( EmptyListException emptyListException )

35{

36emptyListException.printStackTrace();

37} // end catch

38} // end main

39} // end class StackInheritanceTest

The stack is: -1

The stack is: 0 -1

The stack is: 1 0 -1

The stack is: 5 1 0 -1