Data Structures - Deekle.Net

102
21 Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved Data Structures OBJECTIVES In this chapter you will learn: To form linked data structures using pointers, self- referential classes and recursion. To create and manipulate dynamic data structures such as linked lists, queues, stacks and binary trees. To use binary search trees for high speed searching and sorting. To understand various important applications of linked data structures. To understand how to create reusable data structures with class templates, inheritance and composition. 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 on — keep moving. —Thomas Morton I’ll turn over a new leaf. —Miguel de Cervantes

Transcript of Data Structures - Deekle.Net

21

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

Data Structures

O B J E C T I V E SIn this chapter you will learn:

■ To form linked data structures using pointers, self-referential classes and recursion.

■ To create and manipulate dynamic data structures such as linked lists, queues, stacks and binary trees.

■ To use binary search trees for high speed searching and sorting.

■ To understand various important applications of linked data structures.

■ To understand how to create reusable data structures with class templates, inheritance and composition.

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 on — keep moving.—Thomas Morton

I’ll turn over a new leaf.—Miguel de Cervantes

cpphtp5_21_DataStructures_IM.fm Page 1238 Thursday, December 23, 2004 5:00 PM

Self-Review Exercises 1239

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

Self-Review Exercises21.1 Fill in the blanks in each of the following:

a) A self- class is used to form dynamic data structures that can grow andshrink at execution time.

ANS: referential.b) The operator is used to dynamically allocate memory and construct an ob-

ject; this operator returns a pointer to the object.ANS: new.c) 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 and node values are returned in last-in, first-out order.

ANS: stack.d) A function that does not alter a linked list, but looks at the list to determine whether it

is empty, is an example of a(n) function.ANS: predicate. e) A queue is referred to as a(n) data structure, because the first nodes inserted

are the first nodes removed.ANS: first-in, first-out (FIFO).f) The pointer to the next node in a linked list is referred to as a(n) . ANS: link. g) The operator is used to destroy an object and release dynamically allocated

memory.ANS: delete.h) 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.ANS: queue.i) A(n) is a nonlinear, two-dimensional data structure that contains nodes

with two or more links.ANS: tree.j) A stack is referred to as a(n) data structure, because the last node inserted

is the first node removed.ANS: last-in, first-out (LIFO).k) The nodes of a(n) tree contain two link members.ANS: binary.l) The first node of a tree is the node.ANS: root.m) Each link in a tree node points to a(n) or of that node.ANS: child or subtree.n) A tree node that has no children is called a(n) node.ANS: leaf.o) The four traversal algorithms we mentioned in the text for binary search trees are

, , and .ANS: inorder, preorder, postorder and level order.

21.2 What are the differences between a linked list and a stack?ANS: It is possible to insert a node anywhere in a linked list and remove a node from any-

where in a linked list. Nodes in a stack may only be inserted at the top of the stackand removed from the top of a stack.

cpphtp5_21_DataStructures_IM.fm Page 1239 Thursday, December 23, 2004 5:00 PM

1240 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.3 What are the differences between a stack and a queue?ANS: A queue data structure allows nodes to be removed only from the head of the queue

and inserted only at the tail of the queue. A queue is referred to as a first-in, first-out(FIFO) data structure. A stack data structure allows nodes to be added to the stackand removed from the stack only at the top. A stack is referred to as a last-in, first-out (LIFO) data structure.

21.4 Perhaps a more appropriate title for this chapter would have been “Reusable Data Struc-tures.” Comment on how each of the following entities or concepts contributes to the reusability ofdata structures:

a) classesANS: Classes allow us to instantiate as many data structure objects of a certain type (i.e.,

class) as we wish.b) class templatesANS: Class templates enable us to instantiate related classes, each based on different type

parameters—we can then generate as many objects of each template class as we like. c) inheritanceANS: Inheritance enables us to reuse code from a base class in a derived class, so that the de-

rived-class data structure is also a base-class data structure (with public inheritance, thatis).

d) private inheritanceANS: Private inheritance enables us to reuse portions of the code from a base class to form

a derived-class data structure; because the inheritance is private, all public base-classmember functions become private in the derived class. This enables us to preventclients of the derived-class data structure from accessing base-class member functionsthat do not apply to the derived class.

e) compositionANS: Composition enables us to reuse code by making a class object data structure a mem-

ber of a composed class; if we make the class object a private member of the com-posed class, then the class object’s public member functions are not available throughthe composed object’s interface.

21.5 Manually provide the inorder, preorder and postorder traversals of the binary search tree ofFig. 21.24.

ANS: The inorder traversal is

11 18 19 28 32 40 44 49 69 71 72 83 92 97 99

The preorder traversal is

49 28 18 11 19 40 32 44 83 71 69 72 97 92 99

Fig. 21.24 | A 15-node binary search tree.

49

28

18 40 71 97

83

11 19 32 44 69 72 92 99

cpphtp5_21_DataStructures_IM.fm Page 1240 Thursday, December 23, 2004 5:00 PM

Exercises 1241

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

The postorder traversal is

11 19 18 32 44 40 28 69 72 71 92 99 97 83 49

Exercises21.6 Write a program that concatenates two linked list objects of characters. The program shouldinclude function concatenate, which takes references to both list objects as arguments and concat-enates the second list to the first list.

ANS:

1 // Exercise 21.6 Solution: ListNode.h2 // ListNode class template definition3 #ifndef LISTNODE_H4 #define LISTNODE_H56 template< typename T > class List; // forward declaration78 template< typename NODETYPE >9 class ListNode

10 {11 friend class List< NODETYPE >; // make List a friend12 public:13 ListNode( const NODETYPE & ); // constructor14 NODETYPE getData() const; // return the data in the node1516 // set nextPtr to nPtr17 void setNextPtr( ListNode *nPtr ) 18 { 19 nextPtr = nPtr; 20 } // end function setNextPtr21 22 // return nextPtr23 ListNode *getNextPtr() const 24 { 25 return nextPtr; 26 } // end function getNextPtr2728 private:29 NODETYPE data; // data30 ListNode *nextPtr; // next node in the list31 }; // end class ListNode3233 // constructor34 template< typename NODETYPE >35 ListNode< NODETYPE >::ListNode( const NODETYPE &info )36 {37 data = info;38 nextPtr = 0;39 } // end constructor4041 // return a copy of the data in the node42 template< typename NODETYPE >43 NODETYPE ListNode< NODETYPE >::getData() const

cpphtp5_21_DataStructures_IM.fm Page 1241 Thursday, December 23, 2004 5:00 PM

1242 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

44 { 45 return data; 46 } // end function getData4748 #endif

1 // Exercise 21.6 Solution: List.h2 // List class template definition3 // Added copy constructor to member functions (not included in chapter).4 #ifndef LIST_H5 #define LIST_H67 #include <iostream> 8 using std::cout; 9

10 #include <new>11 #include "ListNode.h"1213 template< typename NODETYPE >14 class List 15 {16 public:17 List(); // default constructor18 List( const List< NODETYPE > & ); // copy constructor19 ~List(); // destructor2021 void insertAtFront( const NODETYPE & );22 void insertAtBack( const NODETYPE & );23 bool removeFromFront( NODETYPE & );24 bool removeFromBack( NODETYPE & );25 bool isEmpty() const;26 void print() const;27 protected:28 ListNode< NODETYPE > *firstPtr; // pointer to first node29 ListNode< NODETYPE > *lastPtr; // pointer to last node3031 // Utility function to allocate a new node32 ListNode< NODETYPE > *getNewNode( const NODETYPE & );33 }; // end class template List3435 // default constructor36 template< typename NODETYPE >37 List< NODETYPE >::List() 38 { 39 firstPtr = lastPtr = 0; 40 } // end constructor4142 // copy constructor43 template< typename NODETYPE >44 List< NODETYPE >::List( const List<NODETYPE> &copy )45 {46 firstPtr = lastPtr = 0; // initialize pointers4748 ListNode< NODETYPE > *currentPtr = copy.firstPtr;

cpphtp5_21_DataStructures_IM.fm Page 1242 Thursday, December 23, 2004 5:00 PM

Exercises 1243

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

4950 // insert into the list51 while ( currentPtr != 0 ) 52 {53 insertAtBack( currentPtr->data );54 currentPtr = currentPtr->nextPtr;55 } // end while56 } // end List copy constructor5758 // destructor59 template< typename NODETYPE >60 List< NODETYPE >::~List()61 {62 if ( !isEmpty() ) // List is not empty63 {64 cout << "Destroying nodes ...\n";6566 ListNode< NODETYPE > *currentPtr = firstPtr;67 ListNode< NODETYPE > *tempPtr;6869 while ( currentPtr != 0 ) // delete remaining nodes70 {71 tempPtr = currentPtr;72 cout << tempPtr->data << ' ';73 currentPtr = currentPtr->nextPtr;74 delete tempPtr;75 } // end while76 } // end if7778 cout << "\nAll nodes destroyed\n\n";79 } // end destructor8081 // Insert a node at the front of the list82 template< typename NODETYPE >83 void List< NODETYPE >::insertAtFront( const NODETYPE &value )84 {85 ListNode<NODETYPE> *newPtr = getNewNode( value );8687 if ( isEmpty() ) // List is empty88 firstPtr = lastPtr = newPtr;89 else // List is not empty90 {91 newPtr->nextPtr = firstPtr;92 firstPtr = newPtr;93 } // end else94 } // end function insertAtFront9596 // Insert a node at the back of the list97 template< typename NODETYPE >98 void List< NODETYPE >::insertAtBack( const NODETYPE &value )99 {100 ListNode< NODETYPE > *newPtr = getNewNode( value );101102 if ( isEmpty() ) // List is empty103 firstPtr = lastPtr = newPtr;

cpphtp5_21_DataStructures_IM.fm Page 1243 Thursday, December 23, 2004 5:00 PM

1244 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

104 else // List is not empty105 {106 lastPtr->nextPtr = newPtr;107 lastPtr = newPtr;108 } // end else109 } // end function insertAtBack110111 // Delete a node from the front of the list112 template< typename NODETYPE >113 bool List< NODETYPE >::removeFromFront( NODETYPE &value )114 {115 if ( isEmpty() ) // List is empty116 return false; // delete unsuccessful117 else 118 {119 ListNode< NODETYPE > *tempPtr = firstPtr;120121 if ( firstPtr == lastPtr )122 firstPtr = lastPtr = 0;123 else124 firstPtr = firstPtr->nextPtr;125126 value = tempPtr->data; // data being removed127128 delete tempPtr;129 return true; // delete successful130 } // end else131 } // end function removeFromFront132133 // delete a node from the back of the list134 template< typename NODETYPE >135 bool List< NODETYPE >::removeFromBack( NODETYPE &value )136 {137 if ( isEmpty() )138 return false; // delete unsuccessful139 else 140 {141 ListNode< NODETYPE > *tempPtr = lastPtr;142143 if ( firstPtr == lastPtr )144 firstPtr = lastPtr = 0;145 else 146 {147 ListNode< NODETYPE > *currentPtr = firstPtr;148149 while ( currentPtr->nextPtr != lastPtr )150 currentPtr = currentPtr->nextPtr;151152 lastPtr = currentPtr;153 currentPtr->nextPtr = 0;154 } // end else155156 value = tempPtr->data;157 delete tempPtr;158 return true; // delete successful

cpphtp5_21_DataStructures_IM.fm Page 1244 Thursday, December 23, 2004 5:00 PM

Exercises 1245

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

159 } // end else160 } // end function removeFromBack161162 // Is the List empty?163 template< typename NODETYPE >164 bool List< NODETYPE >::isEmpty() const 165 { 166 return firstPtr == 0; 167 } // end function isEmpty168169 // Return a pointer to a newly allocated node170 template< typename NODETYPE >171 ListNode< NODETYPE > *List< NODETYPE >::getNewNode( 172 const NODETYPE &value )173 {174 ListNode< NODETYPE > *ptr = new ListNode< NODETYPE >( value );175 return ptr;176 } // end function getNewNode177178 // Display the contents of the List179 template< typename NODETYPE >180 void List< NODETYPE >::print() const181 {182 if ( isEmpty() ) // empty list183 {184 cout << "The list is empty\n\n";185 return;186 } // end if187188 ListNode< NODETYPE > *currentPtr = firstPtr;189190 cout << "The list is: ";191192 while ( currentPtr != 0 ) // display elements in list193 {194 cout << currentPtr->data << ' ';195 currentPtr = currentPtr->nextPtr;196 } // end while197198 cout << "\n\n";199 } // end function print200201 #endif

1 // Exercise 21.6 solution: Ex21_06.cpp2 #include <iostream> 3 using std::cout; 45 #include "List.h"67 template< typename T >8 void concatenate( List< T > &first, List< T > &second )9 {

10 List< T > temp( second ); // create a copy of second

cpphtp5_21_DataStructures_IM.fm Page 1245 Thursday, December 23, 2004 5:00 PM

1246 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

11 T value; // variable to store removed item from temp1213 while ( !temp.isEmpty() ) 14 {15 temp.removeFromFront( value ); // remove value from temp list16 first.insertAtBack( value ); // insert at end of first list17 } // end loop18 } // end function concatenate1920 int main()21 {22 List< char > list1; // storage for first list23 List< char > list2; // storage for second list24 char c;2526 // assign alphabets into first list, from a to e 27 for ( c = 'a'; c <= 'e'; c++ )28 list1.insertAtBack( c );2930 // call function print to print the list31 list1.print();3233 // assign from f to j into second list34 for ( c = 'f'; c <= 'j'; c++ )35 list2.insertAtBack( c );3637 list2.print();3839 // function concatenate will append list2 with list140 concatenate( list1, list2 );41 cout << "The new list1 after concatenation is:\n";42 list1.print();43 return 0; // indicates successful termination44 } // end main

The list is: a b c d e

The list is: f g h i j

All nodes destroyed

The new list1 after concatenation is:The list is: a b c d e f g h i j

Destroying nodes ...f g h i jAll nodes destroyed

Destroying nodes ...a b c d e f g h i jAll nodes destroyed

cpphtp5_21_DataStructures_IM.fm Page 1246 Thursday, December 23, 2004 5:00 PM

Exercises 1247

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.7 Write a program that merges two ordered list objects of integers into a single ordered listobject of integers. Function merge should receive references to each of the list objects to be mergedand reference to a list object into which the merged elements will be placed.

ANS: [Note: The solution to this exercise uses List.h and ListNode.h from Exercise 21.6.]

1 // Exercise 21.7 solution: Ex21_07.cpp2 #include <iostream> 3 using std::cout; 45 #include "List.h"67 template< typename T >8 void merge( List< T > &first, List< T > &second, List< T > &result )9 {

10 List< T > tempFirst( first ); // create a copy of first11 List< T > tempSecond( second ); // create a copy of second12 T value1;13 T value2;1415 tempFirst.removeFromFront( value1 );16 tempSecond.removeFromFront( value2 );1718 while ( !tempFirst.isEmpty() && !tempSecond.isEmpty() ) 19 {20 if ( value1 <= value2 ) 21 {22 result.insertAtBack( value1 );23 tempFirst.removeFromFront( value1 );24 } // end if25 else 26 {27 result.insertAtBack( value2 );28 tempSecond.removeFromFront( value2 );29 } // end else30 } // end while3132 // Insert the values currently in value1 and value233 if ( value1 < value2 ) 34 {35 result.insertAtBack( value1 );36 result.insertAtBack( value2 );37 } // end if38 else 39 {40 result.insertAtBack( value2 );41 result.insertAtBack( value1 );42 } // end else4344 // Complete the insertion of the list that is not empty.45 // NOTE: Only one of the following 2 while statements will execute46 // because one of the lists must be empty to exit the preceding while47 if ( !tempFirst.isEmpty() ) // items left in tempFirst48 {49 do

cpphtp5_21_DataStructures_IM.fm Page 1247 Thursday, December 23, 2004 5:00 PM

1248 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

50 {51 tempFirst.removeFromFront( value1 );52 result.insertAtBack( value2 );53 } while ( !tempFirst.isEmpty() );54 } // end if55 else // items left in tempSecond56 {57 do 58 {59 tempSecond.removeFromFront( value2 );60 result.insertAtBack( value2 );61 } while ( !tempSecond.isEmpty() );62 } // end else63 } // end function merge6465 int main()66 {67 List< int > list1;68 List< int > list2;69 List< int > result;70 int i;7172 for ( i = 1; i <= 9; i += 2 )73 list1.insertAtBack( i );7475 list1.print();7677 for ( i = 2; i <= 10; i += 2 )78 list2.insertAtBack( i );7980 list2.print();8182 merge( list1, list2, result );83 84 cout << "The merged list is:\n";85 result.print();86 return 0; // indicates successful termination87 } // end main

cpphtp5_21_DataStructures_IM.fm Page 1248 Thursday, December 23, 2004 5:00 PM

Exercises 1249

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.8 Write a program that inserts 25 random integers from 0 to 100 in order in a linked list ob-ject. The program should calculate the sum of the elements and the floating-point average of theelements.

ANS: [Note: The solution to this exercise uses List.h and ListNode.h from Exercise 21.6.]

The list is: 1 3 5 7 9

The list is: 2 4 6 8 10

All nodes destroyed

All nodes destroyed

The merged list is:The list is: 1 2 3 4 5 6 7 8 9 10

Destroying nodes ...1 2 3 4 5 6 7 8 9 10All nodes destroyed

Destroying nodes ...2 4 6 8 10All nodes destroyed

Destroying nodes ...1 3 5 7 9All nodes destroyed

1 // Exercise 21.8 Solution: List2.h2 // List2 class template definition3 // Enhances List by adding insertInOrder.4 #ifndef LIST2_H5 #define LIST2_H67 #include "ListNode.h"8 #include "List.h"9

10 template< typename NODETYPE >11 class List2 : public List< NODETYPE > 12 {13 public:14 void insertInOrder( const NODETYPE & );15 }; // end class List21617 // insert a node in order18 template< typename NODETYPE >19 void List2< NODETYPE >::insertInOrder( const NODETYPE &value )20 {21 if ( isEmpty() ) // list is empty22 {23 ListNode< NODETYPE > *newPtr = getNewNode( value );24 firstPtr = lastPtr = newPtr;

cpphtp5_21_DataStructures_IM.fm Page 1249 Thursday, December 23, 2004 5:00 PM

1250 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

25 } // end if26 else // list is not empty27 {28 if ( firstPtr->getData() > value ) // value is the smallest29 insertAtFront( value );30 else if ( lastPtr->getData() < value ) // value is the largest31 insertAtBack( value );32 else 33 {34 ListNode< NODETYPE > *currentPtr = firstPtr->getNextPtr();35 ListNode< NODETYPE > *previousPtr = firstPtr;36 ListNode< NODETYPE > *newPtr = getNewNode( value );3738 while ( currentPtr != lastPtr && currentPtr->getData() < value )39 {40 previousPtr = currentPtr;41 currentPtr = currentPtr->getNextPtr();42 } // end while4344 previousPtr->setNextPtr( newPtr );45 newPtr->setNextPtr( currentPtr );46 } // end else47 } // end else48 } // end function insertInOrder4950 #endif

1 // Exercise 21.8 solution: Ex21_08.cpp2 #include <iostream> 3 using std::cout; 45 #include <cstdlib>6 using std::rand;7 using std::srand;89 #include <ctime>

10 using std::time;1112 #include "List2.h"1314 // integer specific list sum15 int sumList( List2< int > &listRef )16 {17 List2< int > temp( listRef );18 int sum = 0;19 int value;2021 // until temp is empty22 while ( !temp.isEmpty() ) 23 {24 temp.removeFromFront( value ); // remove from the front25 sum += value; // add value to sum26 } // end while27

cpphtp5_21_DataStructures_IM.fm Page 1250 Thursday, December 23, 2004 5:00 PM

Exercises 1251

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

28 return sum;29 } // end function sumList3031 // integer specific list average32 double aveList( List2< int > &listRef )33 {34 List2< int > temp( listRef );35 int sum = 0;36 int value;37 int count = 0;3839 // go through copy of listRef40 while ( !temp.isEmpty() ) 41 {42 temp.removeFromFront( value ); // remove each element43 count++; // increment the count44 sum += value; // add into sum45 } // end while4647 // return the average48 return static_cast< double >( sum ) / count;49 } // end function aveList5051 int main()52 {53 srand( time( 0 ) ); // randomize the random number generator54 55 List2< int > intList;5657 // fill intList with 25 random numbers58 for ( int i = 1; i <= 25; i++ )59 intList.insertInOrder( rand() % 101 );6061 intList.print();6263 int sum = sumList( intList ); // calculate sum64 double average = aveList( intList ); // calculate average6566 cout << "The sum of the elements is: " << sum << '\n';67 cout << "The average of the elements is: " << average << '\n';68 return 0; // indicates successful termination69 } // end main

cpphtp5_21_DataStructures_IM.fm Page 1251 Thursday, December 23, 2004 5:00 PM

1252 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.9 Write a program that creates a linked list object of 10 characters and creates a second listobject containing a copy of the first list, but in reverse order.

ANS: [Note: The solution to this exercise uses List.h and ListNode.h from Exercise 21.6.]

The list is: 2 4 14 23 31 33 33 36 43 52 53 56 56 67 73 76 81 81 82 83 90 93 95 98 98

All nodes destroyed

All nodes destroyed

The sum of the elements is: 1453The average of the elements is: 58.12Destroying nodes ...2 4 14 23 31 33 33 36 43 52 53 56 56 67 73 76 81 81 82 83 90 93 95 98 98All nodes destroyed

1 // Exercise 21.9 solution: Ex21_09.cpp2 #include <iostream> 3 using std::cout; 45 #include "List.h"67 // function template that takes two List objects as arguments8 // and makes a copy of the second argument reversed in the first argument.9 template< typename T >

