2003 Prentice Hall, Inc. All rights reserved Linked Lists Upcoming program has two class templates –Create two class templates –ListNode data (type depends on class template) nextPtr –List Linked list of ListNode objects List manipulation functions –insertAtFront –insertAtBack –removeFromFront –removeFromBack
2003 Prentice Hall, Inc. All rights reserved. Outline 2 listnode.h (1 of 2) 1 // Fig. 17.3: listnode.h 2 // Template ListNode class definition. 3 #ifndef LISTNODE_H 4 #define LISTNODE_H 5 6 // forward declaration of class List 8 10 class ListNode { 11 friend class List; // make List a friend public: 14 ListNode( const & int ); // constructor 15 int getData() const; // return data in node private: 18 int data; // data 19 ListNode *nextPtr; // next node in list }; // end class ListNode 22 Template class ListNode. The type of member data depends on how the class template is used.
2003 Prentice Hall, Inc. All rights reserved. Outline 3 listnode.h (2 of 2) 23 // constructor 25 ListNode::ListNode( const int &info ) 26 : data( info ), 27 nextPtr( 0 ) 28 { 29 // empty body } // end ListNode constructor // return copy of data in node ListNode::getData() const 36 { 37 return data; } // end function getData #endif
2003 Prentice Hall, Inc. All rights reserved. Outline 4 list.h (1 of 9) 1 // Fig. 17.4: list.h 3 #ifndef LIST_H 4 #define LIST_H 5 6 #include 7 8 using std::cout; 9 10 #include 11 #include "listnode.h" // ListNode class definition class List { public: 17 List(); // constructor 18 ~List(); // destructor 19 void insertAtFront( const int & ); 20 void insertAtBack( const int & ); 21 bool removeFromFront( int & ); 22 bool removeFromBack( int & ); 23 bool isEmpty() const; 24 void print() const; 25
2003 Prentice Hall, Inc. All rights reserved. Outline 5 list.h (2 of 9) 26 private: 27 ListNode *firstPtr; // pointer to first node 28 ListNode *lastPtr; // pointer to last node // utility function to allocate new node 31 ListNode *getNewNode( const int & ); }; // end class List // default constructor 37 List::List() 38 : firstPtr( 0 ), 39 lastPtr( 0 ) 40 { 41 // empty body } // end List constructor 44 Each List has a firstPtr and lastPtr.
2003 Prentice Hall, Inc. All rights reserved. Outline 6 list.h (3 of 9) 45 // destructor 47 List::~List() 48 { 49 if ( !isEmpty() ) { // List is not empty 50 cout << "Destroying nodes...\n"; ListNode *currentPtr = firstPtr; 53 ListNode *tempPtr; while ( currentPtr != 0 ) { // delete remaining nodes 56 tempPtr = currentPtr; 57 cout data << '\n'; 58 currentPtr = currentPtr->nextPtr; 59 delete tempPtr; } // end while } // end if cout << "All nodes destroyed\n\n"; } // end List destructor 68
2003 Prentice Hall, Inc. All rights reserved. Outline 7 list.h (4 of 9) 69 // insert node at front of list 71 void List::insertAtFront( const int &value ) 72 { 73 ListNode *newPtr = getNewNode( value ); if ( isEmpty() ) // List is empty 76 firstPtr = lastPtr = newPtr; else { // List is not empty 79 newPtr->nextPtr = firstPtr; 80 firstPtr = newPtr; } // end else } // end function insertAtFront 85 Insert a new node as described in the previous diagrams.
2003 Prentice Hall, Inc. All rights reserved. Outline 8 list.h (5 of 9) 86 // insert node at back of list 88 void List::insertAtBack( const int &value ) 89 { 90 ListNode *newPtr = getNewNode( value ); if ( isEmpty() ) // List is empty 93 firstPtr = lastPtr = newPtr; else { // List is not empty 96 lastPtr->nextPtr = newPtr; 97 lastPtr = newPtr; } // end else } // end function insertAtBack 102
2003 Prentice Hall, Inc. All rights reserved. Outline 9 list.h (6 of 9) 103 // delete node from front of list 105 bool List::removeFromFront( int &value ) 106 { 107 if ( isEmpty() ) // List is empty 108 return false; // delete unsuccessful else { 111 ListNode *tempPtr = firstPtr; if ( firstPtr == lastPtr ) 114 firstPtr = lastPtr = 0; 115 else 116 firstPtr = firstPtr->nextPtr; value = tempPtr->data; // data being removed 119 delete tempPtr; return true; // delete successful } // end else } // end function removeFromFront 126
2003 Prentice Hall, Inc. All rights reserved. Outline 10 list.h (7 of 9) 127 // delete node from back of list 129 bool List::removeFromBack( int &value ) 130 { 131 if ( isEmpty() ) 132 return false; // delete unsuccessful else { 135 ListNode *tempPtr = lastPtr; if ( firstPtr == lastPtr ) 138 firstPtr = lastPtr = 0; 139 else { 140 ListNode *currentPtr = firstPtr; // locate second-to-last element 143 while ( currentPtr->nextPtr != lastPtr ) 144 currentPtr = currentPtr->nextPtr; lastPtr = currentPtr; 147 currentPtr->nextPtr = 0; } // end else value = tempPtr->data; 152 delete tempPtr; 153
2003 Prentice Hall, Inc. All rights reserved. Outline 11 list.h (8 of 9) 154 return true; // delete successful } // end else } // end function removeFromBack // is List empty? 162 bool List::isEmpty() const 163 { 164 return firstPtr == 0; } // end function isEmpty // return pointer to newly allocated node 170 ListNode *List::getNewNode( 171 const &value ) 172 { 173 return new ListNode( value ); } // end function getNewNode 176 Note use of new operator to dynamically allocate a node.
2003 Prentice Hall, Inc. All rights reserved. Outline 12 list.h (9 of 9) 177 // display contents of List 179 void List::print() const 180 { 181 if ( isEmpty() ) { 182 cout << "The list is empty\n\n"; 183 return; } // end if ListNode *currentPtr = firstPtr; cout << "The list is: "; while ( currentPtr != 0 ) { 192 cout data << ' '; 193 currentPtr = currentPtr->nextPtr; } // end while cout << "\n\n"; } // end function print #endif
2003 Prentice Hall, Inc. All rights reserved Stacks Upcoming program –Create stack from list insertAtFront, removeFromFront –Software reusability Inheritance –Stack inherits from List Composition –Stack contains a private List object –Performs operations on that object –Makes stack implementation simple
2003 Prentice Hall, Inc. All rights reserved. Outline 14 stack.h (1 of 2) 1 // Fig : stack.h 2 // Template Stack class definition derived from class List. 3 #ifndef STACK_H 4 #define STACK_H 5 6 #include "list.h" // List class definition 7 9 class Stack : private List { public: 12 // push calls List function insertAtFront 13 void push( const int &data ) 14 { 15 insertAtFront( data ); } // end function push // pop calls List function removeFromFront 20 bool pop( int &data ) 21 { 22 return removeFromFront( data ); } // end function pop 25 Stack inherits from List.Define push and pop, which call insertAtFront and removeFromFront.
2003 Prentice Hall, Inc. All rights reserved. Outline 15 stack.h (2 of 2) 26 // isStackEmpty calls List function isEmpty 27 bool isStackEmpty() const 28 { 29 return isEmpty(); } // end function isStackEmpty // printStack calls List function print 34 void printStack() const 35 { 36 print(); } // end function print }; // end class Stack #endif
2003 Prentice Hall, Inc. All rights reserved. Outline 16 fig17_11.cpp (1 of 3) 1 // Fig : fig17_11.cpp 2 // Template Stack class test program. 3 #include 4 5 using std::endl; 6 7 #include "stack.h" // Stack class definition 8 9 int main() 10 { 11 Stack intStack; // create Stack of ints cout << "processing an integer Stack" << endl; // push integers onto intStack 16 for ( int i = 0; i < 4; i++ ) { 17 intStack.push( i ); 18 intStack.printStack(); } // end for // pop integers from intStack 23 int popInteger; 24
2003 Prentice Hall, Inc. All rights reserved. Outline 17 fig17_11.cpp (2 of 3) 25 while ( !intStack.isStackEmpty() ) { 26 intStack.pop( popInteger ); 27 cout << popInteger << " popped from stack" << endl; 28 intStack.printStack(); } // end while } // end for 44
2003 Prentice Hall, Inc. All rights reserved Recursion Recursive functions –Functions that call themselves –base case: can directly be solved –Recursive case: ? Recursive (not base) case –Break problem into smaller problem(s) –Launch new copy of function to work on the smaller problem (recursive call/recursive step) Slowly converges towards base case Function makes call to itself inside the return statement –Eventually base case gets solved Answer works way back up, solves entire problem
2003 Prentice Hall, Inc. All rights reserved Recursion Example: factorial n! = n * ( n – 1 ) * ( n – 2 ) * … * 1 –Recursive relationship ( n! = n * ( n – 1 )! ) 5! = 5 * 4! 4! = 4 * 3!… –Base case (1! = 0! = 1)
2003 Prentice Hall, Inc. All rights reserved. Outline 20 fig03_14.cpp (1 of 2) 1 // Fig. 3.14: fig03_14.cpp 2 // Recursive factorial function. 3 #include 4 5 using std::cout; 6 using std::endl; 7 8 #include 9 10 using std::setw; unsigned long factorial( unsigned long ); // function prototype int main() 15 { 16 // Loop 10 times. During each iteration, calculate 17 // factorial( i ) and display result. 18 for ( int i = 0; i <= 10; i++ ) 19 cout << setw( 2 ) << i << "! = " 20 << factorial( i ) << endl; return 0; // indicates successful termination } // end main Data type unsigned long can hold an integer from 0 to 4 billion.
2003 Prentice Hall, Inc. All rights reserved. Outline 21 fig03_14.cpp (2 of 2) fig03_14.cpp output (1 of 1) // recursive definition of function factorial 27 unsigned long factorial( unsigned long number ) 28 { 29 // base case 30 if ( number <= 1 ) 31 return 1; // recursive step 34 else 35 return number * factorial( number - 1 ); } // end function factorial 0! = 1 1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 6! = 720 7! = ! = ! = ! = The base case occurs when we have 0! or 1!. All other cases must be split up (recursive step).
2003 Prentice Hall, Inc. All rights reserved Example Using Recursion: Fibonacci Series Fibonacci series: 0, 1, 1, 2, 3, 5, 8... –Each number sum of two previous ones –Example of a recursive formula: fib(n) = fib(n-1) + fib(n-2) C++ code for Fibonacci function long fibonacci( long n ) { if ( n == 0 || n == 1 ) // base case return n; else return fibonacci( n - 1 ) + fibonacci( n – 2 ); }
2003 Prentice Hall, Inc. All rights reserved Example Using Recursion: Fibonacci Series f( 3 ) f( 1 ) f( 2 ) f( 1 )f( 0 )return 1 return 0 return + +
2003 Prentice Hall, Inc. All rights reserved Recursion vs. Iteration Repetition –Iteration: explicit loop –Recursion: repeated function calls Termination –Iteration: loop condition fails –Recursion: base case recognized Both can have infinite loops Balance between performance (iteration) and good software engineering (recursion)
2003 Prentice Hall, Inc. All rights reserved. 25 Palindrome: Problem A palindrome is a string that reads the same backward or forward Question: how do you check a String to see whether or not it is a Palindrome? –What is the base case? –What is the recursive case? –How to convert a high-order recursive case to low-order recursive case xyza zyx
2003 Prentice Hall, Inc. All rights reserved. 26 Palindrome checkPalindrome(string, left, right) Base case: –if right <= left, then “true” –if string.charAt(left) != string.charAt(right), then “false” Recursive case: –check palindrome (string, left + 1, right - 1) xyza zyx
2003 Prentice Hall, Inc. All rights reserved. 27 Palindrome Check boolean checkPalindrome(String s, int left, int right) { if (right <= left) // base return true; else if (s.charAt(left) != s.charAt(right)) // base return false; else return checkPalindrome(s, left + 1, right - 1); }
2003 Prentice Hall, Inc. All rights reserved. 28 Towers of Hanoi Question 3.42, page
2003 Prentice Hall, Inc. All rights reserved. 29 Tower of Hanoi: code void moveTower (int numDisks, int start, int end, int temp) { if (numDisks == 1) System.out.println(“move disk from “ + start + “ to “ + end); else { moveTower (numDisks-1, start, temp, end); System.out.println(“move disk from “ + start + “ to “ + end); moveTower (numDisks-1, temp, end, start); } public static void main(String[] args) { moveTower(4, 1, 3, 2); }
2003 Prentice Hall, Inc. All rights reserved. 30 Towers of Hanoi An iterative solution to the Towers of Hanoi is quite complex A recursive solution is much shorter and more elegant