10 void reverseList( List< T > &first, List< T > &second )11 {12 List< T > temp( second ); // create a copy of second 13 T value; // variable to store removed item from temp1415 // loop through the list until it is empty16 while ( !temp.isEmpty() ) 17 {18 temp.removeFromFront( value ); // remove value from temp list19 first.insertAtFront( value ); // insert at beginning of first list20 } // end while21 } // end reverseList template function2223 int main()24 {25 List< char > list1;26 List< char > list2;2728 // insert a - g onto list129 for ( char c = 'a'; c <= 'g'; c++ )30 list1.insertAtBack( c );3132 list1.print(); // print list33 reverseList( list2, list1 ); // call to function reverseList34

cpphtp5_21_DataStructures_IM.fm Page 1252 Thursday, December 23, 2004 5:00 PM

Exercises 1253

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.10 Write a program that inputs a line of text and uses a stack object to print the line reversed.ANS: [Note: The solution to this exercise uses List.h, ListNode.h and Stack.h from the

chapter (Figs. 21.3–21.4 and Fig. 21.13).]

35 cout << "The list after reversing:\n";36 list2.print(); // print list37 return 0; // indicates successful termination38 } // end main

The list is: a b c d e f g

All nodes destroyed

The list after reversing:The list is: g f e d c b a

Destroying nodes ...g f e d c b aAll nodes destroyed

Destroying nodes ...a b c d e f gAll nodes destroyed

1 // Exercise 21.10 solution: Ex21_10.cpp2 #include <iostream> 3 using std::cin; 4 using std::cout;56 #include "Stack.h"78 int main()9 {

10 Stack< char > charStack; // a stack of char11 char c; // represent a character from the input stream1213 cout << "Enter a sentence:\n";1415 // push onto stack until a null terminator is reached16 while ( ( c = static_cast< char >( cin.get() ) ) != '\n' )17 charStack.push( c );1819 cout << "\nThe sentence in reverse is:\n";2021 while ( !charStack.isStackEmpty() )22 {23 charStack.pop( c );24 cout << c << ' ';25 } // end while2627 cout << '\n';28 return 0; // indicates successful termination

cpphtp5_21_DataStructures_IM.fm Page 1253 Thursday, December 23, 2004 5:00 PM

1254 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.11 Write a program that uses a stack object to determine if a string is a palindrome (i.e., thestring is spelled identically backward and forward). The program should ignore spaces and punc-tuation.

ANS: [Note: The solution to this exercise uses List.h, ListNode.h and Stack.h from thechapter (Figs. 21.3–21.4 and Fig. 21.13).]

29 } // end main

Enter a sentence:Hello World!

The sentence in reverse is:! d l r o W o l l e HAll nodes destroyed

1 // Exercise 21.11 Solution: Ex21_11.cpp2 #include <iostream> 3 using std::cin;4 using std::cout; 56 #include <ctype>7 using std::isalpha;89 #include "Stack.h"

1011 int main()12 {13 Stack< char > charStack;14 char c;15 char string1[ 80 ];16 char string2[ 80 ];17 int i = 0;1819 cout << "Enter a sentence:\n";20 21 // get input 22 while ( ( c = static_cast< char >( cin.get() ) ) != '\n' )23 {24 if ( isalpha( c ) ) 25 {26 string1[ i++ ] = c;27 charStack.push( c );28 } // end if29 } // end while3031 string1[ i ] = '\0';32 i = 0;3334 // get stack elements35 while ( !charStack.isStackEmpty() )36 charStack.pop( string2[ i++ ] );3738 string2[ i ] = '\0';

cpphtp5_21_DataStructures_IM.fm Page 1254 Thursday, December 23, 2004 5:00 PM

Exercises 1255

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.12 Stacks are used by compilers to help in the process of evaluating expressions and generatingmachine language code. In this and the next exercise, we investigate how compilers evaluate arith-metic expressions consisting only of constants, operators and parentheses.

Humans generally write expressions like 3 + 4 and 7 / 9 in which the operator (+ or / here) iswritten between its operands—this is called infix notation. Computers “prefer” postfix notation inwhich the operator is written to the right of its two operands. The preceding infix expressionswould appear in postfix notation as 3 4 + and 7 9 /, respectively.

To evaluate a complex infix expression, a compiler would first convert the expression to post-fix notation and evaluate the postfix version of the expression. Each of these algorithms requiresonly a single left-to-right pass of the expression. Each algorithm uses a stack object in support of itsoperation, and in each algorithm the stack is used for a different purpose.

In this exercise, you will write a C++ version of the infix-to-postfix conversion algorithm. Inthe next exercise, you will write a C++ version of the postfix expression evaluation algorithm. Laterin the chapter, you will discover that code you write in this exercise can help you implement a com-plete working compiler.

Write a program that converts an ordinary infix arithmetic expression (assume a validexpression is entered) with single-digit integers such as

(6 + 2) * 5 - 8 / 4

to a postfix expression. The postfix version of the preceding infix expression is

6 2 + 5 * 8 4 / -

The program should read the expression into character array infix and use modified versions ofthe stack functions implemented in this chapter to help create the postfix expression in characterarray postfix. The algorithm for creating a postfix expression is as follows:

1) Push a left parenthesis '(' onto the stack.2) Append a right parenthesis ')' to the end of infix.3) While the stack is not empty, read infix from left to right and do the following:

If the current character in infix is a digit, copy it to the next element of postfix.If the current character in infix is a left parenthesis, push it onto the stack.If the current character in infix is an operator,

Pop operators (if there are any) at the top of the stack while they have equal orhigher precedence than the current operator, and insert the popped operators in postfix.

Push the current character in infix onto the stack.

3940 if ( strcmp( string1, string2 ) == 0 )41 cout << "\nThe sentence is a palindrome\n";42 else43 cout << "\nThe sentence is not a palindrome\n";4445 return 0; // indicates successful termination46 } // end main

Enter a sentence:oat y tao

The sentence is a palindromeAll nodes destroyed

cpphtp5_21_DataStructures_IM.fm Page 1255 Thursday, December 23, 2004 5:00 PM

1256 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

If the current character in infix is a right parenthesisPop operators from the top of the stack and insert them in postfix until a left

parenthesis is at the top of the stack.Pop (and discard) the left parenthesis from the stack.

The following arithmetic operations are allowed in an expression:+ addition- subtraction* multiplication/ division^ exponentiation% modulus

[Note: We assume left to right associativity for all operators for the purpose of this exercise.] Thestack should be maintained with stack nodes, each containing a data member and a pointer to thenext stack node.

Some of the functional capabilities you may want to provide are:a) function convertToPostfix that converts the infix expression to postfix notationb) function isOperator that determines whether c is an operatorc) function precedence that determines whether the precedence of operator1 is less than,

equal to or greater than the precedence of operator2 (the function returns –1, 0 and 1,respectively)

d) function push that pushes a value onto the stacke) function pop that pops a value off the stackf) function stackTop that returns the top value of the stack without popping the stackg) function isEmpty that determines if the stack is emptyh) function printStack that prints the stackANS:

1 // Exercise 21.12 Solution: StackNode.h2 // Definition of class template StackNode.3 #ifndef STACKNODE_H4 #define STACKNODE_H56 template< typename T > class Stack; // forward declaration78 template < typename T >9 class StackNode

10 {11 friend class Stack< T >;12 public:13 StackNode( const T & = 0, StackNode * = 0 );14 T getData() const;1516 // set point to next stack node17 void setNextPtr( StackNode *nPtr ) 18 { 19 nextPtr = nPtr; 20 } // end function setNextPtr21 22 // get point to next stack node23 StackNode *getNextPtr() const 24 { 25 return nextPtr;

cpphtp5_21_DataStructures_IM.fm Page 1256 Thursday, December 23, 2004 5:00 PM

Exercises 1257

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

26 } // end function getNextPtr2728 private:29 T data;30 StackNode *nextPtr;31 }; // end class StackNode3233 // member-function definitions for class StackNode34 // constructor35 template < typename T >36 StackNode< T >::StackNode( const T &d, StackNode< T > *ptr )37 {38 data = d;39 nextPtr = ptr;40 } // end constructor4142 // get data43 template < typename T >44 T StackNode< T >::getData() const 45 { 46 return data; 47 } // end function getData4849 #endif

1 // Exercise 21.12 Solution: Stack.h2 // Definition of class template Stack.3 // NOTE: This Stack class is a standalone Stack class template.4 #ifndef STACK_H5 #define STACK_H67 #include <iostream> 8 using std::cout; 9

10 #include <new>11 #include "StackNode.h"1213 template < typename T >14 class Stack 15 {16 public:17 Stack(); // default constructor18 ~Stack(); // destructor1920 void push( T & ); // insert item in stack21 T pop(); // remove item from stack22 bool isEmpty() const; // is the stack empty?23 T stackTop() const; // check the top value24 void print() const; // output the stack2526 // return pointer to first stack node27 StackNode< T > *getTopPtr() const 28 { 29 return topPtr;

cpphtp5_21_DataStructures_IM.fm Page 1257 Thursday, December 23, 2004 5:00 PM

1258 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

30 } // end function getTopPtr3132 private:33 StackNode< T > *topPtr; // pointer to fist StackNode34 }; // end class template Stack3536 // member-function definitions for class template Stack37 template < typename T >38 Stack< T >::Stack() 39 { 40 topPtr = 0; 41 } // end constructor4243 template < typename T >44 Stack< T >::~Stack()45 {46 StackNode< T > *tempPtr, *currentPtr = topPtr;4748 while ( currentPtr != 0 ) 49 {50 tempPtr = currentPtr;51 currentPtr = currentPtr->getNextPtr();52 delete tempPtr;53 } // end while54 } // end destructor5556 // push node57 template < typename T >58 void Stack< T >::push( T &d )59 {60 StackNode< T > *newPtr = new StackNode< T >( d, topPtr );61 topPtr = newPtr;62 } // end function push6364 // pop node65 template < typename T >66 T Stack< T >::pop()67 {68 StackNode< T > *tempPtr = topPtr;6970 topPtr = topPtr->nextPtr;71 T poppedValue = tempPtr->data;72 delete tempPtr;73 return poppedValue;74 } // end function pop7576 // is the stack empty?77 template < typename T >78 bool Stack< T >::isEmpty() const 79 { 80 return topPtr == 0; 81 } // end function isEmpty 8283 // get the top node84 template < typename T >

cpphtp5_21_DataStructures_IM.fm Page 1258 Thursday, December 23, 2004 5:00 PM

Exercises 1259

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

85 T Stack< T >::stackTop() const 86 { 87 return !isEmpty() ? getTopPtr()->getData() : static_cast< T >( 0 );88 } // end function stackTop8990 // display the stack91 template < typename T >92 void Stack< T >::print() const93 {94 StackNode< T > *currentPtr = topPtr;9596 if ( isEmpty() ) // Stack is empty97 cout << "Stack is empty\n";98 else // Stack is not empty99 {100 cout << "The stack is:\n";101102 while ( currentPtr != 0 ) 103 {104 cout << currentPtr->data << ' ';105 currentPtr = currentPtr->nextPtr;106 } // end while107108 cout << '\n';109 } // end else110 } // end function print111112 #endif

1 // Exercise 21.12 Solution: Ex21_12.cpp2 // Infix to postfix conversion3 #include <iostream> 4 using std::cin;5 using std::cout; 6 using std::endl;78 #include <ctype>9 using std::isdigit;

1011 #include "Stack.h"1213 // function prototype14 void convertToPostfix( char * const, char * const );15 bool isOperator( char );16 bool precedence( char, char );1718 int main()19 {20 const int MAXSIZE = 100;21 char c;22 char inFix[ MAXSIZE ];23 char postFix[ MAXSIZE ];24 int pos = 0;25

cpphtp5_21_DataStructures_IM.fm Page 1259 Thursday, December 23, 2004 5:00 PM

1260 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

26 cout << "Enter the infix expression.\n";2728 // get input29 while ( ( c = static_cast< char >( cin.get() ) ) != '\n' )3031 if ( c != ' ' )32 inFix[ pos++ ] = c;3334 inFix[ pos ] = '\0';3536 cout << "The original infix expression is:\n" << inFix << '\n';3738 // change from infix notation into postfix notation39 convertToPostfix( inFix, postFix );4041 cout << "The expression in postfix notation is:\n" << postFix << endl;42 return 0; // indicates successful termination43 } // end main 4445 // take out the infix and change it into postfix46 void convertToPostfix( char * const infix, char * const postfix )47 {48 Stack< char > charStack;49 int infixCount;50 int postfixCount;51 bool higher;52 char popValue;53 char leftParen = '(';5455 // push a left paren onto the stack and add a right paren to infix56 charStack.push( leftParen );57 charStack.print();58 strcat( infix, ")" );5960 // convert the infix expression to postfix61 for ( infixCount = 0, postfixCount = 0; charStack.stackTop(); 62 infixCount++ ) 63 {64 if ( isdigit( infix[ infixCount ] ) )65 postfix[ postfixCount++ ] = infix[ infixCount ];66 else if ( infix[ infixCount ] == '(' ) 67 {68 charStack.push( leftParen );69 charStack.print();70 } // end else if71 else if ( isOperator( infix[ infixCount ] ) ) 72 {73 higher = true; // used to store value of precedence test7475 while ( higher ) 76 {77 if ( isOperator( charStack.stackTop() ) )78 {79 if ( precedence( charStack.stackTop(), 80 infix[ infixCount ] ) )

cpphtp5_21_DataStructures_IM.fm Page 1260 Thursday, December 23, 2004 5:00 PM

Exercises 1261

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

81 {82 postfix[ postfixCount++ ] = charStack.pop();83 charStack.print();84 } // end if85 else 86 higher = false;87 } // end if88 else89 higher = false;90 } // end while9192 charStack.push( infix[ infixCount ] );93 charStack.print();94 } // end else if95 else if ( infix[ infixCount ] == ')' ) 96 {97 while ( ( popValue = charStack.pop() ) != '(' ) 98 {99 charStack.print();100 postfix[ postfixCount++ ] = popValue;101 } // end while102103 charStack.print();104 } // end else if105 } // end for106107 postfix[ postfixCount ] = '\0';108 } // end function convertToPostfix109110 // check if c is an operator111 bool isOperator( char c )112 {113 if ( c == '+' || c == '-' || c == '*' || c == '/' || c == '^' )114 return true;115 else116 return false;117 } // end function isOperator118119 // ensure proper order of operations120 bool precedence( char operator1, char operator2 )121 {122 if ( operator1 == '^' )123 return true;124 else if ( operator2 == '^' )125 return false;126 else if ( operator1 == '*' || operator1 == '/' )127 return true;128 else if ( operator1 == '+' || operator1 == '-' )129 {130 if ( operator2 == '*' || operator2 == '/' )131 return false;132 else133 return true;134 } // end else if135

cpphtp5_21_DataStructures_IM.fm Page 1261 Thursday, December 23, 2004 5:00 PM

1262 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.13 Write a program that evaluates a postfix expression (assume it is valid) such as

6 2 + 5 * 8 4 / -

The program should read a postfix expression consisting of digits and operators into a characterarray. Using modified versions of the stack functions implemented earlier in this chapter, the pro-gram should scan the expression and evaluate it. The algorithm is as follows:

1) Append the null character ('\0') to the end of the postfix expression. When the nullcharacter is encountered, no further processing is necessary.

2) While '\0' has not been encountered, read the expression from left to right.If the current character is a digit,

Push its integer value onto the stack (the integer value of a digit character is its value in the computer’s character set minus the value of '0' in the computer’s character set).

Otherwise, if the current character is an operator,Pop the two top elements of the stack into variables x and y.Calculate y operator x.Push the result of the calculation onto the stack.

3) When the null character is encountered in the expression, pop the top value of the stack.This is the result of the postfix expression.

136 return false;137 } // end function precedence

Enter the infix expression.(6 + 2) * 5 - 8 / 4The original infix expression is:(6+2)*5-8/4The stack is:(The stack is:( (The stack is:+ ( (The stack is:( (The stack is:(The stack is:* (The stack is:(The stack is:- (The stack is:/ - (The stack is:- (The stack is:(Stack is emptyThe expression in postfix notation is:62+5*84/-

cpphtp5_21_DataStructures_IM.fm Page 1262 Thursday, December 23, 2004 5:00 PM

Exercises 1263

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

[Note: In Step 2 above, if the operator is '/', the top of the stack is 2 and the next element in thestack is 8, then pop 2 into x, pop 8 into y, evaluate 8 / 2 and push the result, 4, back onto the stack.This note also applies to operator '–'.] The arithmetic operations allowed in an expression are

+ addition– subtraction* multiplication/ division^ exponentiation% modulus

[Note: We assume left to right associativity for all operators for the purpose of this exercise.] Thestack should be maintained with stack nodes that contain an int data member and a pointer to thenext stack node. You may want to provide the following functional capabilities:

a) function evaluatePostfixExpression that evaluates the postfix expressionb) function calculate that evaluates the expression op1 operator op2c) function push that pushes a value onto the stackd) function pop that pops a value off the stacke) function isEmpty that determines if the stack is emptyf) function printStack that prints the stackANS: [Note: The solution to this exercises uses Stack.h and StackNode.h from

Exercise 21.12.]

1 // Exercise 21.13 Solution: Ex21_13.cpp2 // Using a stack to evaluate an expression in postfix notation3 #include <iostream> 4 using std::cin;5 using std::cout; 6 using std::endl;78 #include <ctype>9 using std::isdigit;

1011 #include <cmath>12 using std::pow;1314 #include "Stack.h"1516 // prototype17 int evaluatePostfixExpression( char * const );18 int calculate( int, int, char );1920 int main()21 {22 char expression[ 100 ];23 char c;24 int answer;25 int i = 0;2627 cout << "Enter a postfix expression:\n";2829 // get input30 while ( ( c = static_cast< char >( cin.get() ) ) != '\n')31

cpphtp5_21_DataStructures_IM.fm Page 1263 Thursday, December 23, 2004 5:00 PM

1264 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

32 if ( c != ' ' )33 expression[ i++ ] = c;34 35 expression[ i ] = '\0';36 answer = evaluatePostfixExpression( expression );37 cout << "The value of the expression is: " << answer << endl;38 return 0; // indicates successful termination39 } // end main4041 // evaluate the postfix notation42 int evaluatePostfixExpression( char * const expr )43 {44 int i;45 int popVal1;46 int popVal2;47 int pushVal;48 Stack< int > intStack;49 char c;50 51 strcat( expr, ")" );52 53 // until it reaches ")"54 for ( i = 0; ( c = expr[ i ] ) != ')'; i++ )55 {56 if ( isdigit( expr[ i ] ) ) 57 {58 pushVal = c - '0';59 intStack.push( pushVal );60 intStack.print();61 } // end if62 else 63 {64 popVal2 = intStack.pop();65 intStack.print();66 popVal1 = intStack.pop();67 intStack.print();68 pushVal = calculate( popVal1, popVal2, expr[ i ] );69 intStack.push( pushVal );70 intStack.print();71 } // end else72 } // end for73 74 return intStack.pop();75 } // end evaluatePostfixExpression7677 // do the calculation78 int calculate( int op1, int op2, char oper )79 {80 switch( oper ) 81 {82 case '+':83 return op1 + op2;84 case '-':85 return op1 - op2;86 case '*':

cpphtp5_21_DataStructures_IM.fm Page 1264 Thursday, December 23, 2004 5:00 PM

Exercises 1265

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.14 Modify the postfix evaluator program of Exercise 21.13 so that it can process integer oper-ands larger than 9.

21.15 (Supermarket Simulation) Write a program that simulates a checkout line at a supermarket.The line is a queue object. Customers (i.e., customer objects) arrive in random integer intervals of1–4 minutes. Also, each customer is served in random integer intervals of 1–4 minutes. Obviously,the rates need to be balanced. If the average arrival rate is larger than the average service rate, thequeue will grow infinitely. Even with “balanced” rates, randomness can still cause long lines. Runthe supermarket simulation for a 12-hour day (720 minutes) using the following algorithm:

87 return op1 * op2;88 case '/':89 return op1 / op2;90 case '^': // exponentiation91 return static_cast< int >( 92 pow( static_cast< float >( op1 ), op2 ) );93 } // end switch statement9495 return 0;96 } // end function calculate

Enter a postfix expression:6 2 + 5 * 8 4 / -The stack is:6The stack is:2 6The stack is:6Stack is emptyThe stack is:8The stack is:5 8The stack is:8Stack is emptyThe stack is:40The stack is:8 40The stack is:4 8 40The stack is:8 40The stack is:40The stack is:2 40The stack is:40Stack is emptyThe stack is:38The value of the expression is: 38

cpphtp5_21_DataStructures_IM.fm Page 1265 Thursday, December 23, 2004 5:00 PM

1266 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

1) Choose a random integer between 1 and 4 to determine the minute at which the firstcustomer arrives.

2) At the first customer’s arrival time:Determine customer’s service time (random integer from 1 to 4);Begin servicing the customer;Schedule arrival time of next customer (random integer 1 to 4 added to the currenttime).

3) For each minute of the day:If the next customer arrives,

Say so,Enqueue the customer;Schedule the arrival time of the next customer;

If service was completed for the last customer;Say soDequeue next customer to be servicedDetermine customer’s service completion time

(random integer from 1 to 4 added to the current time).

Now run your simulation for 720 minutes, and answer each of the following:a) What is the maximum number of customers in the queue at any time?b) What is the longest wait any one customer experiences?c) What happens if the arrival interval is changed from 1–4 minutes to 1–3 minutes?

21.16 Modify the program of Figs. 21.20–21.22 to allow the binary tree object to contain dupli-cates.

ANS: [Note: The solution to this exercise uses TreeNode.h in Fig. 21.20.]

1 // Exercise 21.16: Tree.h2 // Tree class template definition.3 #ifndef TREE_H4 #define TREE_H56 #include <iostream>7 using std::cout;8 using std::endl;9

10 #include "Treenode.h"1112 // Tree class-template definition13 template< typename NODETYPE > class Tree14 {15 public:16 Tree(); // constructor17 void insertNode( const NODETYPE & );18 void preOrderTraversal() const; 19 void inOrderTraversal() const; 20 void postOrderTraversal() const; 21 private:22 TreeNode< NODETYPE > *rootPtr;2324 // utility functions 25 void insertNodeHelper( TreeNode< NODETYPE > **, const NODETYPE & );26 void preOrderHelper( TreeNode< NODETYPE > * ) const;

cpphtp5_21_DataStructures_IM.fm Page 1266 Thursday, December 23, 2004 5:00 PM

Exercises 1267

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

27 void inOrderHelper( TreeNode< NODETYPE > * ) const; 28 void postOrderHelper( TreeNode< NODETYPE > * ) const; 29 }; // end class Tree3031 // constructor32 template< typename NODETYPE >33 Tree< NODETYPE >::Tree() 34 { 35 rootPtr = 0; // indicate tree is initially empty36 } // end Tree constructor3738 // insert node in Tree39 template< typename NODETYPE >40 void Tree< NODETYPE >::insertNode( const NODETYPE &value )41 { 42 insertNodeHelper( &rootPtr, value ); 43 } // end function insertNode4445 // utility function called by insertNode; receives a pointer46 // to a pointer so that the function can modify pointer's value47 template< typename NODETYPE >48 void Tree< NODETYPE >::insertNodeHelper( 49 TreeNode< NODETYPE > **ptr, const NODETYPE &value )50 {51 // subtree is empty; create new TreeNode containing value52 if ( *ptr == 0 ) 53 *ptr = new TreeNode< NODETYPE >( value );54 else // subtree is not empty55 {56 // data to insert is less than or equal to data in current node57 if ( value <= ( *ptr )->data )58 insertNodeHelper( &( ( *ptr )->leftPtr ), value );59 else60 {61 // data to insert is greater than data in current node62 if ( value > ( *ptr )->data )63 insertNodeHelper( &( ( *ptr )->rightPtr ), value );64 else // duplicate data value ignored65 cout << value << " dup" << endl;66 } // end else67 } // end else68 } // end function insertNodeHelper6970 // begin preorder traversal of Tree71 template< typename NODETYPE > 72 void Tree< NODETYPE >::preOrderTraversal() const73 { 74 preOrderHelper( rootPtr ); 75 } // end function preOrderTraversal7677 // utility function to perform preorder traversal of Tree78 template< typename NODETYPE >79 void Tree< NODETYPE >::preOrderHelper( TreeNode< NODETYPE > *ptr ) const80 {81 if ( ptr != 0 )

cpphtp5_21_DataStructures_IM.fm Page 1267 Thursday, December 23, 2004 5:00 PM

1268 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

82 {83 cout << ptr->data << ' '; // process node 84 preOrderHelper( ptr->leftPtr ); // traverse left subtree 85 preOrderHelper( ptr->rightPtr ); // traverse right subtree86 } // end if87 } // end function preOrderHelper8889 // begin inorder traversal of Tree90 template< typename NODETYPE >91 void Tree< NODETYPE >::inOrderTraversal() const92 { 93 inOrderHelper( rootPtr ); 94 } // end function inOrderTraversal9596 // utility function to perform inorder traversal of Tree97 template< typename NODETYPE >98 void Tree< NODETYPE >::inOrderHelper( TreeNode< NODETYPE > *ptr ) const99 {100 if ( ptr != 0 ) 101 {102 inOrderHelper( ptr->leftPtr ); // traverse left subtree 103 cout << ptr->data << ' '; // process node 104 inOrderHelper( ptr->rightPtr ); // traverse right subtree105 } // end if106 } // end function inOrderHelper107108 // begin postorder traversal of Tree109 template< typename NODETYPE >110 void Tree< NODETYPE >::postOrderTraversal() const111 { 112 postOrderHelper( rootPtr ); 113 } // end function postOrderTraversal114115 // utility function to perform postorder traversal of Tree116 template< typename NODETYPE >117 void Tree< NODETYPE >::postOrderHelper( 118 TreeNode< NODETYPE > *ptr ) const119 {120 if ( ptr != 0 ) 121 {122 postOrderHelper( ptr->leftPtr ); // traverse left subtree 123 postOrderHelper( ptr->rightPtr ); // traverse right subtree124 cout << ptr->data << ' '; // process node 125 } // end if126 } // end function postOrderHelper127128 #endif

1 // Exercise 21.16 Solution: Ex21_16.cpp2 // Driver to test class template Tree.3 #include <iostream> 4 using std::cin; 5 using std::cout;

cpphtp5_21_DataStructures_IM.fm Page 1268 Thursday, December 23, 2004 5:00 PM

Exercises 1269

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

67 #include <iomanip> 8 using std::setprecision; 9 using std::fixed;

1011 #include "Tree.h"1213 int main()14 {15 Tree< int > intTree;16 int intVal;17 int i;1819 cout << "Enter 10 integer values:\n";2021 // insert input into intTree22 for ( i = 0; i < 10; i++ ) 23 {24 cin >> intVal;25 intTree.insertNode( intVal );26 } // end for2728 cout << "\nPreorder traversal\n";29 intTree.preOrderTraversal();3031 cout << "\nInorder traversal\n";32 intTree.inOrderTraversal();3334 cout << "\nPostorder traversal\n";35 intTree.postOrderTraversal();3637 Tree< double > doubleTree;38 double doubleVal;3940 cout << "\n\n\nEnter 10 double values:\n"41 << fixed << setprecision( 1 );4243 // takes 10 double values44 for ( i = 0; i < 10; i++ ) 45 {46 cin >> doubleVal;47 doubleTree.insertNode( doubleVal );48 } // end for4950 cout << "\nPreorder traversal\n";51 doubleTree.preOrderTraversal();5253 cout << "\nInorder traversal\n";54 doubleTree.inOrderTraversal();5556 cout << "\nPostorder traversal\n";57 doubleTree.postOrderTraversal();58 cout << "\n";59 return 0; // indicates successful termination60 } // end main

cpphtp5_21_DataStructures_IM.fm Page 1269 Thursday, December 23, 2004 5:00 PM

1270 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.17 Write a program based on Figs. 21.20–21.22 that inputs a line of text, tokenizes the sen-tence into separate words (you may want to use the strtok library function), inserts the words in abinary search tree and prints the inorder, preorder and postorder traversals of the tree. Use an OOPapproach.

ANS: [Note: The solution to this exercise uses TreeNode.h and Tree.h in Figs. 21.20–21.21.]

Enter 10 integer values:22 8 88 22 73 88 83 68 99 92

Preorder traversal22 8 22 88 73 68 88 83 99 92Inorder traversal8 22 22 68 73 83 88 88 92 99Postorder traversal22 8 68 83 88 73 92 99 88 22

Enter 10 double values:9.9 2.2 8.8 2.2 0.0 6.0 3.4 9.8 5.2 6.3

Preorder traversal9.9 2.2 2.2 0.0 8.8 6.0 3.4 5.2 6.3 9.8Inorder traversal0.0 2.2 2.2 3.4 5.2 6.0 6.3 8.8 9.8 9.9Postorder traversal0.0 2.2 5.2 3.4 6.3 6.0 9.8 8.8 2.2 9.9

1 // Exercise 21.17 Solution: Ex21_17.cpp2 #include <iostream> 3 using std::cout; 4 using std::endl;5 using std::cin; 67 #include <string>8 using std::string;9

10 #include "Tree.h"1112 int main()13 {14 Tree< string > stringTree;15 char sentence[ 80 ];16 char *tokenPtr;1718 cout << "Enter a sentence:\n";19 cin.getline( sentence, 80 );2021 tokenPtr = strtok( sentence, " " );2223 // until the token is empty24 while ( tokenPtr != 0 ) 25 {

cpphtp5_21_DataStructures_IM.fm Page 1270 Thursday, December 23, 2004 5:00 PM

Exercises 1271

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.18 In this chapter, we saw that duplicate elimination is straightforward when creating a binarysearch tree. Describe how you would perform duplicate elimination using only a one-dimensionalarray. Compare the performance of array-based duplicate elimination with the performance of bi-nary-search-tree-based duplicate elimination.

21.19 Write a function depth that receives a binary tree and determines how many levels it has.ANS:

26 string *newString = new string( tokenPtr );27 stringTree.insertNode( *newString );28 tokenPtr = strtok( 0, " " );29 } // end while3031 cout << "\nPreorder traversal\n";32 stringTree.preOrderTraversal();3334 cout << "\nInorder traversal\n";35 stringTree.inOrderTraversal();3637 cout << "\nPostorder traversal\n";38 stringTree.postOrderTraversal();3940 cout << endl;41 return 0; // indicates successful termination42 } // end main

Enter a sentence:ANSI/ISO C++ How to Program

Preorder traversalANSI/ISO C++ How to ProgramInorder traversalANSI/ISO C++ How Program toPostorder traversalProgram to How C++ ANSI/ISO

1 // Exercise 21.19 Solution: TreeNode.h2 // Definition of class template TreeNode.3 #ifndef TREENODE_H4 #define TREENODE_H56 template< typename T > class Tree; // forward declaration78 template< typename NODETYPE >9 class TreeNode

10 {11 friend class Tree< NODETYPE >;12 public:13 TreeNode( const NODETYPE & ); // constructor14 NODETYPE getData() const; // return data1516 // return a leftPtr17 TreeNode *getLeftPtr() const

cpphtp5_21_DataStructures_IM.fm Page 1271 Thursday, December 23, 2004 5:00 PM

1272 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

18 { 19 return leftPtr; 20 } // end getLeftPtr function21 22 // return a rightPtr23 TreeNode *getRightPtr() const 24 { 25 return rightPtr; 26 } // end function getRightPtr2728 // set value for leftPtr29 void setLeftPtr( TreeNode *ptr ) 30 { 31 leftPtr = ptr; 32 } // end setLeftPtr function33 34 // set value for rightPtr35 void setRightPtr( TreeNode *ptr ) 36 { 37 rightPtr = ptr; 38 } // end function setRightPtr39 private:40 TreeNode *leftPtr; // pointer to left subtree41 NODETYPE data;42 TreeNode *rightPtr; // pointer to right subtree43 }; // end class TreeNode4445 // constructor46 template< typename NODETYPE >47 TreeNode< NODETYPE >::TreeNode( const NODETYPE &d )48 {49 data = d;50 leftPtr = rightPtr = 0;51 } // end TreeNode constructor5253 // return a copy of the data value54 template< typename NODETYPE >55 NODETYPE TreeNode< NODETYPE >::getData() const 56 { 57 return data; 58 } // end function getData5960 #endif

1 // Exercise 21.19 Solution: Tree.h2 // Definition of class template Tree.3 #ifndef TREE_H4 #define TREE_H56 #include <iostream> 7 using std::cout; 89 #include <new>

10 #include "TreeNode.h"

cpphtp5_21_DataStructures_IM.fm Page 1272 Thursday, December 23, 2004 5:00 PM

Exercises 1273

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

1112 template< typename NODETYPE >13 class Tree 14 {15 public:16 Tree();17 void insertNode( const NODETYPE & );18 void preOrderTraversal() const;19 void inOrderTraversal() const;20 void postOrderTraversal() const;21 int getDepth() const;22 protected:23 TreeNode<NODETYPE> *rootPtr;24 private:25 // utility functions26 void insertNodeHelper( TreeNode< NODETYPE > **, const NODETYPE & );27 void preOrderHelper( TreeNode< NODETYPE > * ) const;28 void inOrderHelper( TreeNode< NODETYPE > * ) const;29 void postOrderHelper( TreeNode< NODETYPE > * ) const;30 void determineDepth( TreeNode< NODETYPE > *, int *, int * ) const;31 }; // end class Tree3233 // constructor34 template< typename NODETYPE >35 Tree< NODETYPE >::Tree() 36 { 37 rootPtr = 0; 38 } // end Tree constructor3940 // begin inserting node into Tree41 template< typename NODETYPE >42 void Tree< NODETYPE >::insertNode( const NODETYPE &value )43 { 44 insertNodeHelper( &rootPtr, value ); 45 } // end function insertNode4647 // This function receives a pointer to a pointer so the48 // pointer can be modified.49 // NOTE: THIS FUNCTION WAS MODIFIED TO ALLOW DUPLICATES.50 template< typename NODETYPE >51 void Tree< NODETYPE >::insertNodeHelper( TreeNode< NODETYPE > **ptr,52 const NODETYPE &value )53 {54 if ( *ptr == 0 ) // tree is empty55 *ptr = new TreeNode< NODETYPE >( value );56 else // tree is not empty57 { 58 // data to insert is less than data in current node59 if ( value <= ( *ptr )->data )60 insertNodeHelper( &( ( *ptr )->leftPtr ), value );61 else62 insertNodeHelper( &( ( *ptr )->rightPtr ), value );63 } // end else64 } // end function insertNodeHelper65

cpphtp5_21_DataStructures_IM.fm Page 1273 Thursday, December 23, 2004 5:00 PM

1274 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

66 // begin preorder traversal of Tree67 template< typename NODETYPE >68 void Tree< NODETYPE >::preOrderTraversal() const 69 { 70 preOrderHelper( rootPtr ); 71 } // end function preOrderTraversal7273 // utility function to perform preorder traversal of Tree74 template< typename NODETYPE >75 void Tree< NODETYPE >::preOrderHelper( TreeNode< NODETYPE > *ptr ) const76 {77 if ( ptr != 0 ) 78 {79 cout << ptr->data << ' '; // process node80 preOrderHelper( ptr->leftPtr ); // go to left subtree81 preOrderHelper( ptr->rightPtr ); // go to right subtree82 } // end if83 } // end function preOrderHelper8485 // begin inorder traversal of Tree86 template< typename NODETYPE >87 void Tree< NODETYPE >::inOrderTraversal() const 88 { 89 inOrderHelper( rootPtr ); 90 } // end function inOrderTraversal9192 // utility function to perform inorder traversal of Tree93 template< typename NODETYPE >94 void Tree< NODETYPE >::inOrderHelper( TreeNode< NODETYPE > *ptr ) const95 {96 if ( ptr != 0 ) 97 {98 inOrderHelper( ptr->leftPtr ); // go to left subtree99 cout << ptr->data << ' '; // process node100 inOrderHelper( ptr->rightPtr ); // go to right subtree101 } // end if102 } // end function inOrderHelper103104 // begin postorder traversal of Tree105 template< typename NODETYPE >106 void Tree< NODETYPE >::postOrderTraversal() const 107 { 108 postOrderHelper( rootPtr ); 109 } // end function postOrderTraversal110111 // utility function to perform postorder traversal112 template< typename NODETYPE >113 void Tree< NODETYPE >::postOrderHelper( TreeNode< NODETYPE > *ptr ) const114 {115 if ( ptr != 0 ) 116 {117 postOrderHelper( ptr->leftPtr ); // go to left subtree118 postOrderHelper( ptr->rightPtr ); // go to right subtree119 cout << ptr->data << ' '; // process node120 } // end if

cpphtp5_21_DataStructures_IM.fm Page 1274 Thursday, December 23, 2004 5:00 PM

Exercises 1275

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

121 } // end postOrderHelper122123 // get the depth of the tree124 template< typename NODETYPE >125 int Tree< NODETYPE >::getDepth() const126 {127 int totalDepth = 0;128 int currentDepth = 0;129130 determineDepth( rootPtr, &totalDepth, &currentDepth );131 return totalDepth;132 } // end function getDepth133134 // calculate the depth of the tree135 template< typename NODETYPE >136 void Tree< NODETYPE >::determineDepth( TreeNode< NODETYPE > *ptr,137 int *totPtr, int *currPtr ) const138 { 139 if ( ptr != 0 ) // until ptr points to 0140 {141 ( *currPtr )++;142143 if ( *currPtr > *totPtr )144 *totPtr = *currPtr;145146 determineDepth( ptr->getLeftPtr(), totPtr, currPtr );147 determineDepth( ptr->getRightPtr(), totPtr, currPtr );148 ( *currPtr )--;149 } // end if150 } // end function determineDepth151152 #endif

1 // Exercise 21.19 Solution: Ex21_19.cpp2 #include <iostream> 3 using std::cin; 4 using std::cout; 56 #include "Tree.h"78 int main()9 {

10 Tree< int > intTree;11 int intVal;1213 cout << "Enter 10 integer values:\n";1415 // inserting value into tree16 for ( int i = 0; i < 10; i++ ) 17 {18 cin >> intVal;19 intTree.insertNode( intVal );20 } // end loop21

cpphtp5_21_DataStructures_IM.fm Page 1275 Thursday, December 23, 2004 5:00 PM

1276 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.20 (Recursively Print a List Backward) Write a member function printListBackward that re-cursively outputs the items in a linked list object in reverse order. Write a test program that createsa sorted list of integers and prints the list in reverse order.

ANS: [Note: The solution to this exercise uses List.h and ListNode.h from Exercise 21.6.]

22 cout << "\nPreorder traversal\n";23 intTree.preOrderTraversal();2425 cout << "\nInorder traversal\n";26 intTree.inOrderTraversal();2728 cout << "\nPostorder traversal\n";29 intTree.postOrderTraversal();3031 cout << "\n\nThere are " << intTree.getDepth()32 << " levels in this binary tree\n";33 return 0; // indicates successful termination34 } // end main

Enter 10 integer values:1 2 3 88 4 6 0 22 21 10

Preorder traversal1 0 2 3 88 4 6 22 21 10Inorder traversal0 1 2 3 4 6 10 21 22 88Postorder traversal0 10 21 22 6 4 88 3 2 1

There are 9 levels in this binary tree

1 // Exercise 21.20 Solution: List2.h2 // List2 class template definition.3 #ifndef LIST2_H4 #define LIST2_H56 #include <iostream> 7 using std::cout; 89 #include "ListNode.h"

10 #include "List.h"1112 template< typename NODETYPE >13 class List2 : public List< NODETYPE > 14 {15 public:16 void recursivePrintReverse() const;17 private:18 void recursivePrintReverseHelper( ListNode< NODETYPE > * ) const;19 }; // end class template List22021 // print a list backwards recursively.22 template< typename NODETYPE >

cpphtp5_21_DataStructures_IM.fm Page 1276 Thursday, December 23, 2004 5:00 PM

Exercises 1277

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

23 void List2< NODETYPE >::recursivePrintReverse() const24 {25 cout << "The list printed recursively backwards is:\n";26 recursivePrintReverseHelper( firstPtr );27 cout << '\n';28 } // end function recursivePrintReverse2930 // helper for printing a list backwards recursively.31 template< typename NODETYPE >32 void List2< NODETYPE >::recursivePrintReverseHelper( 33 ListNode< NODETYPE > *currentPtr ) const34 {35 if ( currentPtr == 0 )36 return;37 38 recursivePrintReverseHelper( currentPtr->getNextPtr() );39 cout << currentPtr->getData() << ' ';40 } // end function recursivePrintReverseHelper4142 #endif

1 // Exercise 21.20 Solution: Ex21_20.cpp2 #include "List2.h"34 int main()5 {6 List2< int > intList; 78 // insert into list9 for ( int i = 1; i <= 10; i++ )

10 intList.insertAtBack( i );1112 intList.print();13 intList.recursivePrintReverse();14 return 0; // indicates successful termination15 } // end main

The list is: 1 2 3 4 5 6 7 8 9 10

The list printed recursively backwards is:10 9 8 7 6 5 4 3 2 1Destroying nodes ...1 2 3 4 5 6 7 8 9 10All nodes destroyed

cpphtp5_21_DataStructures_IM.fm Page 1277 Thursday, December 23, 2004 5:00 PM

1278 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.21 (Recursively Search a List) Write a member function searchList that recursively searches alinked list object for a specified value. The function should return a pointer to the value if it is found;otherwise, null should be returned. Use your function in a test program that creates a list of integers.The program should prompt the user for a value to locate in the list.

ANS: [Note: The solution to this exercise uses List.h from Exercise 21.6.]

1 // Exercise 21.21 Solution: ListNode.h2 // ListNode class template definition.3 #ifndef LISTNODE_H4 #define LISTNODE_H56 template< typename T > class List; // forward declaration78 template< typename NODETYPE >9 class ListNode

10 {11 friend class List< NODETYPE >; // make List a friend12 public:13 ListNode( const NODETYPE & ); // constructor14 NODETYPE getData() const; // return the data in the node1516 // set the next pointer17 void setNextPtr( ListNode *nPtr ) 18 { 19 nextPtr = nPtr; 20 } // end function setNextPtr2122 // get the next pointer23 ListNode *getNextPtr() const 24 { 25 return nextPtr; 26 } // end function getNextPtr2728 // get the address29 NODETYPE *getAddress() 30 { 31 return &data; 32 } // end function getAddress33 private:34 NODETYPE data; // data35 ListNode *nextPtr; // next node in the list36 }; // end class ListNode3738 // constructor39 template< typename NODETYPE >40 ListNode< NODETYPE >::ListNode( const NODETYPE &info )41 {42 data = info;43 nextPtr = 0;44 } // end ListNode constructor4546 // return a copy of the data in the node47 template< typename NODETYPE >48 NODETYPE ListNode< NODETYPE >::getData() const

cpphtp5_21_DataStructures_IM.fm Page 1278 Thursday, December 23, 2004 5:00 PM

Exercises 1279

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

49 { 50 return data; 51 } // end getData5253 #endif

1 // Exercise 21.21 Solution: List2.h2 // List2 class template definition3 #ifndef LIST2_H4 #define LIST2_H56 #include <iostream> 7 using std::cout; 89 #include <new>

10 #include "ListNode.h"11 #include "List.h"1213 template< typename NODETYPE >14 class List2 : public List< NODETYPE > 15 {16 public:17 NODETYPE *searchList( NODETYPE & ) const;18 private:19 // utility function20 NODETYPE *recursiveSearchHelper( 21 ListNode< NODETYPE > *, NODETYPE & ) const;22 }; // end class List22324 // Search a List recursively.25 template< typename NODETYPE >26 NODETYPE *List2< NODETYPE >::searchList( NODETYPE &val ) const27 { 28 return recursiveSearchHelper( firstPtr, val ); 29 } // end function recursiveSearch3031 // Helper for searching a list recursively.32 template< typename NODETYPE >33 NODETYPE *List2< NODETYPE >::recursiveSearchHelper( 34 ListNode< NODETYPE > *currentPtr, NODETYPE &value ) const35 {36 if ( currentPtr == 0 )37 return 0;3839 // if data is found40 if ( currentPtr->getData() == value )41 return currentPtr->getAddress();4243 // continue recursive call 44 return recursiveSearchHelper( currentPtr->getNextPtr(), value );45 } // end function recursiveSearchHelper4647 #endif

cpphtp5_21_DataStructures_IM.fm Page 1279 Thursday, December 23, 2004 5:00 PM

1280 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.22 (Binary Tree Delete) In this exercise, we discuss deleting items from binary search trees. Thedeletion algorithm is not as straightforward as the insertion algorithm. There are three cases that areencountered when deleting an item—the item is contained in a leaf node (i.e., it has no children),the item is contained in a node that has one child or the item is contained in a node that has twochildren.

If the item to be deleted is contained in a leaf node, the node is deleted and the pointer in theparent node is set to null.

If the item to be deleted is contained in a node with one child, the pointer in the parent nodeis set to point to the child node and the node containing the data item is deleted. This causes thechild node to take the place of the deleted node in the tree.

The last case is the most difficult. When a node with two children is deleted, another node inthe tree must take its place. However, the pointer in the parent node cannot be assigned to point to

1 // Exercise 21.21 Solution: Ex21_21.cpp2 #include <iostream> 3 using std::cout; 4 using std::cin; 56 #include "List2.h"78 int main()9 {

10 List2< int > intList;1112 // create list13 for ( int i = 2; i <= 20; i += 2 )14 intList.insertAtBack( i );1516 intList.print(); // print list1718 int value; 19 int *ptr; // int pointer2021 cout << "Enter a value to search for: ";22 cin >> value;23 ptr = intList.searchList( value );2425 if ( ptr != 0 )26 cout << *ptr << " was found\n";27 else28 cout << "Element not found\n";2930 return 0; // indicates successful termination31 } // end main

The list is: 2 4 6 8 10 12 14 16 18 20

Enter a value to search for: 1818 was foundDestroying nodes ...2 4 6 8 10 12 14 16 18 20All nodes destroyed

cpphtp5_21_DataStructures_IM.fm Page 1280 Thursday, December 23, 2004 5:00 PM

Exercises 1281

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

one of the children of the node to be deleted. In most cases, the resulting binary search tree wouldnot adhere to the following characteristic of binary search trees (with no duplicate values): The val-ues in any left subtree are less than the value in the parent node, and the values in any right subtree aregreater than the value in the parent node.

Which node is used as a replacement node to maintain this characteristic? Either the node con-taining the largest value in the tree less than the value in the node being deleted, or the node con-taining the smallest value in the tree greater than the value in the node being deleted. Let usconsider the node with the smaller value. In a binary search tree, the largest value less than a par-ent’s value is located in the left subtree of the parent node and is guaranteed to be contained in therightmost node of the subtree. This node is located by walking down the left subtree to the rightuntil the pointer to the right child of the current node is null. We are now pointing to the replace-ment node, which is either a leaf node or a node with one child to its left. If the replacement nodeis a leaf node, the steps to perform the deletion are as follows:

1) Store the pointer to the node to be deleted in a temporary pointer variable (this pointeris used to delete the dynamically allocated memory).

2) Set the pointer in the parent of the node being deleted to point to the replacement node.3) Set the pointer in the parent of the replacement node to null.4) Set the pointer to the right subtree in the replacement node to point to the right subtree

of the node to be deleted.5) Delete the node to which the temporary pointer variable points.

The deletion steps for a replacement node with a left child are similar to those for a replacementnode with no children, but the algorithm also must move the child into the replacement node’sposition in the tree. If the replacement node is a node with a left child, the steps to perform thedeletion are as follows:

1) Store the pointer to the node to be deleted in a temporary pointer variable.2) Set the pointer in the parent of the node being deleted to point to the replacement node.3) Set the pointer in the parent of the replacement node to point to the left child of the

replacement node.4) Set the pointer to the right subtree in the replacement node to point to the right subtree

of the node to be deleted.5) Delete the node to which the temporary pointer variable points.

Write member function deleteNode, which takes as its arguments a pointer to the root nodeof the tree object and the value to be deleted. The function should locate in the tree the node con-taining the value to be deleted and use the algorithms discussed here to delete the node. The func-tion should print a message that indicates whether the value is deleted. Modify the program ofFigs. 21.20–21.22 to use this function. After deleting an item, call the inOrder, preOrder and pos-tOrder traversal functions to confirm that the delete operation was performed correctly.

21.23 (Binary Tree Search) Write member function binaryTreeSearch, which attempts to locatea specified value in a binary search tree object. The function should take as arguments a pointer tothe root node of the binary tree and a search key to be located. If the node containing the search keyis found, the function should return a pointer to that node; otherwise, the function should return anull pointer.

ANS:

1 // Exercise 21.23 Solution: TreeNode.h2 // Definition of class template TreeNode.3 #ifndef TREENODE_H4 #define TREENODE_H56 template< typename T > class Tree; // forward declaration

cpphtp5_21_DataStructures_IM.fm Page 1281 Thursday, December 23, 2004 5:00 PM

1282 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

78 template< typename NODETYPE >9 class TreeNode

10 {11 friend class Tree< NODETYPE >;12 public:13 TreeNode( const NODETYPE & ); // constructor14 NODETYPE getData() const; // return data1516 // return a leftPtr17 TreeNode *getLeftPtr() const 18 { 19 return leftPtr; 20 } // end getLeftPtr function21 22 // return a rightPtr23 TreeNode *getRightPtr() const 24 { 25 return rightPtr; 26 } // end function getRightPtr2728 // set value for leftPtr29 void setLeftPtr( TreeNode *ptr ) 30 { 31 leftPtr = ptr; 32 } // end setLeftPtr function33 34 // set value for rightPtr35 void setRightPtr( TreeNode *ptr ) 36 { 37 rightPtr = ptr; 38 } // end function setRightPtr39 private:40 TreeNode *leftPtr; // pointer to left subtree41 NODETYPE data;42 TreeNode *rightPtr; // pointer to right subtree43 }; // end class TreeNode4445 // constructor46 template< typename NODETYPE >47 TreeNode< NODETYPE >::TreeNode( const NODETYPE &d )48 {49 data = d;50 leftPtr = rightPtr = 0;51 } // end TreeNode constructor5253 // return a copy of the data value54 template< typename NODETYPE >55 NODETYPE TreeNode< NODETYPE >::getData() const 56 { 57 return data; 58 } // end function getData5960 #endif

cpphtp5_21_DataStructures_IM.fm Page 1282 Thursday, December 23, 2004 5:00 PM

Exercises 1283

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

1 // Exercise 21.23 Solution: Tree.h2 // Definition of class template Tree.3 #ifndef TREE_H4 #define TREE_H56 #include <iostream> 7 using std::cout; 89 #include <new>

10 #include "TreeNode.h"1112 template< typename NODETYPE >13 class Tree 14 {15 public:16 Tree();17 void insertNode( const NODETYPE & );18 void preOrderTraversal() const;19 void inOrderTraversal() const;20 void postOrderTraversal() const;21 TreeNode< NODETYPE > *binaryTreeSearch( int ) const;22 protected:23 TreeNode< NODETYPE > *rootPtr;24 private:25 // utility functions26 void insertNodeHelper( TreeNode< NODETYPE > **, const NODETYPE & );27 void preOrderHelper( TreeNode< NODETYPE > * ) const;28 void inOrderHelper( TreeNode< NODETYPE > * ) const;29 void postOrderHelper( TreeNode< NODETYPE > * ) const;30 TreeNode< NODETYPE > 31 *binarySearchHelper( TreeNode< NODETYPE > *, int ) const;32 }; // end class Tree3334 // constructor35 template< typename NODETYPE >36 Tree< NODETYPE >::Tree() 37 { 38 rootPtr = 0; 39 } // end Tree constructor4041 // begin inserting node into Tree42 template< typename NODETYPE >43 void Tree< NODETYPE >::insertNode( const NODETYPE &value )44 { 45 insertNodeHelper( &rootPtr, value ); 46 } // end function insertNode4748 // This function receives a pointer to a pointer so the49 // pointer can be modified.50 // NOTE: THIS FUNCTION WAS MODIFIED TO ALLOW DUPLICATES.51 template< typename NODETYPE >52 void Tree< NODETYPE >::insertNodeHelper( TreeNode< NODETYPE > **ptr,53 const NODETYPE &value )54 {55 if ( *ptr == 0 ) // tree is empty

cpphtp5_21_DataStructures_IM.fm Page 1283 Thursday, December 23, 2004 5:00 PM

1284 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

56 *ptr = new TreeNode< NODETYPE >( value );57 else // tree is not empty58 { 59 // data to insert is less than data in current node60 if ( value <= ( *ptr )->data )61 insertNodeHelper( &( ( *ptr )->leftPtr ), value );62 else63 insertNodeHelper( &( ( *ptr )->rightPtr ), value );64 } // end else65 } // end function insertNodeHelper6667 // begin preorder traversal of Tree68 template< typename NODETYPE >69 void Tree< NODETYPE >::preOrderTraversal() const 70 { 71 preOrderHelper( rootPtr ); 72 } // end function preOrderTraversal7374 // utility function to perform preorder traversal of Tree75 template< typename NODETYPE >76 void Tree< NODETYPE >::preOrderHelper( TreeNode< NODETYPE > *ptr ) const77 {78 if ( ptr != 0 ) 79 {80 cout << ptr->data << ' '; // process node81 preOrderHelper( ptr->leftPtr ); // go to left subtree82 preOrderHelper( ptr->rightPtr ); // go to right subtree83 } // end if84 } // end function preOrderHelper8586 // begin inorder traversal of Tree87 template< typename NODETYPE >88 void Tree< NODETYPE >::inOrderTraversal() const 89 { 90 inOrderHelper( rootPtr ); 91 } // end function inOrderTraversal9293 // utility function to perform inorder traversal of Tree94 template< typename NODETYPE >95 void Tree< NODETYPE >::inOrderHelper( TreeNode< NODETYPE > *ptr ) const96 {97 if ( ptr != 0 ) 98 {99 inOrderHelper( ptr->leftPtr ); // go to left subtree100 cout << ptr->data << ' '; // process node101 inOrderHelper( ptr->rightPtr ); // go to right subtree102 } // end if103 } // end function inOrderHelper104105 // begin postorder traversal of Tree106 template< typename NODETYPE >107 void Tree< NODETYPE >::postOrderTraversal() const 108 { 109 postOrderHelper( rootPtr ); 110 } // end function postOrderTraversal

cpphtp5_21_DataStructures_IM.fm Page 1284 Thursday, December 23, 2004 5:00 PM

Exercises 1285

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

111112 // utility function to perform postorder traversal113 template< typename NODETYPE >114 void Tree< NODETYPE >::postOrderHelper( TreeNode< NODETYPE > *ptr ) const115 {116 if ( ptr != 0 ) 117 {118 postOrderHelper( ptr->leftPtr ); // go to left subtree119 postOrderHelper( ptr->rightPtr ); // go to right subtree120 cout << ptr->data << ' '; // process node121 } // end if122 } // end postOrderHelper123124 // begin binary search125 template< typename NODETYPE >126 TreeNode< NODETYPE > *Tree< NODETYPE >::binaryTreeSearch( int val ) const127 { 128 return binarySearchHelper( rootPtr, val ); 129 } // end function binaryTreeSearch130131 // do a binary search on the Tree132 template< typename NODETYPE >133 TreeNode< NODETYPE > *Tree< NODETYPE >::binarySearchHelper( 134 TreeNode< NODETYPE > *ptr, int value ) const135 {136 // if value is not found137 if ( ptr == 0 )138 return 0;139140 cout << "Comparing " << value << " to " << ptr->getData();141142 if ( value == ptr->getData() ) // match143 {144 cout << "; search complete\n";145 return ptr;146 } // end if147 else if ( value < ptr->getData() ) // value is less than current data148 {149 cout << "; smaller, walk left\n";150 return binarySearchHelper( ptr->getLeftPtr(), value );151 } // end else...if152 else // search value is greater than current data153 {154 cout << "; larger, walk right\n";155 return binarySearchHelper( ptr->getRightPtr(), value );156 } // end else157 } // end function binarySearchHelper158159 #endif

1 // Exercise 21.23 Solution: Ex21_23.cpp2 #include <iostream> 3 using std::cout; 4 using std::endl;

cpphtp5_21_DataStructures_IM.fm Page 1285 Thursday, December 23, 2004 5:00 PM

1286 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

5 using std::cin;67 #include <cstdlib>8 using std::rand;9 using std::srand;

1011 #include <ctime>12 using std::time;1314 #include "Tree.h"1516 int main()17 {18 srand( time( 0 ) ); // randomize the random number generator1920 Tree< int > intTree;21 int intVal;2223 cout << "The values being placed in the tree are:\n";2425 // generate a tree with values26 for ( int i = 1; i <= 15; i++ ) 27 {28 intVal = rand() % 100;29 cout << intVal << ' ';30 intTree.insertNode( intVal );31 } // end for3233 cout << "\n\nEnter a value to search for: ";34 cin >> intVal;3536 // create a pointer with the user value37 TreeNode< int > *ptr = intTree.binaryTreeSearch( intVal );3839 // a value is found40 if ( ptr != 0 )41 cout << ptr->getData() << " was found\n";42 else // value not found43 cout << "Element was not found\n";4445 cout << endl;46 return 0; // indicates successful termination47 } // end main

The values being placed in the tree are:3 15 75 24 26 13 12 11 33 17 36 47 28 29 67

Enter a value to search for: 17Comparing 17 to 3; larger, walk rightComparing 17 to 15; larger, walk rightComparing 17 to 75; smaller, walk leftComparing 17 to 24; smaller, walk leftComparing 17 to 17; search complete17 was found

cpphtp5_21_DataStructures_IM.fm Page 1286 Thursday, December 23, 2004 5:00 PM

Exercises 1287

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.24 (Level-Order Binary Tree Traversal) The program of Figs. 21.20–21.22 illustrated three re-cursive methods of traversing a binary tree—inorder, preorder and postorder traversals. This exer-cise presents the level-order traversal of a binary tree, in which the node values are printed level bylevel, starting at the root node level. The nodes on each level are printed from left to right. The level-order traversal is not a recursive algorithm. It uses a queue object to control the output of the nodes.The algorithm is as follows:

1) Insert the root node in the queue2) While there are nodes left in the queue,

Get the next node in the queuePrint the node’s valueIf the pointer to the left child of the node is not null

Insert the left child node in the queueIf the pointer to the right child of the node is not null

Insert the right child node in the queue.Write member function levelOrder to perform a level-order traversal of a binary tree object.

Modify the program of Figs. 21.20–21.22 to use this function. [Note: You will also need to modifyand incorporate the queue-processing functions of Fig. 21.16 in this program.]

ANS:

1 // Exercise 21.24 Solution: QueueNode.h2 // Definition of template class QueueNode3 #ifndef QUEUENODE_H4 #define QUEUENODE_H56 template< typename T > class Queue; // forward declaration78 template < typename T >9 class QueueNode

10 {11 friend class Queue< T >;12 public:13 QueueNode( const T & = 0 );14 T getData() const;15 private:16 T data;17 QueueNode *nextPtr;18 }; // end class QueueNode1920 // Member function definitions for class QueueNode2122 // constructor for class QueueNode23 template < typename T >24 QueueNode< T >::QueueNode( const T &d )25 {26 data = d;27 nextPtr = 0;28 } // end Queue constructor2930 // get function returns data31 template < typename T >32 T QueueNode< T >::getData() const 33 { 34 return data;

cpphtp5_21_DataStructures_IM.fm Page 1287 Thursday, December 23, 2004 5:00 PM

1288 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

35 } // end function getData3637 #endif

1 // Exercise 21.24 Solution: Queue.h2 // Definition of template class Queue3 #ifndef QUEUE_H4 #define QUEUE_H56 #include <iostream> 7 using std::cout; 89 #include <new>

10 #include "QueueNode.h"1112 template < typename T >13 class Queue 14 {15 public:16 Queue(); // default constructor17 ~Queue(); // destructor18 void enqueue( T ); // insert item in queue19 T dequeue(); // remove item from queue20 bool isEmpty() const; // is the queue empty?21 void print() const; // output the queue22 private:23 QueueNode< T > *headPtr; // pointer to first QueueNode24 QueueNode< T > *tailPtr; // pointer to last QueueNode25 }; // end class2627 // Member function definitions for class Queue2829 // constructor30 template < typename T >31 Queue< T >::Queue()32 { 33 headPtr = tailPtr = 0; 34 } // end Queue constructor3536 // destructor37 template < typename T >38 Queue< T >::~Queue()39 {40 QueueNode< T > *tempPtr, *currentPtr = headPtr;4142 while ( currentPtr != 0 )43 {44 tempPtr = currentPtr;45 currentPtr = currentPtr->nextPtr;46 delete tempPtr;47 } // end while loop48 } // end Queue destructor4950 // enqueue function

cpphtp5_21_DataStructures_IM.fm Page 1288 Thursday, December 23, 2004 5:00 PM

Exercises 1289

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

51 template < typename T >52 void Queue< T >::enqueue( T d )53 {54 // create pointer to new node55 QueueNode< T > *newPtr = new QueueNode< T >( d );5657 // if queue is empty58 if ( isEmpty() )59 headPtr = tailPtr = newPtr;60 else // add to end 61 {62 tailPtr->nextPtr = newPtr;63 tailPtr = newPtr;64 } // end else65 } // end function enqueue6667 // dequeue function68 template < typename T >69 T Queue< T >::dequeue()70 {71 QueueNode< T > *tempPtr = headPtr;7273 headPtr = headPtr->nextPtr;74 T value = tempPtr->data;75 delete tempPtr;7677 if ( headPtr == 0 ) 78 tailPtr = 0;7980 return value; // return value taken out81 } // end function dequeue8283 // is the queue empty?84 template < typename T >85 bool Queue< T >::isEmpty() const 86 { 87 return headPtr == 0; 88 } // end function isEmpty8990 // print the queue91 template < typename T >92 void Queue< T >::print() const93 {94 QueueNode< T > *currentPtr = headPtr;9596 // Queue is empty97 if ( isEmpty() ) 98 cout << "Queue is empty\n";99 else // Queue is not empty100 {101 cout << "The queue is:\n";102103 while ( currentPtr != 0 ) 104 {105 cout << currentPtr->data << ' ';

cpphtp5_21_DataStructures_IM.fm Page 1289 Thursday, December 23, 2004 5:00 PM

1290 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

106 currentPtr = currentPtr->nextPtr;107 } // end while108109 cout << endl;110 } // end if...else111 } // end function print112113 #endif

1 // Exercise 21.24 Solution: Treenode.h2 // Template TreeNode class definition.3 #ifndef TREENODE_H4 #define TREENODE_H56 // forward declaration of class Tree7 template< typename NODETYPE > class Tree; 89 // TreeNode class-template definition

10 template< typename NODETYPE >11 class TreeNode 12 {13 friend class Tree< NODETYPE >;14 public:15 // constructor16 TreeNode( const NODETYPE &d ) 17 : leftPtr( 0 ), // pointer to left subtree18 data( d ), // tree node data19 rightPtr( 0 ) // pointer to right subtree20 { 21 // empty body 22 } // end TreeNode constructor2324 // return copy of node's data25 NODETYPE getData() const 26 { 27 return data; 28 } // end getData function29 private:30 TreeNode< NODETYPE > *leftPtr; // pointer to left subtree31 NODETYPE data;32 TreeNode< NODETYPE > *rightPtr; // pointer to right subtree33 }; // end class TreeNode3435 #endif

1 // Exercise 21.24 Solution: Tree.h2 // Template Tree class definition.3 #ifndef TREE_H4 #define TREE_H56 #include <iostream>7 using std::cout;8 using std::endl;

cpphtp5_21_DataStructures_IM.fm Page 1290 Thursday, December 23, 2004 5:00 PM

Exercises 1291

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

910 #include <new>11 #include "Treenode.h"12 #include "Queue.h"1314 // Tree class-template definition15 template< typename NODETYPE > class Tree16 {17 public:18 Tree(); // constructor19 void insertNode( const NODETYPE & );20 void preOrderTraversal() const;21 void inOrderTraversal() const;22 void postOrderTraversal() const;23 void levelOrder() const;24 private:25 TreeNode< NODETYPE > *rootPtr;2627 // utility functions28 void insertNodeHelper( TreeNode< NODETYPE > **, const NODETYPE & );29 void preOrderHelper( TreeNode< NODETYPE > * ) const;30 void inOrderHelper( TreeNode< NODETYPE > * ) const;31 void postOrderHelper( TreeNode< NODETYPE > * ) const;32 }; // end class Tree3334 // constructor35 template< typename NODETYPE >36 Tree< NODETYPE >::Tree() 37 { 38 rootPtr = 0; // indicate tree is initially empty 39 } // end Tree constructor4041 // insert node in Tree42 template< typename NODETYPE >43 void Tree< NODETYPE >::insertNode( const NODETYPE &value )44 { 45 insertNodeHelper( &rootPtr, value ); 46 } // end function insertNode4748 // utility function called by insertNode; receives a pointer49 // to a pointer so that the function can modify pointer's value50 template< typename NODETYPE >51 void Tree< NODETYPE >::insertNodeHelper( 52 TreeNode< NODETYPE > **ptr, const NODETYPE &value )53 {54 // subtree is empty; create new TreeNode containing value55 if ( *ptr == 0 ) 56 *ptr = new TreeNode< NODETYPE >( value );57 else // subtree is not empty58 {59 // data to insert is less than data in current node60 if ( value < ( *ptr )->data )61 insertNodeHelper( &( ( *ptr )->leftPtr ), value );62 else63 {

cpphtp5_21_DataStructures_IM.fm Page 1291 Thursday, December 23, 2004 5:00 PM

1292 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

64 // data to insert is greater than data in current node65 if ( value > ( *ptr )->data )66 insertNodeHelper( &( ( *ptr )->rightPtr ), value );67 else // duplicate data value ignored68 cout << value << " dup" << endl;69 } // end else70 } // end else71 } // end function insertNodeHelper7273 // begin preorder traversal of Tree74 template< typename NODETYPE > 75 void Tree< NODETYPE >::preOrderTraversal() const76 { 77 preOrderHelper( rootPtr ); 78 } // end function preOrderTraversal7980 // utility function to perform preorder traversal of Tree81 template< typename NODETYPE >82 void Tree< NODETYPE >::preOrderHelper( TreeNode< NODETYPE > *ptr ) const83 {84 if ( ptr != 0 ) 85 {86 cout << ptr->data << ' '; // process node 87 preOrderHelper( ptr->leftPtr ); // traverse left subtree 88 preOrderHelper( ptr->rightPtr ); // traverse right subtree89 } // end if90 } // end function preOrderHelper9192 // begin inorder traversal of Tree93 template< typename NODETYPE >94 void Tree< NODETYPE >::inOrderTraversal() const95 { 96 inOrderHelper( rootPtr ); 97 } // end function inOrderTraversal9899 // utility function to perform inorder traversal of Tree100 template< typename NODETYPE >101 void Tree< NODETYPE >::inOrderHelper( TreeNode< NODETYPE > *ptr ) const102 {103 if ( ptr != 0 ) 104 {105 inOrderHelper( ptr->leftPtr ); // traverse left subtree 106 cout << ptr->data << ' '; // process node 107 inOrderHelper( ptr->rightPtr ); // traverse right subtree108 } // end if109 } // end function inOrderHelper110111 // begin postorder traversal of Tree112 template< typename NODETYPE >113 void Tree< NODETYPE >::postOrderTraversal() const114 { 115 postOrderHelper( rootPtr ); 116 } // end function postOrderTraversal117118 // utility function to perform postorder traversal of Tree

cpphtp5_21_DataStructures_IM.fm Page 1292 Thursday, December 23, 2004 5:00 PM

Exercises 1293

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

119 template< typename NODETYPE >120 void Tree< NODETYPE >::postOrderHelper( 121 TreeNode< NODETYPE > *ptr ) const122 {123 if ( ptr != 0 ) 124 {125 postOrderHelper( ptr->leftPtr ); // traverse left subtree 126 postOrderHelper( ptr->rightPtr ); // traverse right subtree127 cout << ptr->data << ' '; // process node 128 } // end if129 } // end function postOrderHelper130131 // perform level-order traversal132 template< typename NODETYPE >133 void Tree< NODETYPE >::levelOrder() const134 {135 Queue< TreeNode< NODETYPE > * > queue;136 TreeNode< NODETYPE > *nodePtr;137138 if ( rootPtr != 0 )139 queue.enqueue( rootPtr );140141 while ( !queue.isEmpty() ) 142 {143 nodePtr = queue.dequeue();144 cout << nodePtr->data << ' ';145146 if ( nodePtr->leftPtr != 0 )147 queue.enqueue( nodePtr->leftPtr );148149 if ( nodePtr->rightPtr != 0 )150 queue.enqueue( nodePtr->rightPtr );151 } // end while152 } // end function levelOrder153154 #endif

1 // Exercise 21.24 Solution: Ex21_24.cpp2 #include <iostream> 3 using std::cout;4 using std::endl;56 #include <cstdlib>7 using std::rand;8 using std::srand;9

10 #include <ctime>11 using std::time;1213 #include "Tree.h"1415 int main()16 {17 srand( time( 0 ) ); // randomize the random number generator

cpphtp5_21_DataStructures_IM.fm Page 1293 Thursday, December 23, 2004 5:00 PM

1294 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.25 (Printing Trees) Write a recursive member function outputTree to display a binary tree ob-ject on the screen. The function should output the tree row by row, with the top of the tree at theleft of the screen and the bottom of the tree toward the right of the screen. Each row is output verti-cally. For example, the binary tree illustrated in Fig. 21.24 is output as follows:

1819 Tree< int > intTree;20 int intVal;2122 cout << "The values being placed in the tree are:\n";2324 // adding values into intTree25 for ( int i = 1; i <= 15; i++ ) 26 {27 intVal = rand() % 100;28 cout << intVal << ' ';29 intTree.insertNode( intVal );30 } // end for3132 cout << "\n\nThe level-order traversal is:\n";33 intTree.levelOrder();3435 cout << endl;36 return 0; // indicates successful termination37 } // end main

The values being placed in the tree are:82 6 27 35 91 85 68 23 41 32 11 87 96 60 84

The level-order traversal is:82 6 91 27 85 96 23 35 84 87 11 32 68 41 60

cpphtp5_21_DataStructures_IM.fm Page 1294 Thursday, December 23, 2004 5:00 PM

Exercises 1295

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

Note that the rightmost leaf node appears at the top of the output in the rightmost column and theroot node appears at the left of the output. Each column of output starts five spaces to the right of theprevious column. Function outputTree should receive an argument totalSpaces representing thenumber of spaces preceding the value to be output (this variable should start at zero, so the root nodeis output at the left of the screen). The function uses a modified inorder traversal to output the tree—it starts at the rightmost node in the tree and works back to the left. The algorithm is as follows:

While the pointer to the current node is not nullRecursively call outputTree with the right subtree of the current node and totalSpaces + 5Use a for statement to count from 1 to totalSpaces and output spacesOutput the value in the current nodeSet the pointer to the current node to point to the left subtree of the current nodeIncrement totalSpaces by 5.

ANS: [Note: The solution to this exercise uses Treenode.h from the solution toExercise 21.24.]

9997

9283

7271

6949

4440

3228

1918

11

1 // Exercise 21.25 Solution: Tree.h2 // Template Tree class definition.3 #ifndef TREE_H4 #define TREE_H56 #include <iostream>7 using std::cout;8 using std::endl;9

10 #include <new>11 #include "Treenode.h"1213 // Tree class-template definition14 template< typename NODETYPE > class Tree15 {16 public:17 Tree(); // constructor18 void insertNode( const NODETYPE & );19 void preOrderTraversal() const;20 void inOrderTraversal() const;

cpphtp5_21_DataStructures_IM.fm Page 1295 Thursday, December 23, 2004 5:00 PM

1296 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21 void postOrderTraversal() const;22 void outputTree() const;23 private:24 TreeNode< NODETYPE > *rootPtr;2526 // utility functions27 void insertNodeHelper( TreeNode< NODETYPE > **, const NODETYPE & );28 void preOrderHelper( TreeNode< NODETYPE > * ) const;29 void inOrderHelper( TreeNode< NODETYPE > * ) const;30 void postOrderHelper( TreeNode< NODETYPE > * ) const;31 void outputTreeHelper( TreeNode< NODETYPE > *, int ) const;32 }; // end class Tree3334 // constructor35 template< typename NODETYPE >36 Tree< NODETYPE >::Tree() 37 { 38 rootPtr = 0; // indicate tree is initially empty 39 } // end Tree constructor4041 // insert node in Tree42 template< typename NODETYPE >43 void Tree< NODETYPE >::insertNode( const NODETYPE &value )44 { 45 insertNodeHelper( &rootPtr, value ); 46 } // end function insertNode4748 // utility function called by insertNode; receives a pointer49 // to a pointer so that the function can modify pointer's value50 template< typename NODETYPE >51 void Tree< NODETYPE >::insertNodeHelper( 52 TreeNode< NODETYPE > **ptr, const NODETYPE &value )53 {54 // subtree is empty; create new TreeNode containing value55 if ( *ptr == 0 ) 56 *ptr = new TreeNode< NODETYPE >( value );57 else // subtree is not empty58 {59 // data to insert is less than data in current node60 if ( value < ( *ptr )->data )61 insertNodeHelper( &( ( *ptr )->leftPtr ), value );62 else63 {64 // data to insert is greater than data in current node65 if ( value > ( *ptr )->data )66 insertNodeHelper( &( ( *ptr )->rightPtr ), value );67 else // duplicate data value ignored68 cout << value << " dup" << endl;69 } // end else70 } // end else71 } // end function insertNodeHelper7273 // begin preorder traversal of Tree74 template< typename NODETYPE > 75 void Tree< NODETYPE >::preOrderTraversal() const

cpphtp5_21_DataStructures_IM.fm Page 1296 Thursday, December 23, 2004 5:00 PM

Exercises 1297

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

76 { 77 preOrderHelper( rootPtr ); 78 } // end function preOrderTraversal7980 // utility function to perform preorder traversal of Tree81 template< typename NODETYPE >82 void Tree< NODETYPE >::preOrderHelper( TreeNode< NODETYPE > *ptr ) const83 {84 if ( ptr != 0 ) 85 {86 cout << ptr->data << ' '; // process node 87 preOrderHelper( ptr->leftPtr ); // traverse left subtree 88 preOrderHelper( ptr->rightPtr ); // traverse right subtree89 } // end if90 } // end function preOrderHelper9192 // begin inorder traversal of Tree93 template< typename NODETYPE >94 void Tree< NODETYPE >::inOrderTraversal() const95 { 96 inOrderHelper( rootPtr ); 97 } // end function inOrderTraversal9899 // utility function to perform inorder traversal of Tree100 template< typename NODETYPE >101 void Tree< NODETYPE >::inOrderHelper( TreeNode< NODETYPE > *ptr ) const102 {103 if ( ptr != 0 ) 104 {105 inOrderHelper( ptr->leftPtr ); // traverse left subtree 106 cout << ptr->data << ' '; // process node 107 inOrderHelper( ptr->rightPtr ); // traverse right subtree108 } // end if109 } // end function inOrderHelper110111 // begin postorder traversal of Tree112 template< typename NODETYPE >113 void Tree< NODETYPE >::postOrderTraversal() const114 { 115 postOrderHelper( rootPtr ); 116 } // end function postOrderTraversal117118 // utility function to perform postorder traversal of Tree119 template< typename NODETYPE >120 void Tree< NODETYPE >::postOrderHelper( 121 TreeNode< NODETYPE > *ptr ) const122 {123 if ( ptr != 0 ) 124 {125 postOrderHelper( ptr->leftPtr ); // traverse left subtree 126 postOrderHelper( ptr->rightPtr ); // traverse right subtree127 cout << ptr->data << ' '; // process node 128 } // end if129 } // end function postOrderHelper130

cpphtp5_21_DataStructures_IM.fm Page 1297 Thursday, December 23, 2004 5:00 PM

1298 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

131 // print the tree132 template< typename NODETYPE >133 void Tree< NODETYPE >::outputTree() const 134 { 135 outputTreeHelper( rootPtr, 0 ); 136 } // end function outputTree137138 // utility function to print the tree139 template< typename NODETYPE >140 void Tree< NODETYPE >::outputTreeHelper( TreeNode< NODETYPE > *ptr,141 int totalSpaces ) const142 {143 if ( ptr != 0 ) 144 {145 outputTreeHelper( ptr->rightPtr, totalSpaces + 5 );146147 for ( int i = 1; i <= totalSpaces; i++ )148 cout << ' ';149 150 cout << ptr->data << '\n';151 outputTreeHelper( ptr->leftPtr, totalSpaces + 5 );152 } // end if153 } // end function outputTreeHelper154155 #endif

1 // Exercise 21.25 Solution: Ex21_25.cpp2 #include <iostream> 3 using std::cout; 45 #include <cstdlib>6 using std::rand;7 using std::srand;89 #include <ctime>

10 using std::time;1112 #include "Tree.h"1314 int main()15 {16 srand( time( 0 ) ); // randomize the random number generator1718 Tree< int > intTree;19 int intVal;2021 cout << "The values being placed in the tree are:\n";2223 for ( int i = 1; i <= 15; i++ ) 24 {25 intVal = rand() % 100;26 cout << intVal << ' ';27 intTree.insertNode( intVal );28 } // end loop

cpphtp5_21_DataStructures_IM.fm Page 1298 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1299

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

Special Section: Building Your Own CompilerIn Exercise 8.18 and Exercise 8.19, we introduced Simpletron Machine Language (SML) and youimplemented a Simpletron computer simulator to execute programs written in SML. In this sec-tion, we build a compiler that converts programs written in a high-level programming language toSML. This section “ties” together the entire programming process. You will write programs in thisnew high-level language, compile these programs on the compiler you build and run them on thesimulator you built in Exercise 8.19. You should make every effort to implement your compiler inan object-oriented manner.

21.26 (The Simple Language) Before we begin building the compiler, we discuss a simple, yet pow-erful, high-level language similar to early versions of the popular language BASIC. We call the lan-guage Simple. Every Simple statement consists of a line number and a Simple instruction. Linenumbers must appear in ascending order. Each instruction begins with one of the following Simplecommands: rem, input, let, print, goto, if…goto and end (see Fig. 21.25). All commands exceptend can be used repeatedly. Simple evaluates only integer expressions using the +, -, * and / opera-tors. These operators have the same precedence as in C++. Parentheses can be used to change theorder of evaluation of an expression.

Our Simple compiler recognizes only lowercase letters. All characters in a Simple file shouldbe lowercase (uppercase letters result in a syntax error unless they appear in a rem statement, inwhich case they are ignored). A variable name is a single letter. Simple does not allow descriptive

2930 cout << "\n\nThe tree is:\n";31 intTree.outputTree();32 return 0; // indicates successful termination33 } // end main

The values being placed in the tree are:54 78 81 14 74 20 84 59 71 8 76 41 65 27 47

The tree is: 84 81 78 76 74 71 65 5954 47 41 27 20 14 8

cpphtp5_21_DataStructures_IM.fm Page 1299 Thursday, December 23, 2004 5:00 PM

1300 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

variable names, so variables should be explained in remarks to indicate their use in a program. Sim-ple uses only integer variables. Simple does not have variable declarations—merely mentioning avariable name in a program causes the variable to be declared and initialized to zero automatically.The syntax of Simple does not allow string manipulation (reading a string, writing a string, com-paring strings, etc.). If a string is encountered in a Simple program (after a command other thanrem), the compiler generates a syntax error. The first version of our compiler will assume that Sim-ple programs are entered correctly. Exercise 21.29 asks the student to modify the compiler to per-form syntax error checking.

Simple uses the conditional if…goto statement and the unconditional goto statement toalter the flow of control during program execution. If the condition in the if…goto statement istrue, control is transferred to a specific line of the program. The following relational and equalityoperators are valid in an if…goto statement: <, >, <=, >=, == and !=. The precedence of these oper-ators is the same as in C++.

Let us now consider several programs that demonstrate Simple’s features. The first program(Fig. 21.26) reads two integers from the keyboard, stores the values in variables a and b and com-putes and prints their sum (stored in variable c).

The program of Fig. 21.27 determines and prints the larger of two integers. The integers areinput from the keyboard and stored in s and t. The if…goto statement tests the condition s >= t.If the condition is true, control is transferred to line 90 and s is output; otherwise, t is output andcontrol is transferred to the end statement in line 99, where the program terminates.

Simple does not provide a repetition statement (such as C++’s for, while or do…while). How-ever, Simple can simulate each of C++'s repetition statements using the if…goto and goto state-ments. Figure 21.28 uses a sentinel-controlled loop to calculate the squares of several integers. Eachinteger is input from the keyboard and stored in variable j. If the value entered is the sentinel value -9999, control is transferred to line 99, where the program terminates. Otherwise, k is assigned thesquare of j, k is output to the screen and control is passed to line 20, where the next integer is input.

Command Example statement Description

rem 50 rem this is a remark Text following rem is for documentation purposes and is ignored by the compiler.

input 30 input x Display a question mark to prompt the user to enter an integer. Read that integer from the keyboard, and store the integer in x.

let 80 let u = 4 * (j - 56) Assign u the value of 4 * (j - 56). Note that an arbitrarily complex expression can appear to the right of the equals sign.

print 10 print w Display the value of w.

goto 70 goto 45 Transfer program control to line 45.

if…goto 35 if i == z goto 80 Compare i and z for equality and transfer control to line 80 if the condition is true; otherwise, continue execution with the next statement.

end 99 end Terminate program execution.

Fig. 21.25 | Simple commands.

cpphtp5_21_DataStructures_IM.fm Page 1300 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1301

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

Using the sample programs of Fig. 21.26, Fig. 21.27 and Fig. 21.28 as your guide, write aSimple program to accomplish each of the following:

a) Input three integers, determine their average and print the result.b) Use a sentinel-controlled loop to input 10 integers and compute and print their sum.c) Use a counter-controlled loop to input seven integers, some positive and some negative,

and compute and print their average.d) Input a series of integers and determine and print the largest. The first integer input in-

dicates how many numbers should be processed.e) Input 10 integers and print the smallest.f) Calculate and print the sum of the even integers from 2 to 30.g) Calculate and print the product of the odd integers from 1 to 9.

1 10 rem determine and print the sum of two integers2 15 rem 3 20 rem input the two integers 4 30 input a5 40 input b6 45 rem7 50 rem add integers and store result in c8 60 let c = a + b9 65 rem

10 70 rem print the result11 80 print c12 90 rem terminate program execution13 99 end

Fig. 21.26 | Simple program that determines the sum of two integers.

1 10 rem determine the larger of two integers2 20 input s3 30 input t4 32 rem5 35 rem test if s >= t 6 40 if s >= t goto 907 45 rem8 50 rem t is greater than s, so print t9 60 print t

10 70 goto 9911 75 rem12 80 rem s is greater than or equal to t, so print s13 90 print s14 99 end

Fig. 21.27 | Simple program that finds the larger of two integers.

1 10 rem calculate the squares of several integers2 20 input j3 23 rem4 25 rem test for sentinel value5 30 if j == -9999 goto 99

Fig. 21.28 | Calculate the squares of several integers. (Part 1 of 2.)

cpphtp5_21_DataStructures_IM.fm Page 1301 Thursday, December 23, 2004 5:00 PM

1302 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.27 (Building a Compiler; Prerequisite: Complete Exercises 8.18, 8.19, 21.12, 21.13 and 21.26)Now that the Simple language has been presented (Exercise 21.26), we discuss how to build a Sim-ple compiler. First, we consider the process by which a Simple program is converted to SML andexecuted by the Simpletron simulator (see Fig. 21.29). A file containing a Simple program is readby the compiler and converted to SML code. The SML code is output to a file on disk, in whichSML instructions appear one per line. The SML file is then loaded into the Simpletron simulator,and the results are sent to a file on disk and to the screen. Note that the Simpletron program devel-oped in Exercise 8.19 took its input from the keyboard. It must be modified to read from a file soit can run the programs produced by our compiler.

The Simple compiler performs two passes of the Simple program to convert it to SML. The firstpass constructs a symbol table (object) in which every line number (object), variable name (object)and constant (object) of the Simple program is stored with its type and corresponding location in thefinal SML code (the symbol table is discussed in detail below). The first pass also produces the corre-sponding SML instruction object(s) for each of the Simple statements (object, etc.). As we will see, ifthe Simple program contains statements that transfer control to a line later in the program, the firstpass results in an SML program containing some “unfinished” instructions. The second pass of thecompiler locates and completes the unfinished instructions, and outputs the SML program to a file.

First PassThe compiler begins by reading one statement of the Simple program into memory. The line mustbe separated into its individual tokens (i.e., “pieces” of a statement) for processing and compilation(standard library function strtok can be used to facilitate this task). Recall that every statementbegins with a line number followed by a command. As the compiler breaks a statement intotokens, if the token is a line number, a variable or a constant, it is placed in the symbol table. A linenumber is placed in the symbol table only if it is the first token in a statement. The symbolTableobject is an array of tableEntry objects representing each symbol in the program. There is norestriction on the number of symbols that can appear in the program. Therefore, the symbolTable

6 33 rem7 35 rem calculate square of j and assign result to k8 40 let k = j * j9 50 print k

10 53 rem11 55 rem loop to get next j12 60 goto 2013 99 end

Fig. 21.29 | Writing, compiling and executing a Simple language program.

Fig. 21.28 | Calculate the squares of several integers. (Part 2 of 2.)

SimpletronSimulator

compilerSimple file SML file

output todisk

output toscreen

cpphtp5_21_DataStructures_IM.fm Page 1302 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1303

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

for a particular program could be large. Make the symbolTable a 100-element array for now. Youcan increase or decrease its size once the program is working.

Each tableEntry object contains three members. Member symbol is an integer containing theASCII representation of a variable (remember that variable names are single characters), a line num-ber or a constant. Member type is one of the following characters indicating the symbol’s type: 'C'for constant, 'L' for line number and 'V' for variable. Member location contains the Simpletronmemory location (00 to 99) to which the symbol refers. Simpletron memory is an array of 100 inte-gers in which SML instructions and data are stored. For a line number, the location is the element inthe Simpletron memory array at which the SML instructions for the Simple statement begin. For avariable or constant, the location is the element in the Simpletron memory array in which the vari-able or constant is stored. Variables and constants are allocated from the end of Simpletron’s memorybackward. The first variable or constant is stored in location at 99, the next in location at 98, etc.

The symbol table plays an integral part in converting Simple programs to SML. We learned inChapter 8 that an SML instruction is a four-digit integer composed of two parts—the operationcode and the operand. The operation code is determined by commands in Simple. For example, thesimple command input corresponds to SML operation code 10 (read), and the Simple commandprint corresponds to SML operation code 11 (write). The operand is a memory location contain-ing the data on which the operation code performs its task (e.g., operation code 10 reads a valuefrom the keyboard and stores it in the memory location specified by the operand). The compilersearches symbolTable to determine the Simpletron memory location for each symbol so the cor-responding location can be used to complete the SML instructions.

The compilation of each Simple statement is based on its command. For example, after theline number in a rem statement is inserted in the symbol table, the remainder of the statement isignored by the compiler because a remark is for documentation purposes only. The input, print,goto and end statements correspond to the SML read, write, branch (to a specific location) and haltinstructions. Statements containing these Simple commands are converted directly to SML (notethat a goto statement may contain an unresolved reference if the specified line number refers to astatement further into the Simple program file; this is sometimes called a forward reference).

When a goto statement is compiled with an unresolved reference, the SML instruction mustbe flagged to indicate that the second pass of the compiler must complete the instruction. The flagsare stored in 100-element array flags of type int in which each element is initialized to -1. If thememory location to which a line number in the Simple program refers is not yet known (i.e., it isnot in the symbol table), the line number is stored in array flags in the element with the same sub-script as the incomplete instruction. The operand of the incomplete instruction is set to 00 tem-porarily. For example, an unconditional branch instruction (making a forward reference) is left as+4000 until the second pass of the compiler. The second pass of the compiler is described shortly.

Compilation of if…goto and let statements is more complicated than for other statements—they are the only statements that produce more than one SML instruction. For an if…goto, thecompiler produces code to test the condition and to branch to another line if necessary. The resultof the branch could be an unresolved reference. Each of the relational and equality operators can besimulated using SML’s branch zero or branch negative instructions (or a combination of both).

For a let statement, the compiler produces code to evaluate an arbitrarily complex arithmeticexpression consisting of integer variables and/or constants. Expressions should separate each oper-and and operator with spaces. Exercise 21.12 and Exercise 21.13 presented the infix-to-postfixconversion algorithm and the postfix evaluation algorithm used by compilers to evaluate expres-sions. Before proceeding with your compiler, you should complete each of these exercises. When acompiler encounters an expression, it converts the expression from infix notation to postfix nota-tion and then evaluates the postfix expression.

How is it that the compiler produces the machine language to evaluate an expression con-taining variables? The postfix evaluation algorithm contains a “hook” where the compiler can gen-

cpphtp5_21_DataStructures_IM.fm Page 1303 Thursday, December 23, 2004 5:00 PM

1304 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

erate SML instructions rather than actually evaluating the expression. To enable this “hook” in thecompiler, the postfix evaluation algorithm must be modified to search the symbol table for eachsymbol it encounters (and possibly insert it), determine the symbol’s corresponding memory loca-tion and push the memory location onto the stack (instead of the symbol). When an operator isencountered in the postfix expression, the two memory locations at the top of the stack are poppedand machine language for effecting the operation is produced, using the memory locations as oper-ands. The result of each subexpression is stored in a temporary location in memory and pushedback onto the stack so that the evaluation of the postfix expression can continue. When postfixevaluation is complete, the memory location containing the result is the only location left on thestack. This is popped, and SML instructions are generated to assign the result to the variable at theleft of the let statement.

Second PassThe second pass of the compiler performs two tasks: Resolve any unresolved references, and outputthe SML code to a file. Resolution of references occurs as follows:

a) Search the flags array for an unresolved reference (i.e., an element with a value otherthan -1).

b) Locate the object in array symbolTable, containing the symbol stored in the flags array(be sure that the type of the symbol is 'L' for line number).

c) Insert the memory location from member location into the instruction with the un-resolved reference (remember that an instruction containing an unresolved referencehas operand 00).

d) Repeat Steps 1, 2 and 3 until the end of the flags array is reached.

After the resolution process is complete, the entire array containing the SML code is output to a diskfile with one SML instruction per line. This file can be read by the Simpletron for execution (afterthe simulator is modified to read its input from a file). Compiling your first Simple program into anSML file and then executing that file should give you a real sense of personal accomplishment.

A Complete ExampleThe following example illustrates a complete conversion of a Simple program to SML as it will beperformed by the Simple compiler. Consider a Simple program that inputs an integer and sums thevalues from 1 to that integer. The program and the SML instructions produced by the first pass ofthe Simple compiler are illustrated in Fig. 21.30. The symbol table constructed by the first pass isshown in Fig. 21.31.

Simple programSML location& instruction Description

5 rem sum 1 to x none rem ignored10 input x 00 +1099 read x into location 9915 rem check y == x none rem ignored20 if y == x goto 60 01 +2098 load y (98) into accumulator

02 +3199 sub x (99) from accumulator03 +4200 branch zero to unresolved location

25 rem increment y none rem ignored

Fig. 21.30 | SML instructions produced after the compiler’s first pass. (Part 1 of 2.)

cpphtp5_21_DataStructures_IM.fm Page 1304 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1305

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

30 let y = y + 1 04 +2098 load y into accumulator05 +3097 add 1 (97) to accumulator06 +2196 store in temporary location 9607 +2096 load from temporary location 96 08 +2198 store accumulator in y

35 rem add y to total none rem ignored40 let t = t + y 09 +2095 load t (95) into accumulator

10 +3098 add y to accumulator11 +2194 store in temporary location 9412 +2094 load from temporary location 94 13 +2195 store accumulator in t

45 rem loop y none rem ignored50 goto 20 14 +4001 branch to location 0155 rem output result none rem ignored60 print t 15 +1195 output t to screen99 end 16 +4300 terminate execution

Symbol Type Location

5 L 00

10 L 00

'x' V 99

15 L 01

20 L 01

'y' V 98

25 L 04

30 L 04

1 C 97

35 L 09

40 L 09

't' V 95

45 L 14

50 L 14

55 L 15

60 L 15

99 L 16

Fig. 21.31 | Symbol table for program of Fig. 21.30.

Simple programSML location& instruction Description

Fig. 21.30 | SML instructions produced after the compiler’s first pass. (Part 2 of 2.)

cpphtp5_21_DataStructures_IM.fm Page 1305 Thursday, December 23, 2004 5:00 PM

1306 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

Most Simple statements convert directly to single SML instructions. The exceptions in thisprogram are remarks, the if…goto statement in line 20 and the let statements. Remarks do nottranslate into machine language. However, the line number for a remark is placed in the symboltable in case the line number is referenced in a goto statement or an if…goto statement. Line 20 ofthe program specifies that if the condition y == x is true, program control is transferred to line 60.Because line 60 appears later in the program, the first pass of the compiler has not as yet placed 60 inthe symbol table (statement line numbers are placed in the symbol table only when they appear asthe first token in a statement). Therefore, it is not possible at this time to determine the operand ofthe SML branch zero instruction at location 03 in the array of SML instructions. The compilerplaces 60 in location 03 of the flags array to indicate that the second pass completes this instruction.

We must keep track of the next instruction location in the SML array, because there is not aone-to-one correspondence between Simple statements and SML instructions. For example, theif…goto statement of line 20 compiles into three SML instructions. Each time an instruction isproduced, we must increment the instruction counter to the next location in the SML array. Notethat the size of Simpletron’s memory could present a problem for Simple programs with manystatements, variables and constants. It is conceivable that the compiler will run out of memory. Totest for this case, your program should contain a data counter to keep track of the location at whichthe next variable or constant will be stored in the SML array. If the value of the instruction counteris larger than the value of the data counter, the SML array is full. In this case, the compilation pro-cess should terminate and the compiler should print an error message indicating that it ran out ofmemory during compilation. This serves to emphasize that, although the programmer is freedfrom the burdens of managing memory by the compiler, the compiler itself must carefully deter-mine the placement of instructions and data in memory, and must check for such errors as memorybeing exhausted during the compilation process.

A Step-by-Step View of the Compilation ProcessLet us now walk through the compilation process for the Simple program in Fig. 21.30. The compilerreads the first line of the program

5 rem sum 1 to x

into memory. The first token in the statement (the line number) is determined using strtok (seeChapter 8 and Chapter 21 for a discussion of C++’s C-style string-manipulation functions). The to-ken returned by strtok is converted to an integer using atoi, so the symbol 5 can be located in thesymbol table. If the symbol is not found, it is inserted in the symbol table. Since we are at the begin-ning of the program and this is the first line, no symbols are in the table yet. So 5 is inserted into thesymbol table as type L (line number) and assigned the first location in SML array (00). Although thisline is a remark, a space in the symbol table is still allocated for the line number (in case it is refer-enced by a goto or an if…goto). No SML instruction is generated for a rem statement, so the instruc-tion counter is not incremented.

The statement

10 input x

is tokenized next. The line number 10 is placed in the symbol table as type L and assigned the firstlocation in the SML array (00, because a remark began the program so the instruction counter iscurrently 00). The command input indicates that the next token is a variable (only a variable canappear in an input statement). Because input corresponds directly to an SML operation code, thecompiler has to determine the location of x in the SML array. Symbol x is not found in the symboltable, so it is inserted into the symbol table as the ASCII representation of x, given type V, andassigned location 99 in the SML array (data storage begins at 99 and is allocated backward). SML

cpphtp5_21_DataStructures_IM.fm Page 1306 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1307

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

code can now be generated for this statement. Operation code 10 (the SML read operation code) ismultiplied by 100, and the location of x (as determined in the symbol table) is added to completethe instruction. The instruction is then stored in the SML array at location 00. The instructioncounter is incremented by 1, because a single SML instruction was produced.

The statement

15 rem check y == x

is tokenized next. The symbol table is searched for line number 15 (which is not found). The linenumber is inserted as type L and assigned the next location in the array, 01 (remember that remstatements do not produce code, so the instruction counter is not incremented).

The statement

20 if y == x goto 60

is tokenized next. Line number 20 is inserted in the symbol table and given type L with the next lo-cation in the SML array 01. The command if indicates that a condition is to be evaluated. The vari-able y is not found in the symbol table, so it is inserted and given the type V and the SML location 98.Next, SML instructions are generated to evaluate the condition. Since there is no direct equivalent inSML for the if…goto, it must be simulated by performing a calculation using x and y and branchingbased on the result. If y is equal to x, the result of subtracting x from y is zero, so the branch zeroinstruction can be used with the result of the calculation to simulate the if…goto statement. The firststep requires that y be loaded (from SML location 98) into the accumulator. This produces the instruc-tion 01 +2098. Next, x is subtracted from the accumulator. This produces the instruction 02 +3199. Thevalue in the accumulator may be zero, positive or negative. Since the operator is ==, we want tobranch zero. First, the symbol table is searched for the branch location (60 in this case), which is notfound. So 60 is placed in the flags array at location 03, and the instruction 03 +4200 is generated (wecannot add the branch location, because we have not assigned a location to line 60 in the SML arrayyet). The instruction counter is incremented to 04.

The compiler proceeds to the statement

25 rem increment y

The line number 25 is inserted in the symbol table as type L and assigned SML location 04. Theinstruction counter is not incremented.

When the statement

30 let y = y + 1

is tokenized, the line number 30 is inserted in the symbol table as type L and assigned SML loca-tion 04. Command let indicates that the line is an assignment statement. First, all the symbols onthe line are inserted in the symbol table (if they are not already there). The integer 1 is added to thesymbol table as type C and assigned SML location 97. Next, the right side of the assignment is con-verted from infix to postfix notation. Then the postfix expression (y 1 +) is evaluated. Symbol y islocated in the symbol table, and its corresponding memory location is pushed onto the stack. Sym-bol 1 is also located in the symbol table, and its corresponding memory location is pushed onto thestack. When the operator + is encountered, the postfix evaluator pops the stack into the right oper-and of the operator, pops the stack again into the left operand of the operator and produces theSML instructions

04 +2098 (load y)05 +3097 (add 1)

The result of the expression is stored in a temporary location in memory (96) with instruction

cpphtp5_21_DataStructures_IM.fm Page 1307 Thursday, December 23, 2004 5:00 PM

1308 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

06 +2196 (store temporary)

and the temporary location is pushed on the stack. Now that the expression has been evaluated, theresult must be stored in y (i.e., the variable on the left side of =). So the temporary location isloaded into the accumulator, and the accumulator is stored in y with the instructions

07 +2096 (load temporary)08 +2198 (store y)

The reader will immediately notice that SML instructions appear to be redundant. We will discussthis issue shortly.

When the statement

35 rem add y to total

is tokenized, line number 35 is inserted in the symbol table as type L and assigned location 09. The statement

40 let t = t + y

is similar to line 30. The variable t is inserted in the symbol table as type V and assigned SMLlocation 95. The instructions follow the same logic and format as line 30, and the instructions 09+2095, 10 +3098, 11 +2194, 12 +2094 and 13 +2195 are generated. Note that the result of t + y isassigned to temporary location 94 before being assigned to t (95). Once again, the reader will notethat the instructions in memory locations 11 and 12 appear to be redundant. Again, we will discussthis shortly.

The statement

45 rem loop y

is a remark, so line 45 is added to the symbol table as type L and assigned SML location 14. The statement

50 goto 20

transfers control to line 20. Line number 50 is inserted in the symbol table as type L and assignedSML location 14. The equivalent of goto in SML is the unconditional branch (40) instruction thattransfers control to a specific SML location. The compiler searches the symbol table for line 20 andfinds that it corresponds to SML location 01. The operation code (40) is multiplied by 100, andlocation 01 is added to it to produce the instruction 14 +4001.

The statement

55 rem output result

is a remark, so line 55 is inserted in the symbol table as type L and assigned SML location 15. The statement

60 print t

is an output statement. Line number 60 is inserted in the symbol table as type L and assigned SMLlocation 15. The equivalent of print in SML is operation code 11 (write). The location of t is de-termined from the symbol table and added to the result of the operation code multiplied by 100.

The statement

99 end

cpphtp5_21_DataStructures_IM.fm Page 1308 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1309

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

is the final line of the program. Line number 99 is stored in the symbol table as type L and assignedSML location 16. The end command produces the SML instruction +4300 (43 is halt in SML),which is written as the final instruction in the SML memory array.

This completes the first pass of the compiler. We now consider the second pass. The flagsarray is searched for values other than -1. Location 03 contains 60, so the compiler knows thatinstruction 03 is incomplete. The compiler completes the instruction by searching the symbol tablefor 60, determining its location and adding the location to the incomplete instruction. In this case,the search determines that line 60 corresponds to SML location 15, so the completed instruction 03+4215 is produced, replacing 03 +4200. The Simple program has now been compiled successfully.

To build the compiler, you will have to perform each of the following tasks:a) Modify the Simpletron simulator program you wrote in Exercise 8.19 to take its input

from a file specified by the user (see Chapter 17). The simulator should output its re-sults to a disk file in the same format as the screen output. Convert the simulator to bean object-oriented program. In particular, make each part of the hardware an object.Arrange the instruction types into a class hierarchy using inheritance. Then execute theprogram polymorphically by telling each instruction to execute itself with an exe-cuteInstruction message.

b) Modify the infix-to-postfix conversion algorithm of Exercise 21.12 to process multi-digit integer operands and single-letter variable name operands. [Hint: C++ StandardLibrary function strtok can be used to locate each constant and variable in an expres-sion, and constants can be converted from strings to integers using standard libraryfunction atoi (<csdtlib>).] [Note: The data representation of the postfix expressionmust be altered to support variable names and integer constants.]

c) Modify the postfix evaluation algorithm to process multidigit integer operands andvariable name operands. Also, the algorithm should now implement the “hook” dis-cussed previously so that SML instructions are produced rather than directly evaluatingthe expression. [Hint: Standard library function strtok can be used to locate each con-stant and variable in an expression, and constants can be converted from strings to in-tegers using standard library function atoi.] [Note: The data representation of thepostfix expression must be altered to support variable names and integer constants.]

d) Build the compiler. Incorporate parts (b) and (c) for evaluating expressions in let state-ments. Your program should contain a function that performs the first pass of the com-piler and a function that performs the second pass of the compiler. Both functions cancall other functions to accomplish their tasks. Make your compiler as object oriented aspossible.

ANS:

1 // Exercise 21.27 Solution: StackNode.h2 // Definition of template class StackNode.3 #ifndef STACKNODE_H4 #define STACKNODE_H56 template < typename T > class Stack;78 template < typename T >9 class StackNode

10 {11 friend class Stack< T >;12 public:13 StackNode( const T & = 0, StackNode * = 0 );14 T getData() const;

cpphtp5_21_DataStructures_IM.fm Page 1309 Thursday, December 23, 2004 5:00 PM

1310 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

15 private:16 T data;17 StackNode *nextPtr;18 }; // end class StackNode1920 // Member function definitions for class StackNode2122 // constructor23 template < typename T >24 StackNode< T >::StackNode( const T &d, StackNode< T > *ptr )25 {26 data = d;27 nextPtr = ptr;28 } // end constructor2930 // get data from node31 template < typename T >32 T StackNode< T >::getData() const 33 { 34 return data; 35 } // end function getData3637 #endif

1 // Exercise 12.27 Solution: Stack.h2 // Definition of class Stack3 #ifndef STACK_H4 #define STACK_H56 #include <iostream> 7 using std::cout; 89 #include <new>

10 #include "StackNode.h"1112 template < typename T >13 class Stack 14 {15 public:16 Stack(); // default constructor17 ~Stack(); // destructor1819 void push( T & ); // insert item in stack20 T pop(); // remove item from stack21 bool isEmpty() const; // is the stack empty?22 T stackTop() const; // return the top element of stack23 void print() const; // output the stack24 private:25 StackNode< T > *topPtr; // pointer to fist StackNode26 }; // end class Stack2728 // Member function definitions for class Stack2930 // constructor

cpphtp5_21_DataStructures_IM.fm Page 1310 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1311

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

31 template < typename T >32 Stack< T >::Stack() 33 { 34 topPtr = 0; 35 } // end Stack constructor3637 // destructor38 template < typename T >39 Stack< T >::~Stack()40 {41 StackNode< T > *tempPtr, *currentPtr = topPtr;4243 while ( currentPtr != 0 ) 44 {45 tempPtr = currentPtr;46 currentPtr = currentPtr->nextPtr;47 delete tempPtr;48 } // end while49 } // end Stack destructor5051 // add new node 52 template < typename T >53 void Stack< T >::push( T &d )54 {55 StackNode< T > *newPtr = new StackNode< T >( d, topPtr );56 topPtr = newPtr;57 } // end function push5859 // take out a node60 template < typename T >61 T Stack< T >::pop()62 {63 StackNode< T > *tempPtr = topPtr;64 topPtr = topPtr->nextPtr;65 T poppedValue = tempPtr->data;66 delete tempPtr;67 return poppedValue;68 } // end function pop6970 // check if stack is empty71 template < typename T >72 bool Stack< T >::isEmpty() const 73 { 74 return topPtr == 0; 75 } // end function isEmpty7677 // return the top node78 template < typename T >79 T Stack< T >::stackTop() const 80 { 81 return !isEmpty() ? topPtr->data : 0; 82 } // end function stackTop8384 // print function85 template < typename T >

cpphtp5_21_DataStructures_IM.fm Page 1311 Thursday, December 23, 2004 5:00 PM

1312 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

86 void Stack< T >::print() const87 {88 StackNode< T > *currentPtr = topPtr;8990 if ( isEmpty() ) // Stack is empty91 cout << "Stack is empty\n";92 else // Stack is not empty93 { 94 cout << "The stack is:\n";9596 while ( currentPtr != 0 ) 97 {98 cout << currentPtr->data << ' ';99 currentPtr = currentPtr->nextPtr;100 } // end while101102 cout << '\n';103 } // end else104 } // end function print105106 #endif

1 // Exercise 21.27 Solution: Compiler.h23 const int MAXIMUM = 81; // maximum length for lines4 const int SYMBOLTABLESIZE = 100; // maximum size of symbol table5 const int MEMORYSIZE = 100; // maximum Simpletron memory67 // Definition of class for symbol table entries8 class TableEntry9 {

10 public:11 int location; // SML memory location 00 to 9912 char type; // 'C' = constant, 'V' = variable,13 int symbol; // or 'L' = line number14 }; // end class TableEntry1516 // Function prototypes for compiler functions17 int checkSymbolTable( TableEntry *, int, char );18 int checkOperand( TableEntry *, char *, int *, int *, int * );19 void addToSymbolTable( char, int, int, TableEntry *, int );20 void addLineToFlags( int, int, int *, int *, const int * );21 void compile( ifstream &, char * );22 void printOutput( const int [], char * );23 void lineNumber( char *, TableEntry *, int, int );24 void initArrays( int *, int *, TableEntry * );25 void firstPass( int *, int *, TableEntry *, ifstream & );26 void secondPass( int *, int *, TableEntry * );27 void separateToken( char *, int *, int *, TableEntry *, int *, int * );28 void keyWord( char *, int *, int *, TableEntry *, int *, int * );29 void keyLet( char *, int *, TableEntry *, int *, int * );30 void keyInput( char *, int *, TableEntry *, int *, int * );31 void keyPrint( char *, int *, TableEntry *, int *, int * );32 void keyGoto( char *, int *, int *, TableEntry *, int * );

cpphtp5_21_DataStructures_IM.fm Page 1312 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1313

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

33 void keyIfGoto( char *, int *, int *, TableEntry *, int *, int * );34 void evaluateExpression( int, int, char *, int *, TableEntry *, 35 int *, int *, char * );36 int createLetSML( int, int, int *, int *, int *, char );37 void infixToPostfix( char *, char *, int, TableEntry *, 38 int *, int *, int * );39 void evaluatePostfix( char *, int *, int *, int *, int, TableEntry * );40 bool isOperator( char );41 bool precedence( char, char );4243 // Simpletron Machine Language (SML) Operation Codes44 enum SMLOperationCodes { READ = 10, WRITE = 11, LOAD = 20, STORE = 21, 45 ADD = 30, SUBTRACT = 31, DIVIDE = 32, MULTIPLY = 33, BRANCH = 40, 46 BRANCHNEG = 41, BRANCHZERO = 42, HALT = 43 47 }; // end enum SMLOperationCodes

1 // Exercise 21.27 Solution: Ex21_27.cpp2 // Non-optimized version.3 #include <iostream> 4 using std::cout; 5 using std::cin; 6 using std::ios;7 using std::cerr;89 #include <iomanip>

10 using std::setw; 1112 #include <cstdlib>13 using std::atoi;1415 #include <cctype>16 using std::isalnum;17 using std::isdigit;18 using std::isalpha;1920 #include <fstream>21 using std::ifstream;22 using std::ofstream;2324 #include "Stack.h"25 #include "Compiler.h"2627 int main()28 {29 char inFileName[ 15 ] = "";30 char outFileName[ 15 ] = "";31 int last = 0;3233 cout << "Enter Simple file to be compiled: ";34 cin >> setw( 15 ) >> inFileName;3536 while ( isalnum( inFileName[ last ] ) != 0 )37 {38 outFileName[ last ] = inFileName[ last ];

cpphtp5_21_DataStructures_IM.fm Page 1313 Thursday, December 23, 2004 5:00 PM

1314 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

39 last++; // note the last occurrence40 } // end while4142 outFileName[ last ] = '\0'; // append a NULL character43 strcat( outFileName, ".sml" ); // add .sml to name4445 ifstream inFile( inFileName, ios::in );4647 if ( inFile )48 compile( inFile, outFileName );49 else50 cerr << "File not opened. Program execution terminating.\n";5152 return 0; // indicates successful termination53 } // end main5455 // compile function calls the first pass and the second pass56 void compile( ifstream &input, char *outFileName )57 {58 TableEntry symbolTable[ SYMBOLTABLESIZE ]; // symbol table59 int flags[ MEMORYSIZE ]; // array for forward references60 int machineArray[ MEMORYSIZE ]; // array for SML instructions6162 initArrays( flags, machineArray, symbolTable );63 firstPass( flags, machineArray, symbolTable, input );64 secondPass( flags, machineArray, symbolTable );65 printOutput( machineArray, outFileName );66 } // end function compile6768 // firstPass constructs the symbol table, creates SML, and flags 69 // unresolved references for goto and if…goto statements.70 void firstPass( int flags[], int machineArray[], TableEntry symbolTable[],71 ifstream &input )72 {73 char array[ MAXIMUM ]; // array to copy a Simple line74 int n = MAXIMUM; // required for fgets()75 int dataCounter = MEMORYSIZE - 1; // 1st data location in machineArray76 int instCounter = 0; // 1st instruction location in machineArray7778 input.getline( array, n );7980 while ( !input.eof() ) 81 {82 separateToken( array, flags, machineArray, symbolTable,83 &dataCounter, &instCounter );84 input.getline( array, n );85 } // end while86 } // end function firstPass8788 // separateToken tokenizes a Simple statement, process the line number,89 // and passes the next token to keyWord for processing.90 void separateToken( char array[], int flags[], int machineArray[],91 TableEntry symbolTable[], int *dataCounterPtr, int *instCounterPtr )92 {93 char *tokenPtr = strtok( array, " " ); // tokenize line

cpphtp5_21_DataStructures_IM.fm Page 1314 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1315

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

9495 lineNumber( tokenPtr, symbolTable, *instCounterPtr, *dataCounterPtr );9697 tokenPtr = strtok( 0, " \n" ); // get next token98 99 keyWord( tokenPtr, flags, machineArray, symbolTable, dataCounterPtr,100 instCounterPtr );101 } // end function separateToken102103 // checkSymbolTable searches the symbol table and returns104 // the symbols SML location or a -1 if not found.105 int checkSymbolTable( TableEntry symbolTable[], int symbol, char type )106 {107 for ( int loop = 0; loop < SYMBOLTABLESIZE; loop++ )108 if ( ( symbol == symbolTable[ loop ].symbol ) && 109 ( type == symbolTable[ loop ].type ) )110 return symbolTable[ loop ].location; // return SML location111112 return -1; // symbol not found113 } // end function checkSymbolTable114115 // lineNumber processes line numbers116 void lineNumber( char *tokenPtr, TableEntry symbolTable[],117 int instCounter, int dataCounter )118 {119 const char type = 'L';120 int symbol;121122 if ( isdigit( tokenPtr[ 0 ] ) )123 {124 symbol = atoi( tokenPtr );125126 if ( -1 == checkSymbolTable( symbolTable, symbol, type ) )127 addToSymbolTable( type, symbol, dataCounter, symbolTable, 128 instCounter );129 } // end if130 } // end function lineNumber131132 // keyWord determines the key word type and calls the appropriate function133 void keyWord( char *tokenPtr, int flags[], int machineArray[],134 TableEntry symbolTable[], int *dataCounterPtr, int *instCounterPtr )135 {136 if ( strcmp( tokenPtr, "rem" ) == 0 )137 ; // no instructions are generated by comments138 else if ( strcmp( tokenPtr, "input" ) == 0 ) 139 {140 tokenPtr = strtok( 0, " " ); // assign pointer to next token141 142 keyInput( tokenPtr, machineArray, symbolTable, dataCounterPtr,143 instCounterPtr );144 } // end else if145 else if ( strcmp( tokenPtr, "print" ) == 0 ) 146 {147 tokenPtr = strtok( 0, " " ); // assign pointer to next token148

cpphtp5_21_DataStructures_IM.fm Page 1315 Thursday, December 23, 2004 5:00 PM

1316 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

149 keyPrint( tokenPtr, machineArray, symbolTable, dataCounterPtr,150 instCounterPtr );151 } // end else if152 else if ( strcmp( tokenPtr, "goto" ) == 0 ) 153 {154 tokenPtr = strtok( 0, " " ); // assign pointer to next token155156 keyGoto( tokenPtr, flags, machineArray, symbolTable,157 instCounterPtr );158 } // end else if159 else if ( strcmp( tokenPtr, "if" ) == 0 ) 160 {161 tokenPtr = strtok( 0, " " ); // assign pointer to next token162163 keyIfGoto( tokenPtr, flags, machineArray, symbolTable, 164 dataCounterPtr, instCounterPtr );165 } // end else if166 else if ( strcmp( tokenPtr, "end" ) == 0 ) 167 {168 machineArray[ *instCounterPtr ] = HALT * 100;169 ( *instCounterPtr )++;170 tokenPtr = 0; // assign tokenPtr to 0171 } // end else if172 else if ( strcmp( tokenPtr, "let" ) == 0 ) 173 {174 tokenPtr = strtok( 0, " " ); // assign pointer to next token175176 keyLet( tokenPtr, machineArray, symbolTable, dataCounterPtr,177 instCounterPtr );178 } // end else if179 } // end function keyWord180181 // keyInput process input keywords182 void keyInput( char *tokenPtr, int machineArray[], TableEntry 183 symbolTable[], int *dataCounterPtr, int *instCounterPtr )184 {185 const char type = 'V';186187 machineArray[ *instCounterPtr ] = READ * 100;188 int symbol = tokenPtr[ 0 ];189 int tableTest = checkSymbolTable( symbolTable, symbol, type );190191 if ( -1 == tableTest ) 192 {193 addToSymbolTable( type, symbol, *dataCounterPtr, symbolTable,194 *instCounterPtr );195 machineArray[ *instCounterPtr ] += *dataCounterPtr;196 ( *dataCounterPtr )--;197 } // end if198 else199 machineArray[ *instCounterPtr ] += tableTest;200201 ( *instCounterPtr )++;202 } // end function keyInput203

cpphtp5_21_DataStructures_IM.fm Page 1316 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1317

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

204 // keyPrint process print keywords205 void keyPrint( char *tokenPtr, int machineArray[], 206 TableEntry symbolTable[], int *dataCounterPtr, int *instCounterPtr )207 {208 const char type = 'V';209210 machineArray[ *instCounterPtr ] = WRITE * 100;211 int symbol = tokenPtr[ 0 ];212 int tableTest = checkSymbolTable( symbolTable, symbol, type );213214 if ( -1 == tableTest ) 215 {216 addToSymbolTable( type, symbol, *dataCounterPtr, symbolTable,217 *instCounterPtr );218 machineArray[*instCounterPtr] += *dataCounterPtr;219 ( *dataCounterPtr )--;220 } // end if221 else222 machineArray[ *instCounterPtr ] += tableTest;223224 ( *instCounterPtr )++;225 } // end function keyPrint226227 // keyGoto process goto keywords228 void keyGoto( char *tokenPtr, int flags[], int machineArray[],229 TableEntry symbolTable[], int *instCounterPtr )230 {231 const char type = 'L';232233 machineArray[*instCounterPtr] = BRANCH * 100;234 int symbol = atoi( tokenPtr );235 int tableTest = checkSymbolTable( symbolTable, symbol, type );236 addLineToFlags( tableTest, symbol, flags, machineArray, 237 instCounterPtr );238 ( *instCounterPtr )++;239 } // end function keyGoto240241 // keyIfGoto process if…goto commands242 void keyIfGoto( char *tokenPtr, int flags[], int machineArray[],243 TableEntry symbolTable[], int *dataCounterPtr, int *instCounterPtr )244 {245 int operand1Loc = checkOperand( symbolTable, tokenPtr, dataCounterPtr,246 instCounterPtr, machineArray );247248 char *operatorPtr = strtok( 0, " " ); // get the operator249250 // get the right operand of comparison operator251 tokenPtr = strtok( 0, " " ); 252253 int operand2Loc = checkOperand( symbolTable, tokenPtr, dataCounterPtr,254 instCounterPtr, machineArray );255256 tokenPtr = strtok( 0, " " ); // read in the goto keyword257258 char *gotoLinePtr = strtok( 0, " " ); // read in the goto line number

cpphtp5_21_DataStructures_IM.fm Page 1317 Thursday, December 23, 2004 5:00 PM

1318 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

259260 evaluateExpression( operand1Loc, operand2Loc, operatorPtr, 261 machineArray, symbolTable, instCounterPtr, flags, gotoLinePtr );262 } // end function keyIfGoto263264 // checkOperand ensures that the operands of an if…goto statement are265 // in the symbol table.266 int checkOperand( TableEntry symbolTable[], char *symPtr, 267 int *dataCounterPtr, int *instCounterPtr, int machineArray[] )268 {269 char type;270 int tableTest;271 int operand;272 int temp;273274 if ( isalpha( symPtr[ 0 ] ) ) 275 {276 type = 'V';277 operand = symPtr[ 0 ];278 tableTest = checkSymbolTable( symbolTable, operand, type );279280 if ( tableTest == -1 ) 281 {282 addToSymbolTable( type, operand, *dataCounterPtr, symbolTable,283 *instCounterPtr );284 temp = *dataCounterPtr;285 ( *dataCounterPtr )--;286 return temp;287 } // end if288 else289 return tableTest;290 } // end if291 // if the symbol is a digit or a signed digit292 else if ( isdigit( symPtr[ 0 ] ) || 293 ( ( symPtr[ 0 ] == '-' || symPtr[ 0 ] == '+' ) && 294 isdigit( symPtr[ 1 ] ) != 0 ) )295 {296 type = 'C';297 operand = atoi( symPtr );298 tableTest = checkSymbolTable( symbolTable, operand, type );299300 if ( tableTest == -1 )301 {302 addToSymbolTable( type, operand, *dataCounterPtr, symbolTable,303 *instCounterPtr );304 machineArray[ *dataCounterPtr ] = operand;305 temp = *dataCounterPtr;306 ( *dataCounterPtr )--;307 return temp ;308 } // end if309 else310 return tableTest;311 } // end else if312313 return 0; // default return for compilation purposes

cpphtp5_21_DataStructures_IM.fm Page 1318 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1319

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

314 } // end function checkOperand315316 // evaluateExpression creates SML for conditional operators317 void evaluateExpression( int operator1Loc, int operator2Loc, 318 char *operandPtr, int machineArray[], TableEntry symbolTable[], 319 int *instCounterPtr, int flags[], char *gotoLinePtr )320 {321 const char type = 'L';322 int tableTest;323 int symbol;324325 if ( strcmp( operandPtr, "==" ) == 0 )326 {327 machineArray[ *instCounterPtr ] = LOAD * 100;328 machineArray[ *instCounterPtr ] += operator1Loc;329 ( *instCounterPtr )++;330331 machineArray[ *instCounterPtr ] = SUBTRACT * 100;332 machineArray[ *instCounterPtr ] += operator2Loc;333 ( *instCounterPtr )++;334335 machineArray[ *instCounterPtr ] = BRANCHZERO * 100;336337 symbol = atoi( gotoLinePtr );338 tableTest = checkSymbolTable( symbolTable, symbol, type );339 addLineToFlags( tableTest, symbol, flags, machineArray, 340 instCounterPtr );341 ( *instCounterPtr )++;342 } // end if343 else if ( strcmp( operandPtr, "!=" ) == 0 )344 {345 machineArray[ *instCounterPtr ] = LOAD * 100;346 machineArray[ *instCounterPtr ] += operator2Loc;347 ( *instCounterPtr )++;348349 machineArray[ *instCounterPtr ] = SUBTRACT * 100;350 machineArray[ *instCounterPtr ] += operator1Loc;351 ( *instCounterPtr )++;352353 machineArray[ *instCounterPtr ] = BRANCHNEG * 100;354355 symbol = atoi( gotoLinePtr );356 tableTest = checkSymbolTable( symbolTable, symbol, type );357358 addLineToFlags( tableTest, symbol, flags, machineArray, 359 instCounterPtr );360 ( *instCounterPtr )++; 361362 machineArray[ *instCounterPtr ] = LOAD * 100;363 machineArray[ *instCounterPtr ] += operator1Loc;364 ( *instCounterPtr )++;365366 machineArray[ *instCounterPtr ] = SUBTRACT * 100;367 machineArray[ *instCounterPtr ] += operator2Loc;368 ( *instCounterPtr )++;

cpphtp5_21_DataStructures_IM.fm Page 1319 Thursday, December 23, 2004 5:00 PM

1320 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

369370 machineArray[ *instCounterPtr ] = BRANCHNEG * 100;371372 symbol = atoi( gotoLinePtr );373 tableTest = checkSymbolTable( symbolTable, symbol, type );374375 addLineToFlags( tableTest, symbol, flags, machineArray, 376 instCounterPtr );377 ( *instCounterPtr )++;378 } // end else if379 else if ( strcmp( operandPtr, ">" ) == 0 ) 380 {381 machineArray[ *instCounterPtr ] = LOAD * 100;382 machineArray[ *instCounterPtr ] += operator2Loc;383 ( *instCounterPtr )++;384385 machineArray[ *instCounterPtr ] = SUBTRACT * 100;386 machineArray[ *instCounterPtr ] += operator1Loc;387 ( *instCounterPtr )++;388389 machineArray[ *instCounterPtr ] = BRANCHNEG * 100;390391 symbol = atoi( gotoLinePtr );392 tableTest = checkSymbolTable( symbolTable, symbol, type );393394 addLineToFlags( tableTest, symbol, flags, machineArray, 395 instCounterPtr );396 ( *instCounterPtr )++;397 } // end else if398 else if ( strcmp( operandPtr, "<" ) == 0 ) 399 {400 machineArray[ *instCounterPtr ] = LOAD * 100;401 machineArray[ *instCounterPtr ] += operator1Loc;402 ( *instCounterPtr )++;403404 machineArray[ *instCounterPtr ] = SUBTRACT * 100;405 machineArray[ *instCounterPtr ] += operator2Loc;406 ( *instCounterPtr )++;407408 machineArray[ *instCounterPtr ] = BRANCHNEG * 100;409410 symbol = atoi( gotoLinePtr );411 tableTest = checkSymbolTable( symbolTable, symbol, type );412413 addLineToFlags( tableTest, symbol, flags, machineArray, 414 instCounterPtr );415 ( *instCounterPtr )++;416 } // end else if417 else if ( strcmp( operandPtr, ">=" ) == 0 )418 {419 machineArray[ *instCounterPtr ] = LOAD * 100;420 machineArray[ *instCounterPtr ] += operator2Loc;421 ( *instCounterPtr )++;422423 machineArray[ *instCounterPtr ] = SUBTRACT * 100;

cpphtp5_21_DataStructures_IM.fm Page 1320 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1321

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

424 machineArray[ *instCounterPtr ] += operator1Loc;425 ( *instCounterPtr )++;426427 machineArray[ *instCounterPtr ] = BRANCHNEG * 100;428429 symbol = atoi( gotoLinePtr );430 tableTest = checkSymbolTable( symbolTable, symbol, type );431432 addLineToFlags( tableTest, symbol, flags, machineArray, 433 instCounterPtr );434 ( *instCounterPtr )++;435436 machineArray[ *instCounterPtr ] = BRANCHZERO * 100;437438 addLineToFlags( tableTest, symbol, flags, machineArray, 439 instCounterPtr );440 ( *instCounterPtr )++;441 } // end else if442 else if ( strcmp( operandPtr, "<=" ) == 0 )443 {444 machineArray[ *instCounterPtr ] = LOAD * 100;445 machineArray[ *instCounterPtr ] += operator1Loc;446 ( *instCounterPtr )++;447448 machineArray[ *instCounterPtr ] = SUBTRACT * 100;449 machineArray[ *instCounterPtr ] += operator2Loc;450 ( *instCounterPtr )++;451452 machineArray[ *instCounterPtr ] = BRANCHNEG * 100;453454 symbol = atoi( gotoLinePtr );455 tableTest = checkSymbolTable( symbolTable, symbol, type );456457 addLineToFlags( tableTest, symbol, flags, machineArray, 458 instCounterPtr );459 ( *instCounterPtr )++;460461 machineArray[ *instCounterPtr ] = BRANCHZERO * 100;462463 addLineToFlags( tableTest, symbol, flags, machineArray, 464 instCounterPtr );465 ( *instCounterPtr )++;466 } // end else if467 } // end function evaluateExpression468469 // secondPass resolves incomplete SML instructions for forward references470 void secondPass( int flags[], int machineArray[], 471 TableEntry symbolTable[] )472 {473 const char type = 'L';474475 for ( int loop = 0; loop < MEMORYSIZE; loop++ ) 476 {477 if ( flags[ loop ] != -1 ) 478 {

cpphtp5_21_DataStructures_IM.fm Page 1321 Thursday, December 23, 2004 5:00 PM

1322 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

479 int symbol = flags[ loop ];480 int flagLocation = checkSymbolTable( symbolTable, symbol, type );481 machineArray[ loop ] += flagLocation;482 } // end if483 } // end for484 } // end function secondPass485486 // keyLet processes the keyword let487 void keyLet( char *tokenPtr, int machineArray[], TableEntry symbolTable[],488 int *dataCounterPtr, int *instCounterPtr )489 {490 const char type = 'V';491 char infixArray[ MAXIMUM ] = "";492 char postfixArray[ MAXIMUM ] = "";493 int tableTest;494 int symbol;495 int location;496 static int subscript = 0;497498 symbol = tokenPtr[ 0 ];499 tableTest = checkSymbolTable( symbolTable, symbol, type );500501 if ( -1 == tableTest ) 502 {503 addToSymbolTable( type, symbol, *dataCounterPtr, symbolTable,504 *instCounterPtr );505 location = *dataCounterPtr;506 ( *dataCounterPtr )--;507 } // end if508 else509 location = tableTest;510511 tokenPtr = strtok( 0, " " ); // grab equal sign512 tokenPtr = strtok( 0, " " ); // get next token513514 while ( tokenPtr != 0 ) 515 {516 checkOperand( symbolTable, tokenPtr, dataCounterPtr,517 instCounterPtr, machineArray );518 infixArray[ subscript ] = tokenPtr[ 0 ];519 subscript++;520 tokenPtr = strtok( 0, " " ); // get next token521 } // end while522523 infixArray[ subscript ] = '\0';524525 infixToPostfix( infixArray, postfixArray, location, symbolTable,526 instCounterPtr, dataCounterPtr, machineArray );527528 subscript = 0; // reset static subscript when done529 } // end function keyLet530531 void addToSymbolTable( char type, int symbol, int dataCounter,532 TableEntry symbolTable[], int instCounter )533 {

cpphtp5_21_DataStructures_IM.fm Page 1322 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1323

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

534 static int symbolCounter = 0;535536 symbolTable[ symbolCounter ].type = type;537 symbolTable[ symbolCounter ].symbol = symbol;538539 if ( type == 'V' || type == 'C' )540 symbolTable[ symbolCounter ].location = dataCounter;541 else542 symbolTable[ symbolCounter ].location = instCounter;543544 symbolCounter++;545 } // end function addToSymbolTable546547 void addLineToFlags( int tableTest, int symbol, int flags[],548 int machineArray[], const int *instCounterPtr )549 {550 if ( tableTest == -1 )551 flags[ *instCounterPtr ] = symbol;552 else553 machineArray[ *instCounterPtr ] += tableTest;554 } // end function addLineToFlags555556 void printOutput( const int machineArray[], char *outFileName )557 {558 ofstream output( outFileName, ios::out );559560 if ( !output )561 cerr << "File was not opened.\n";562 else // output every memory cell563 for ( int loop = 0; loop <= MEMORYSIZE - 1; loop++ )564 output << machineArray[ loop ] << '\n';565 } // end function printOutput566567 void initArrays( int flags[], int machineArray[], 568 TableEntry symbolTable[] )569 {570 TableEntry initEntry = { 0, 0, -1 };571572 for ( int loop = 0; loop < MEMORYSIZE; loop++ ) 573 {574 flags[ loop ] = -1;575 machineArray[ loop ] = 0;576 symbolTable[ loop ] = initEntry;577 } // end for578 } // end function initArrays579580 //////////////////////////////////////////////////////////////////////////581 // INFIX TO POSTFIX CONVERSION and POSTFIX EVALUATION FOR LET STATEMENT //582 //////////////////////////////////////////////////////////////////////////583584 // infixToPostfix converts an infix expression to a postfix expression585 void infixToPostfix( char infix[], char postfix[], int getsVariable,586 TableEntry symbolTable[], int *instCounterPtr, int *dataCounterPtr, 587 int machineArray[] )588 {

cpphtp5_21_DataStructures_IM.fm Page 1323 Thursday, December 23, 2004 5:00 PM

1324 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

589 Stack< int > intStack;590 int infixCount;591 int postfixCount;592 int popValue;593 bool higher;594 int leftParen = '('; // made int595596 // push a left paren onto the stack and add a right paren to infix597 intStack.push( leftParen );598 strcat( infix, ")" );599600 // convert the infix expression to postfix601 for ( infixCount = 0, postfixCount = 0; intStack.stackTop(); 602 infixCount++ ) 603 {604 if ( isalnum( infix[ infixCount ] ) )605 postfix[ postfixCount++ ] = infix[ infixCount ];606 else if ( infix[ infixCount ] == '(' )607 intStack.push( leftParen );608 else if ( isOperator( infix[ infixCount ] ) ) 609 {610 higher = true; // used to store value of precedence test611 612 while ( higher ) 613 {614 if ( isOperator( 615 static_cast< char >( intStack.stackTop() ) ) )616 if ( precedence( 617 static_cast< char >( intStack.stackTop() ), 618 infix[ infixCount ] ) ) 619 postfix[ postfixCount++ ] = 620 static_cast< char >( intStack.pop() );621 else622 higher = false;623 else624 higher = false;625 } // end while626627 // See chapter 24 for a discussion of reinterpret_cast628 intStack.push( 629 reinterpret_cast< int & > ( infix[ infixCount ] ) );630 } // end else if631 else if ( infix[ infixCount ] == ')' )632 while ( ( popValue = intStack.pop() ) != '(' )633 postfix[ postfixCount++ ] = static_cast< char >( popValue );634 } // end for loop635636 postfix[ postfixCount ] = '\0';637638 evaluatePostfix( postfix, dataCounterPtr, instCounterPtr,639 machineArray, getsVariable, symbolTable );640 } // end function infixToPostfix641642 // check if c is an operator643 bool isOperator( char c )

cpphtp5_21_DataStructures_IM.fm Page 1324 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1325

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

644 {645 if ( c == '+' || c == '-' || c == '*' || c == '/' || c == '^' )646 return true;647 else648 return false;649 } // end function isOperator650651 // If the precedence of operator1 is >= operator2,652 bool precedence( char operator1, char operator2 )653 {654 if ( operator1 == '^' )655 return true;656 else if ( operator2 == '^' )657 return false;658 else if ( operator1 == '*' || operator1 == '/' )659 return true;660 else if ( operator1 == '+' || operator1 == '-' )661 if ( operator2 == '*' || operator2 == '/' )662 return false;663 else664 return true;665666 return false;667 } // end function precedence668669 // evaluate postfix expression and produce code670 void evaluatePostfix( char *expr, int *dataCounterPtr,671 int *instCounterPtr, int machineArray[],672 int getsVariable, TableEntry symbolTable[] )673 {674 Stack< int > intStack;675 int popRightValue;676 int popLeftValue;677 int accumResult;678 int symbolLocation;679 int symbol;680 char type;681 char array[ 2 ] = "";682 int i;683684 strcat( expr, ")" );685 686 for ( i = 0; expr[ i ] != ')'; i++ )687688 if ( isdigit( expr[ i ] ) ) 689 {690 type = 'C';691 array[ 0 ] = expr[ i ];692 symbol = atoi( array );693694 symbolLocation = checkSymbolTable( symbolTable, symbol, type );695 intStack.push( symbolLocation );696 } // end if697 else if ( isalpha( expr[ i ] ) ) 698 {

cpphtp5_21_DataStructures_IM.fm Page 1325 Thursday, December 23, 2004 5:00 PM

1326 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

699 type = 'V';700 symbol = expr[ i ];701 symbolLocation = checkSymbolTable( symbolTable, symbol, type );702 intStack.push( symbolLocation );703 } // end else if704 else 705 {706 popRightValue = intStack.pop();707 popLeftValue = intStack.pop();708 accumResult = createLetSML( popRightValue, popLeftValue, 709 machineArray, instCounterPtr, dataCounterPtr, expr[ i ] ); 710 intStack.push( accumResult );711 } // end else if712713 machineArray[ *instCounterPtr ] = LOAD * 100;714 machineArray[ *instCounterPtr ] += intStack.pop();715 ( *instCounterPtr )++;716 machineArray[ *instCounterPtr ] = STORE * 100;717 machineArray[ *instCounterPtr ] += getsVariable;718 ( *instCounterPtr )++;719 } // end function evaluatePostfix720721 int createLetSML( int right, int left, int machineArray[],722 int *instCounterPtr, int *dataCounterPtr, char oper )723 {724 int location;725726 switch ( oper ) 727 {728 case '+':729 machineArray[ *instCounterPtr ] = LOAD * 100;730 machineArray[ *instCounterPtr ] += left;731 ( *instCounterPtr )++;732 machineArray[ *instCounterPtr ] = ADD * 100;733 machineArray[ *instCounterPtr ] += right;734 ( *instCounterPtr )++;735 machineArray[ *instCounterPtr ] = STORE * 100;736 machineArray[ *instCounterPtr ] += *dataCounterPtr;737 location = *dataCounterPtr;738 ( *dataCounterPtr )--;739 ( *instCounterPtr )++;740 return location;741 case '-':742 machineArray[ *instCounterPtr ] = LOAD * 100;743 machineArray[ *instCounterPtr ] += left;744 ( *instCounterPtr )++;745 machineArray[ *instCounterPtr ] = SUBTRACT * 100;746 machineArray[ *instCounterPtr ] += right;747 ( *instCounterPtr )++;748 machineArray[ *instCounterPtr ] = STORE * 100;749 machineArray[ *instCounterPtr ] += *dataCounterPtr;750 location = *dataCounterPtr;751 ( *dataCounterPtr )--;752 ( *instCounterPtr )++;753 return location;

cpphtp5_21_DataStructures_IM.fm Page 1326 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1327

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.28 (Optimizing the Simple Compiler) When a program is compiled and converted into SML, aset of instructions is generated. Certain combinations of instructions often repeat themselves, usu-ally in triplets called productions. A production normally consists of three instructions such as load,add and store. For example, Fig. 21.32 illustrates five of the SML instructions that were producedin the compilation of the program in Fig. 21.30. The first three instructions are the production thatadds 1 to y. Note that instructions 06 and 07 store the accumulator value in temporary location 96and load the value back into the accumulator so instruction 08 can store the value in location 98.Often a production is followed by a load instruction for the same location that was just stored. Thiscode can be optimized by eliminating the store instruction and the subsequent load instruction thatoperate on the same memory location, thus enabling the Simpletron to execute the program faster.Figure 21.33 illustrates the optimized SML for the program of Fig. 21.30. Note that there are fourfewer instructions in the optimized code—a memory-space savings of 25 percent.

Modify the compiler to provide an option for optimizing the Simpletron Machine Languagecode it produces. Manually compare the nonoptimized code with the optimized code, and calcu-late the percentage reduction.

754 case '/':755 machineArray[ *instCounterPtr ] = LOAD * 100;756 machineArray[ *instCounterPtr ] += left;757 ( *instCounterPtr )++;758 machineArray[ *instCounterPtr ] = DIVIDE * 100;759 machineArray[ *instCounterPtr ] += right;760 ( *instCounterPtr )++;761 machineArray[ *instCounterPtr ] = STORE * 100;762 machineArray[ *instCounterPtr ] += *dataCounterPtr;763 location = *dataCounterPtr;764 ( *dataCounterPtr )--;765 ( *instCounterPtr )++;766 return location;767 case '*':768 machineArray[ *instCounterPtr ] = LOAD * 100;769 machineArray[ *instCounterPtr ] += left;770 ( *instCounterPtr )++;771 machineArray[ *instCounterPtr ] = MULTIPLY * 100;772 machineArray[ *instCounterPtr ] += right;773 ( *instCounterPtr )++;774 machineArray[ *instCounterPtr ] = STORE * 100;775 machineArray[ *instCounterPtr ] += *dataCounterPtr;776 location = *dataCounterPtr;777 ( *dataCounterPtr )--;778 ( *instCounterPtr )++;779 return location;780 default:781 cerr << "ERROR: operator not recognized.\n";782 break;783 } // end switch784785 return 0; // default return786 } // end function createLetSML

cpphtp5_21_DataStructures_IM.fm Page 1327 Thursday, December 23, 2004 5:00 PM

1328 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.29 (Modifications to the Simple Compiler) Perform the following modifications to the Simplecompiler. Some of these modifications may also require modifications to the Simpletron Simulatorprogram written in Exercise 8.19.

a) Allow the modulus operator (%) to be used in let statements. Simpletron Machine Lan-guage must be modified to include a modulus instruction.

b) Allow exponentiation in a let statement using ^ as the exponentiation operator. Sim-pletron Machine Language must be modified to include an exponentiation instruction.

c) Allow the compiler to recognize uppercase and lowercase letters in Simple statements(e.g., 'A' is equivalent to 'a'). No modifications to the Simulator are required.

d) Allow input statements to read values for multiple variables such as input x, y. Nomodifications to the Simpletron Simulator are required.

1 04 +2098 (load)2 05 +3097 (add)3 06 +2196 (store)4 07 +2096 (load)5 08 +2198 (store)

Fig. 21.32 | Nonoptimized code from the program of Fig. 21.30.

Simple programSML location& instruction Description

5 rem sum 1 to x none rem ignored

10 input x 00 +1099 read x into location 99

15 rem check y == x none rem ignored

20 if y == x goto 60 01 +2098 load y (98) into accumulator

02 +3199 sub x (99) from accumulator

03 +4211 branch to location 11 if zero

25 rem increment y none rem ignored

30 let y = y + 1 04 +2098 load y into accumulator

05 +3097 add 1 (97) to accumulator

06 +2198 store accumulator in y (98)

35 rem add y to total none rem ignored

40 let t = t + y 07 +2096 load t from location (96)

08 +3098 add y (98) accumulator

09 +2196 store accumulator in t (96)

45 rem loop y none rem ignored

50 goto 20 10 +4001 branch to location 01

55 rem output result none rem ignored

60 print t 11 +1196 output t (96) to screen

99 end 12 +4300 terminate execution

Fig. 21.33 | Optimized code for the program of Fig. 21.30.

cpphtp5_21_DataStructures_IM.fm Page 1328 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1329

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

e) Allow the compiler to output multiple values in a single print statement such as printa, b, c. No modifications to the Simpletron Simulator are required.

f) Add syntax-checking capabilities to the compiler so error messages are output when syn-tax errors are encountered in a Simple program. No modifications to the SimpletronSimulator are required.

g) Allow arrays of integers. No modifications to the Simpletron Simulator are required.h) Allow subroutines specified by the Simple commands gosub and return. Command go-

sub passes program control to a subroutine, and command return passes control backto the statement after the gosub. This is similar to a function call in C++. The same sub-routine can be called from many gosub commands distributed throughout a program.No modifications to the Simpletron Simulator are required.

i) Allow repetition statements of the form

for x = 2 to 10 step 2 Simple statementsnext

This for statement loops from 2 to 10 with an increment of 2. The next line marks theend of the body of the for. No modifications to the Simpletron Simulator are required.

j) Allow repetition statements of the form

for x = 2 to 10 Simple statementsnext

This for statement loops from 2 to 10 with a default increment of 1. No modificationsto the Simpletron Simulator are required.

k) Allow the compiler to process string input and output. This requires the Simpletron Sim-ulator to be modified to process and store string values. [Hint: Each Simpletron word canbe divided into two groups, each holding a two-digit integer. Each two-digit integer rep-resents the ASCII decimal equivalent of a character. Add a machine-language instructionthat will print a string beginning at a certain Simpletron memory location. The first halfof the word at that location is a count of the number of characters in the string (i.e., thelength of the string). Each succeeding half word contains one ASCII character expressedas two decimal digits. The machine-language instruction checks the length and prints thestring by translating each two-digit number into its equivalent character.]

l) Allow the compiler to process floating-point values in addition to integers. The Sim-pletron Simulator must also be modified to process floating-point values.

21.30 (A Simple Interpreter) An interpreter is a program that reads a high-level language programstatement, determines the operation to be performed by the statement and executes the operationimmediately. The high-level language program is not converted into machine language first. Inter-preters execute slowly because each statement encountered in the program must first be deciphered.If statements are contained in a loop, the statements are deciphered each time they are encounteredin the loop. Early versions of the BASIC programming language were implemented as interpreters.

Write an interpreter for the Simple language discussed in Exercise 21.26. The program shoulduse the infix-to-postfix converter developed in Exercise 21.12 and the postfix evaluator developedin Exercise 21.13 to evaluate expressions in a let statement. The same restrictions placed on theSimple language in Exercise 21.26 should be adhered to in this program. Test the interpreter withthe Simple programs written in Exercise 21.26. Compare the results of running these programs inthe interpreter with the results of compiling the Simple programs and running them in the Sim-pletron Simulator built in Exercise 8.19.

cpphtp5_21_DataStructures_IM.fm Page 1329 Thursday, December 23, 2004 5:00 PM

1330 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.31 (Insert/Delete Anywhere in a Linked List) Our linked list class template allowed insertionsand deletions at only the front and the back of the linked list. These capabilities were convenientfor us when we used private inheritance and composition to produce a stack class template and aqueue class template with a minimal amount of code by reusing the list class template. Actually,linked lists are more general than those we provided. Modify the linked list class template we devel-oped in this chapter to handle insertions and deletions anywhere in the list.

ANS: [Note: The solution uses zero-based counting for the location of the elements in alist.]

1 // Exercise 21.31 Solution: Listnode.h2 // Template ListNode class definition.3 #ifndef LISTNODE_H4 #define LISTNODE_H56 // forward declaration of class List required to announce that class 7 // List exists so it can be used in the friend declaration at line 138 template< typename NODETYPE > class List; 9

10 template< typename NODETYPE >11 class ListNode 12 {13 friend class List< NODETYPE >; // make List a friend14 public:15 ListNode( const NODETYPE & ); // constructor16 NODETYPE getData() const; // return data in node1718 // set the nextPtr19 void setNextPtr( ListNode *nPtr ) 20 { 21 nextPtr = nPtr; 22 } // end function setNextPtr2324 // get nextPtr25 ListNode *getNextPtr() const 26 { 27 return nextPtr; 28 } // end function getNextPtr2930 private:31 NODETYPE data; // data32 ListNode< NODETYPE > *nextPtr; // next node in list33 }; // end class ListNode3435 // constructor36 template< typename NODETYPE >37 ListNode< NODETYPE >::ListNode( const NODETYPE &info )38 : data( info ), nextPtr( 0 ) 39 { 40 // empty body41 } // end ListNode constructor4243 // return copy of data in node44 template< typename NODETYPE >

cpphtp5_21_DataStructures_IM.fm Page 1330 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1331

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

45 NODETYPE ListNode< NODETYPE >::getData() const 46 { 47 return data; 48 } // end function getData4950 #endif

1 // Exercise 21.31 Solution: List.h2 // Template List class definition.3 #ifndef LIST_H4 #define LIST_H56 #include <iostream>7 using std::cout;89 #include "Listnode.h" // ListNode class definition

1011 template< typename NODETYPE >12 class List 13 {14 public:15 List(); // constructor16 ~List(); // destructor17 void insertAtFront( const NODETYPE & );18 void insertAtBack( const NODETYPE & );19 bool removeFromFront( NODETYPE & );20 bool removeFromBack( NODETYPE & );21 bool insertByLocation( const NODETYPE &, int );22 bool deleteNodeByValue( const NODETYPE &, NODETYPE & );23 bool deleteNodeByLocation( NODETYPE &, int );24 bool isEmpty() const;25 void print() const;26 private:27 ListNode< NODETYPE > *firstPtr; // pointer to first node28 ListNode< NODETYPE > *lastPtr; // pointer to last node2930 // utility function to allocate new node31 ListNode< NODETYPE > *getNewNode( const NODETYPE & );32 }; // end class List3334 // default constructor35 template< typename NODETYPE >36 List< NODETYPE >::List() 37 : firstPtr( 0 ), lastPtr( 0 ) 38 { 39 // empty body40 } // end List constructor4142 // destructor43 template< typename NODETYPE >

cpphtp5_21_DataStructures_IM.fm Page 1331 Thursday, December 23, 2004 5:00 PM

1332 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

44 List< NODETYPE >::~List()45 {46 if ( !isEmpty() ) // List is not empty47 { 48 cout << "Destroying nodes ...\n";4950 ListNode< NODETYPE > *currentPtr = firstPtr;51 ListNode< NODETYPE > *tempPtr;5253 while ( currentPtr != 0 ) // delete remaining nodes54 { 55 tempPtr = currentPtr;56 cout << tempPtr->data << '\n';57 currentPtr = currentPtr->nextPtr;58 delete tempPtr;59 } // end while60 } // end if6162 cout << "All nodes destroyed\n\n";63 } // end List destructor6465 // insert node at front of list66 template< typename NODETYPE >67 void List< NODETYPE >::insertAtFront( const NODETYPE &value )68 {69 ListNode< NODETYPE > *newPtr = getNewNode( value ); // new node7071 if ( isEmpty() ) // List is empty72 firstPtr = lastPtr = newPtr; // new list has only one node73 else // List is not empty74 {75 newPtr->nextPtr = firstPtr; // point new node to previous 1st node76 firstPtr = newPtr; // aim firstPtr at new node77 } // end else78 } // end function insertAtFront7980 // insert node at back of list81 template< typename NODETYPE >82 void List< NODETYPE >::insertAtBack( const NODETYPE &value )83 {84 ListNode< NODETYPE > *newPtr = getNewNode( value ); // new node8586 if ( isEmpty() ) // List is empty87 firstPtr = lastPtr = newPtr; // new list has only one node88 else // List is not empty89 {90 lastPtr->nextPtr = newPtr; // update previous last node91 lastPtr = newPtr; // new last node92 } // end else93 } // end function insertAtBack9495 // delete node from front of list96 template< typename NODETYPE >97 bool List< NODETYPE >::removeFromFront( NODETYPE &value )98 {

cpphtp5_21_DataStructures_IM.fm Page 1332 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1333

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

99 if ( isEmpty() ) // List is empty100 return false; // delete unsuccessful101 else 102 {103 ListNode< NODETYPE > *tempPtr = firstPtr; // hold tempPtr to delete104105 if ( firstPtr == lastPtr )106 firstPtr = lastPtr = 0; // no nodes remain after removal107 else108 firstPtr = firstPtr->nextPtr; // point to previous 2nd node109110 value = tempPtr->data; // return data being removed111 delete tempPtr; // reclaim previous front node112 return true; // delete successful113 } // end else114 } // end function removeFromFront115116 // delete node from back of list117 template< typename NODETYPE >118 bool List< NODETYPE >::removeFromBack( NODETYPE &value )119 {120 if ( isEmpty() ) // List is empty121 return false; // delete unsuccessful122 else 123 {124 ListNode< NODETYPE > *tempPtr = lastPtr; // hold tempPtr to delete125126 if ( firstPtr == lastPtr ) // List has one element127 firstPtr = lastPtr = 0; // no nodes remain after removal128 else 129 {130 ListNode< NODETYPE > *currentPtr = firstPtr;131132 // locate second-to-last element 133 while ( currentPtr->nextPtr != lastPtr ) 134 currentPtr = currentPtr->nextPtr; // move to next node135136 lastPtr = currentPtr; // remove last node137 currentPtr->nextPtr = 0; // this is now the last node138 } // end else139140 value = tempPtr->data; // return value from old last node141 delete tempPtr; // reclaim former last node142 return true; // delete successful143 } // end else144 } // end function removeFromBack145146 // is List empty?147 template< typename NODETYPE > 148 bool List< NODETYPE >::isEmpty() const 149 { 150 return firstPtr == 0; 151 } // end function isEmpty152153 // return pointer to newly allocated node

cpphtp5_21_DataStructures_IM.fm Page 1333 Thursday, December 23, 2004 5:00 PM

1334 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

154 template< typename NODETYPE >155 ListNode< NODETYPE > *List< NODETYPE >::getNewNode( 156 const NODETYPE &value )157 {158 return new ListNode< NODETYPE >( value );159 } // end function getNewNode160161 // display contents of List162 template< typename NODETYPE >163 void List< NODETYPE >::print() const164 {165 if ( isEmpty() ) // List is empty166 {167 cout << "The list is empty\n\n";168 return;169 } // end if170171 ListNode< NODETYPE > *currentPtr = firstPtr;172173 cout << "The list is: ";174175 while ( currentPtr != 0 ) // get element data176 {177 cout << currentPtr->data << ' ';178 currentPtr = currentPtr->nextPtr;179 } // end while180181 cout << "\n\n";182 } // end function print183184 // insert node anywhere in list185 template< typename NODETYPE >186 bool List< NODETYPE >::insertByLocation(187 const NODETYPE &value, int location )188 {189 int count = 1;190191 // if list is empty and index is not 0, then index is not valid192 if ( isEmpty() && ( location != 0 ) )193 return false;194195 if ( location < 0 ) // negative indices are invalid196 return false;197 else if ( location == 0 ) // if index 0, simply insert at front198 {199 insertAtFront( value );200 return true; // successful insertion201 } // end else202203 // pointers used to keep track of current node,204 // previous node and new node205 ListNode< NODETYPE > *currentPtr = firstPtr->nextPtr,206 *previousPtr = firstPtr, *newPtr = getNewNode( value );207208 // loop until we reach proper location

cpphtp5_21_DataStructures_IM.fm Page 1334 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1335

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

209 while ( count < location )210 {211 if ( currentPtr == lastPtr ) // if end of list found first212 {213 if ( location == count + 1 )214 {215 // if user specified index one after end of list,216 // add node at back of list217 insertAtBack( value );218 return true; // successful insertion219 } // end inner if220221 return false; // index too large, invalid input222 } // end outer if223 else224 {225 // continue to next position in list226 previousPtr = currentPtr;227 currentPtr = currentPtr->nextPtr;228 count++;229 } // end else230 } // end while231232 // we have reached specified location, insert new node233 previousPtr->nextPtr = newPtr;234 newPtr->nextPtr = currentPtr;235 return true; // successful insertion236 } // end function insertByLocation237238 // delete specified value239 template< typename NODETYPE >240 bool List< NODETYPE >::deleteNodeByValue(241 const NODETYPE &val, NODETYPE &deletedVal )242 {243 if ( isEmpty() )244 return false; // delete unsuccessful245 if ( firstPtr->getData() == val ) // value at beginning of list246 return removeFromFront( deletedVal ); // remove from the front247 else // search through list for value specified248 {249 // pointers used to keep track of current and previous nodes250 ListNode< NODETYPE > *currentPtr = firstPtr, *previousPtr;251252 // loop until end of list reached253 do254 {255 // move to next node256 previousPtr = currentPtr;257 currentPtr = currentPtr->getNextPtr();258259 // if value found260 if ( currentPtr->getData() == val )261 {262 // store data of node to be deleted263 ListNode< NODETYPE > *tempPtr = currentPtr;

cpphtp5_21_DataStructures_IM.fm Page 1335 Thursday, December 23, 2004 5:00 PM

1336 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

264 deletedVal = currentPtr->getData();265266 // have previous node point to next node267 previousPtr->setNextPtr( currentPtr->getNextPtr() );268269 delete tempPtr; // delete node270 return true; // delete successful271 } // end if272 } while ( currentPtr != lastPtr ); // end do...while loop273274 // if we are here, reached end of list and did not find value275 return false; // delete unsuccessful276 } // end else277 } // end function deleteNodeByValue278279 template< typename NODETYPE >280 bool List< NODETYPE >::deleteNodeByLocation(281 NODETYPE &deletedValue, int location )282 {283 int count = 1; // counter used to move through list284285 if ( isEmpty() )286 return false; // no nodes to delete287288 if ( location < 0 ) // invalid index289 return false;290 else if ( location == 0 ) // index 0, remove from front of list291 return removeFromFront( deletedValue );292293 // keep track of current and previous pointers294 ListNode< NODETYPE > *currentPtr = firstPtr->nextPtr,295 *previousPtr = firstPtr;296297 // move through list until proper location reached298 while ( count < location )299 {300 if ( ( currentPtr == lastPtr ) ) // if end of list reached first301 return false; // invalid index entered302 else303 {304 // move to next node in list305 previousPtr = currentPtr;306 currentPtr = currentPtr->nextPtr;307 count++;308 } // end else309 } // end while310311 // we have reached specified location, remove node312 ListNode< NODETYPE > *tempPtr = currentPtr;313 deletedValue = currentPtr->getData();314315 // have previous node point to next node316 previousPtr->setNextPtr( currentPtr->getNextPtr() );317318 delete tempPtr; // delete node

cpphtp5_21_DataStructures_IM.fm Page 1336 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1337

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

319 return true; // delete successful320 } // end function deleteNodeByLocation321322 #endif

1 // Exercise 21.31 Solution: Ex21_31.cpp2 #include <iostream> 3 using std::cout; 4 using std::cin; 56 #include <cstdlib>7 using std::rand;8 using std::srand;9

10 #include <ctime>11 using std::time;1213 #include "List.h"1415 int main()16 {17 srand( time( 0 ) ); // randomize the random number generator1819 List< int > intList; // create new list2021 for ( int i = 0; i < 10; i++ ) // populate list22 intList.insertAtBack( rand() % 101 );2324 intList.print(); // display list2526 int index; // index where values will be added or deleted27 int value; // value to be added or deleted28 int deletedValue; // value in a node that has been deleted2930 cout << "Enter the index where you want the new value to appear: ";31 cin >> index;32 cout << "Enter the value you want added at this location: ";33 cin >> value;3435 // insert value to list at index specified by the user36 if ( intList.insertByLocation( value, index ) ) 37 intList.print(); // display modified list if successful38 else39 cout << "Invalid index, no data added to list.\n\n";4041 cout << "Enter an integer to delete: ";42 cin >> value;4344 // delete first occurrence of data value45 if ( intList.deleteNodeByValue( value, deletedValue ) )46 {47 cout << deletedValue << " was deleted from the list\n";

cpphtp5_21_DataStructures_IM.fm Page 1337 Thursday, December 23, 2004 5:00 PM

1338 Chapter 21 Data Structures

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.32 (List and Queues without Tail Pointers) Our implementation of a linked list (Figs. 21.3–21.5) used both a firstPtr and a lastPtr. The lastPtr was useful for the insertAtBack and re-moveFromBack member functions of the List class. The insertAtBack function corresponds to theenqueue member function of the Queue class. Rewrite the List class so that it does not use a lastPtr.Thus, any operations on the tail of a list must begin searching the list from the front. Does this affectour implementation of the Queue class (Fig. 21.16)?

48 intList.print(); // display modified list if successful49 } // end if50 else51 cout << "Element was not found\n\n";5253 cout << "Enter a location where you want a value deleted: ";54 cin >> value;5556 // delete node at specified location57 if ( intList.deleteNodeByLocation( deletedValue, value ) )58 {59 cout << deletedValue << " was deleted from the list\n";60 intList.print(); // display modified list if successful61 } // end if62 else63 cout << "Invalid index, no data removed from list.\n\n";6465 return 0; // indicates successful termination66 } // end main

The list is: 95 68 39 32 60 4 87 16 0 15

Enter the index where you want the new value to appear: 3Enter the value you want added at this location: 10The list is: 95 68 39 10 32 60 4 87 16 0 15

Enter an integer to delete: 1616 was deleted from the listThe list is: 95 68 39 10 32 60 4 87 0 15

Enter a location where you want a value deleted: 560 was deleted from the listThe list is: 95 68 39 10 32 4 87 0 15

Destroying nodes ...9568391032487015All nodes destroyed

cpphtp5_21_DataStructures_IM.fm Page 1338 Thursday, December 23, 2004 5:00 PM

Special Section: Building Your Own Compiler 1339

Copyright ® 1992-2005 by Deitel & Associates, Inc. All Rights Reserved

21.33 Use the composition version of the stack program (Fig. 21.15) to form a complete workingstack program. Modify this program to inline the member functions. Compare the two approach-es. Summarize the advantages and disadvantages of inlining member functions.

21.34 (Performance of Binary Tree Sorting and Searching) One problem with the binary tree sort isthat the order in which the data is inserted affects the shape of the tree—for the same collection ofdata, different orderings can yield binary trees of dramatically different shapes. The performance ofthe binary tree sorting and searching algorithms is sensitive to the shape of the binary tree. Whatshape would a binary tree have if its data was inserted in increasing order? in decreasing order? Whatshape should the tree have to achieve maximal searching performance?

21.35 (Indexed Lists) As presented in the text, linked lists must be searched sequentially. For largelists, this can result in poor performance. A common technique for improving list searching perfor-mance is to create and maintain an index to the list. An index is a set of pointers to various key placesin the list. For example, an application that searches a large list of names could improve performanceby creating an index with 26 entries—one for each letter of the alphabet. A search operation for alast name beginning with ‘Y’ would first search the index to determine where the ‘Y’ entries beginand “jump into” the list at that point and search linearly until the desired name is found. This wouldbe much faster than searching the linked list from the beginning. Use the List class of Figs. 21.3–21.5 as the basis of an IndexedList class. Write a program that demonstrates the operation of in-dexed lists. Be sure to include member functions insertInIndexedList, searchIndexedList anddeleteFromIndexedList.

cpphtp5_21_DataStructures_IM.fm Page 1339 Thursday, December 23, 2004 5:00 PM