161
INSTRUCTOR’S GUIDE Stephen P. Alberg DATA ABSTRACTION AND PROBLEM SOLVING WITH C++ WALLS AND MIRRORS Frank M. Carrano University of Rhode Island Paul Helman Robert Veroff University of New Mexico

Excersize DataStructure

Embed Size (px)

Citation preview

Page 1: Excersize DataStructure

INSTRUCTOR’S GUIDEStephen P. Alberg

DATA ABSTRACTIONAND PROBLEM SOLVINGWITH C++WALLS AND MIRRORS

Frank M. CarranoUniversity of Rhode Island

Paul HelmanRobert VeroffUniversity of New Mexico

Page 2: Excersize DataStructure

2

Copyright © 1998 by Addison Wesley Longman, Inc.All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, ortransmitted, in any form or by any means, electronic, mechanical, photocopying, recording, or anyother media or embodiments now known or hereafter to become known, without the prior writtenpermission of the publisher. Published in the United States of America.

The programs and applications presented have been included for their instructionalvalue. They have been tested with care but are not guaranteed for any particular purpose. Thepublisher does not offer warranties or representations, nor does it accept any liabilities with respectto the programs or applications.

Page 3: Excersize DataStructure

3

CONTENTSIntroduction 4

Three Possible Courses Based on Walls and Mirrors 5

Solutions to Exercises 8

PART I Problem-Solving Techniques

1 Principles of Programming and Software Engineering 8

2 Recursion: The Mirrors 13

3 Data Abstraction: The Walls 26

4 Linked Lists 31

5 Recursion as a Problem-Solving Technique 45

PART II Problem Solving with Abstract Data Types

6 Stacks 54

7 Queues 66

8 Class Relationships 72

9 Algorithm Efficiency and Sorting 88

10 Trees 95

11 Tables and Priority Queues 113

12 Advanced Implementations of Tables 122

13 Graphs 129

14 External Methods 138

Appendix A Review of C++ Fundamentals 147

Appendix D Mathematical Induction 152

Page 4: Excersize DataStructure

4

INTRODUCTION

This instructor’s guide, which supplements Data Abstraction and Problem Solving with C++: Walls andMirrors, is organized as follows:

Three Possible Courses Based on Walls and Mirrors. We begin by offering suggestions for how to use Walls and Mirrors in your course. The book’s flexibility will allow you to use it in a variety ofsituations.

Solutions to Exercises. The solutions to the end-of-chapter exercises and some programming projectsare included in this section. Some discussion-type solutions are omitted.

Test Bank. Questions and problems suitable for examinations and quizzes are provided for eachchapter in the text.

Reminder: All programs, header files, implementation files, and functions that appear in the book areavailable by anonymous ftp. Please consult the preface of the book for further details.

Page 5: Excersize DataStructure

5

THREE POSSIBLE COURSES BASED ONWALLS AND MIRRORS

By appropriately choosing which parts of the book to emphasize, you can easily tailor the material tofit your particular curriculum. Although the suggested courses presented here cover material in theorder in which it appears in the book, variations are possible. The book’s preface provides detailsabout the orders in which you can cover chapters. With this flexibility in mind, here are three possiblecourses based on this book.

A Second Course in Computer Science

If your introductory course emphasizes structured programming and introduces recursion, studentscan review most of the first two chapters on their own. On the other hand, if the introductory coursemanages to cover only the basics of a programming language, you should devote a fair amount ofclass time to Chapters 1 and 2.

If your students do not know C++ or C, you may need to devote some class time to the coverage ofAppendix A, which reviews C++. If your students have studied C++ classes, you can devote less timeto Chapter 3 than is indicated in the syllabus given here.

The course should cover the material through Chapter 10, at least. You can select topics from Chap-ters11 through 14, as time permits. You can cover many topics within these chapters in any order.

Possible Syllabus for a Second Course in Computer ScienceWeek Topic Chapter

1 Review of programming principlesReview of recursion

12

2 Data abstraction 33 Data abstraction 3 (Cont.)4 Linked lists 45 Linked lists 4 (Cont.)6 Recursion 57 Stacks 68 Stacks

Queues6 (Cont.)7

9 QueuesClass relationships

7 (Cont.)8

10 Class relationships 8 (Cont.)11 Efficiency and sorting 912 Efficiency and sorting

Trees9 (Cont.)10

13 Trees 10 (Cont.)14 Tables and priority queues 11

15 - 16 Selected advanced topics 12 - 14

Page 6: Excersize DataStructure

6

Lower-Division Data Structures Courses

At many schools, the primary undergraduate data structures course comes early in the curriculum.You can use this book in such a course by giving high priority to the material in Chapter 3 andChapters 6 through 14. This means that you should spend as little time as possible on Chapter 1, andyou may even find it necessary to omit some of the material on recursion. You should assign projects,such as the ones suggested in Chapter 12, in which students implement 2-3 trees or hashing.

Possible Syllabus for a Lower-Division Data Structures CourseWeek Topic Chapter

1 Review of programming principlesReview of recursion

12

2 Data abstraction 33 Linked lists 44 Recursion 55 Stacks 66 Stacks

Queues6 (Cont.)7

7 QueuesClass relationships

7 (Cont.)8

8 Efficiency and sorting 99 Trees 10

10 TreesTables

10 (Cont.)11

11 Priority queues and heaps 11 (Cont.)12 Balanced search trees 1213 Hashing 12 (Cont.)14 Multiple organizations

Graphs12 (Cont.)13

15 GraphsExternal sorting

13 (Cont.)14

16 External sorting 14 (Cont.)

Page 7: Excersize DataStructure

7

Second- and Third-Quarter Courses

This book should work very well for schools on the quarter system. If the first quarter is anintroductory programming course, then Chapters 1 through 7 would constitute a reasonable secondquarter. This would leave the remainder of book for the third quarter.

Possible Syllabus for a Second-Quarter CourseWeek Topic Chapter

1 Review of programming principles 12 Review of recursion 23 Data abstraction 34 Data abstraction 3 (Cont.)5 Linked lists 46 Linked lists 4 (Cont.)7 Recursion 58 Stacks 69 Stacks

Queues6 (Cont.)7

10 Queues 7 (Cont.)

Possible Syllabus for a Third-Quarter CourseWeek Topic Chapter

1 Class relationships 82 Efficiency and sorting 93 Trees 104 Trees

Tables10 (Cont.)11

5 Priority queues and heaps 11 (Cont.)6 Balanced trees 127 Hashing

Multiple organizations12 (Cont.)

8 Graphs 139 External sorting 1410 External sorting 14 (Cont.)

Page 8: Excersize DataStructure

8

SOLUTIONS TO EXERCISESPART I: Problem-Solving Techniques

Principles of Programming and Software Engineering

1 const CENTS_PER_DOLLAR = 100;

void ComputeChange(int DollarCost, int CentsCost, int& D, int& C);// ----------------------------------------------------------------// Computes the change remaining from purchasing an item costing// DollarCost dollars and CentsCost cents with D dollars and C cents.// Preconditions: DollarCost, CentsCost, D and C are all nonnegative// integers and CentsCost and C are both less than CENTS_PER_DOLLAR.// Postconditions: D and C contain the computed remainder values in// dollars and cents respectively. If input value D < DollarCost, the// proper negative values for the amount owed in D dollars and/or C// cents is returned.// ----------------------------------------------------------------

2a #include <bool.h>

const MONTHS_PER_YEAR = 12;const DAYS_PER_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

void IncrementDate( int& Month, int& Day, int& Year);// -----------------------------------------------------------------------// Increments the input Date values (Month, Day, Year) by one day.// Precondition: 1 <= Month <= MONTHS_PER_YEAR,// 1 <= Day <= DAYS_PER_MONTH[Month - 1], except// when Month == 2, Day == 29 and IsLeapYear(Year) is true.// Postcondition: The valid numeric values for the succeeding Month, Day,// and Year are returned.// -----------------------------------------------------------------------

bool IsLeapYear( int Year );// -----------------------------------------------------------------------// Determines if the input year is a leap year.// Precondition: Year > 0.// Postconditions: Returns true if Year is a leap year; false otherwise.// -----------------------------------------------------------------------

2b void IncrementDate( int& Month, int& Day, int& Year){ // error check on input values if( Month <= 0 || Month > MONTHS_PER_YEAR) { cout << "Bad input value for Month" << endl;

return; }

if( Year <= 0) { cout << "Bad input value for Year" << endl;

return; } if( Day <= 0 || Day > DAYS_PER_MONTH[Month - 1]) { // special case for February

1

Page 9: Excersize DataStructure

9

if( Month != 2 ){ cout << "Bad input value for Day" << endl; return;}else if( !IsLeapYear(Year) || Day > 29){ cout << "Bad input value for Day" << endl; return;} // end if

} // end if

// increment the date Day++;

if( Day > DAYS_PER_MONTH[Month - 1]) { // test for February 29

if( Month == 2 && IsLeapYear(Year) && Day == 29) return;else{ // increment to next month Day = 1; Month++;

if( Month > MONTHS_PER_YEAR) { // increment to next year

Month = 1;Year++;

} // end if} // end if

} // end if} // end IncrementDate

bool IsLeapYear( int Year ){ // Example: 2000 is a leap year but 1900 was not return ((Year % 400 == 0) || ((Year % 4 == 0) && (Year % 100 != 0)));} // end IsLeapYear

3 We can make several improvements to user interaction and programming style:

• Prompt the user for the input and indicate the expected form of the input. The user should also be given an option to exit the program.• Give more descriptive output.• Make the program more robust; e.g., requiring exactly eight characters per name is unreasonable.• Check input for obvious errors; e.g., a four-digit age entry is surely a typo and the user should be allowed to correct the error.• Document the program.• Use more descriptive variable names.• Declare and use a constant for the maximum length of a name.

Page 10: Excersize DataStructure

10

4 There are two hazards with the function Computation(). First, the argument X can nnumber because Computation() calls the sqrt() function with X as the argument. Sein the range of the function cos(X), the result of this computation must be tes tdivisor in order to avoid a "divide by zero error." The following implementati osafe checks.

double Computation( double X )// ------------------------------------------------------------// Performs a computation.// Preconditions: X >=0 and X != (2k - 1)*PI/2 where k is a// positive integer.// Postcondition: returns -1 if preconditions are not met// else, returns the value of the Computation.// ------------------------------------------------------------{ // compute the cosine once and store it double Denominator = cos(X);

// check for negative argument to sqrt() function if( X < 0 ) { cerr << "Cannot take square root of negative number" << endl;

return -1; }

// check for division by zero if( Denominator == 0 ) { cerr << "Cannot divide by zero" << endl;

return -1; }

return sqrt(X)/Denominator;}

5 The invariants for the for loop of the function Factorial() are as follows:

a 1 ≤ Integer ≤ N.

b F = N! / Integer!

6 The invariants for the for loop are as follows:

a 0 ≤ I ≤ N - 1.

b 0 ≤ NumPos ≤ LIMIT.

c Sum is equal to the sum of the first NumPos integers in A.

const int LIMIT = 5;typedef int elementType;

elementType ComputeSum(const elementType A[], int N, bool& Success)// ------------------------------------------------------------------------// Computes the sum of the first LIMIT positive elements in A.// Precondition: A is an array of N elementTypes with at least LIMIT// of A positive and N >= LIMIT.// Postcondition: If A contains at least LIMIT positive elements, then// the function returns the sum of the first LIMIT positive// elements and Success is true. Else, Sum is 0 and

Page 11: Excersize DataStructure

11

// Success is false. A and N are unchanged.// ------------------------------------------------------------------------{ int NumPos = LIMIT; elementType Sum = 0;

// check for out of bounds errors if(NumPos > N || N < 0) { Success = false;

return Sum; } // end if

// perform the computation on the array for(int I = 0; I < N && NumPos > 0; ++I) if(A[I] > 0) { Sum += A[I]; NumPos--; } // end for

// verify that LIMIT elements have been added if(NumPos > 0) { Success = False; return 0; } // end if

// pass on results Success = true; return Sum;} // end ComputeSum

7 Invariant: 0 ≤ Index ≤ N and Sum = A[0] + ... + A[Index].

Prior to the while loop, Index is set to 0 and Sum is initialized to A[Index], describes the value of Sum at this point.

Within the while loop, the value of Sum so far is A[0] + ... + A[Index]. If I nincremented (i.e.: Index = Index + 1). The value of the next element of the araccessed element (i.e.: A[ <last value of Index> + 1 ]) is added to Sum.

After the while loop, the last value of Index must have been N since the loop tincrements before it is used to access the array A, the last value of Index (i.Since the value of Sum prior to this last access was A[0] + ... + A[N - 1] and A[N], the algorithm corroborates the invariant at Index = N.

8 The bug is in the while loop:

a Output is The floor of the square root of 64 is 7.

b The while loop condition should be

while(Temp1 <= X)

Debugging involves printing the values of Temp1, Temp2 and Ans at the top of the loop.

c Supply user prompts and check the value of X to ensure that it is greater than 0.

Page 12: Excersize DataStructure

12

9 #include <iostream.h>#include <stdlib.h>

enum errorCode {DZERO, AOTRG, ... }; // mnemonic error codes

void SevereErrorMessage(errorCode Error)// -----------------------------------------------------------------// Displays an error code and terminates program execution.// Preconditions: none.// Postconditions: An error message corresponding to the input// errorCode is output to the standard error stream// and the program is terminated.// -----------------------------------------------------------------{ switch(Error) { case DZERO: cerr << "Divide by zero error." << endl; break; case AORTG: cerr << "Array index out of range." << endl; break; . . default: cerr << "Unknown fatal error." << endl; }; // end switch

exit(0); // terminate execution immediately} // end SevereErrorMessage

Page 13: Excersize DataStructure

13

Recursion: The Mirrors

1 The problem is defined in terms of a smaller problem of the same type: Here, a single index of the array is evaluated and the result added to a call on the remaining part of the array.

Each recursive call diminishes the size of the problem: The recursive call to NumberValue subtracts 1 from the current value for N, passing this as the parameter N in the next call, effectively reducing the size of the unsearched remainder of the array by 1.

An instance of the problem serves as the base case: Here, the case where the size of the array is 0 (i.e.: N ≤ 0) results in the return of the value 0: an array of size 0 can have no instances of the DesiredValue . This terminates the recursion.

As the problem size diminishes, the base case is reached: N is an integer and is decremented by 1 with each recursive call. After N recursive calls, the parameter N in the Nth call will have the value 0 and the base case will be reached.

2a The call Rabbit(5) produces the following box trace:

Follow the Rabbit(4) call

Follow the Rabbit(3) call

Follow the Rabbit(2) call

Base case: N= 2

The Rabbit(2)call

completes

2

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = ?Rabbit(2) = ?Return ?

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = ?Rabbit(2) = ?Return ?

N = 3Rabbit(2) = ?Rabbit(1) = ?Return ?

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = ?Rabbit(2) = ?Return ?

N = 3Rabbit(2) = ?Rabbit(1) = ?Return ?

N = 2

Return 1

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = ?Rabbit(2) = ?Return ?

N = 3Rabbit(2) = ?Rabbit(1) = ?Return ?

N = 2

Return 1

Page 14: Excersize DataStructure

14

Follow the Rabbit(1) call

Base case: N = 1

The Rabbit(1)call

completes

The Rabbit(3)call

completes

Follow the Rabbit(2) call

Base case: N = 2

The Rabbit(2) call completes

The Rabbit(4) call completes

Follow the Rabbit(3) call

Follow the Rabbit(2) call

Base case: N = 2

The Rabbit(2) call completes

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = ?Rabbit(2) = ?Return ?

N = 3Rabbit(2) = 1Rabbit(1) = ?Return ?

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = ?Rabbit(2) = ?Return ?

N = 3Rabbit(2) = 1Rabbit(1) = ?Return ?

N = 1

Return 1

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = ?Rabbit(2) = ?Return ?

N = 3Rabbit(2) = 1Rabbit(1) = 1Return 2

N = 1

Return 1

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = 2Rabbit(2) = ?Return ?

N = 3Rabbit(2) = 1Rabbit(1) = 1Return 2

N = 1

Return 1

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = 2Rabbit(2) = ?Return ?

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = 2Rabbit(2) = ?Return ?

N = 2

Return 1

N = 5Rabbit(4) = ?Rabbit(3) = ?Return ?

N = 4Rabbit(3) = 2Rabbit(2) = 1Return 3

N = 2

Return 1

N = 5Rabbit(4) = 3Rabbit(3) = ?Return ?

N = 4Rabbit(3) = 2Rabbit(2) = 1Return 3

N = 2

Return 1

N = 5Rabbit(4) = 3Rabbit(3) = ?Return ?

N = 5Rabbit(4) = 3Rabbit(3) = ?Return ?

N = 3Rabbit(2) = ?Rabbit(1) = ?Return ?

N = 5Rabbit(4) = 3Rabbit(3) = ?Return ?

N = 3Rabbit(2) = ?Rabbit(1) = ?Return ?

N = 2

Return 1

N = 5Rabbit(4) = 3Rabbit(3) = ?Return ?

N = 3Rabbit(2) = 1Rabbit(1) = ?Return ?

N = 2

Return 1

Page 15: Excersize DataStructure

15

Page 16: Excersize DataStructure

16

Follow the Rabbit(1) call

Base case: N = 1

The Rabbit(1) call completes

The Rabbit(3) call completes

The Rabbit(5) call completes and the value 5 is returned to the calling function

2b The call CountDown(5) produces the following box trace:

The value 5 is printed.Follow the call to CountDown(4)

The value 4 is printed.Follow the call to CountDown(3)

The value 3 is printed.Follow the call to CountDown(2)

The value 2 is printed.Follow the call toCountDown(1)

The value 1 isprinted.

Followthe call toCountDown(0)

The end of line is printed and the CountDown(0)call

completes.

N = 5Rabbit(4) = 3Rabbit(3) = ?Return ?

N = 3Rabbit(2) = 1Rabbit(1) = ?Return ?

N = 5Rabbit(4) = 3Rabbit(3) = ?Return ?

N = 3Rabbit(2) = 1Rabbit(1) = ?Return ?

N = 1

Return 1

N = 5Rabbit(4) = 3Rabbit(3) = ?Return ?

N = 3Rabbit(2) = 1Rabbit(1) = 1Return 2

N = 1

Return 1

N = 5Rabbit(4) = 3Rabbit(3) = 2Return 5

N = 3Rabbit(2) = 1Rabbit(1) = 1Return 2

N = 1

Return 1

N = 5Rabbit(4) = 3Rabbit(3) = 2Return 5

N = 3Rabbit(2) = 1Rabbit(1) = 1Return 2

N = 1

Return 1

N = 5cout << “5“;

N = 5cout << “5 “;

N = 4cout << “4“;

N = 5cout << “5 “;

N = 4cout << “4 “;

N = 3cout << “3“;

N = 5cout << “5 “;

N = 4cout << “4 “;

N = 3cout << “3 “;

N = 2cout << “2“;

N = 5cout << “5 “;

N = 4cout << “4 “;

N = 3cout << “3 “;

N = 2cout << “2 “;

N = 1cout << “1“;

N = 5cout << “5 “;

N = 4cout << “4 “;

N = 3cout << “3 “;

N = 2cout << “2 “;

N = 1cout << “1 “;

N = 0cout <<endl;

N = 5cout << “5 “;

N = 4cout << “4 “;

N = 3cout << “3 “;

N = 2cout << “2 “;

N = 1cout << “1“;

N = 0cout << endl;return

Page 17: Excersize DataStructure

17

The CountDown(1) callcompletes.

The CountDown(2) call completes.

The CountDown(3) call completes.

The CountDown(4) call completes.

The CountDown(5) call completes and returns to the calling function.

3 int ComputeSum(const int A[], int N)// --------------------------------------------------------// Returns the sum of the first N integers in the array A.// Preconditions: 0 <= N <= size of A.// Postconditions: The Sum of the first N integers in the// array A are returned. The contents of// A and the value of N are unchanged.// --------------------------------------------------------{ // base case if(N <= 0) return 0; else // reduce the problem size return A[N - 1] + ComputeSum(A, N - 1);} // end ComputeSum

4 const MAX_LENGTH = 30;

typedef char stringType[MAX_LENGTH];

void WriteBackward(stringType S, int Size)// -----------------------------------------------------// Writes a character string backward.// Precondition: The string S contains Size characters,// where Size >= 1.// Postcondition: S is written backward, but remains// unchanged.// -----------------------------------------------------{ // base case if(Size == 1) cout << S[0];

// else, write rest of string else if (Size > 1) { cout << S[Size - 1];

WriteBackward(S, Size - 1); }

N = 5cout << “5 “;

N = 4cout << “4 “;

N = 3cout << “3“;

N = 2cout << “2 “;

N = 1cout << “1 “;

N = 0cout << endl;return

N = 5cout << “5 “;

N = 4cout << “4“;

N = 3cout << “3 “;

N = 2cout << “2 “;

N = 1cout << “1 “;

N = 0cout << endl;return

N = 5cout << “5“;

N = 4cout << “4 “;

N = 3cout << “3 “;

N = 2cout << “2 “;

N = 1cout << “1 “;

N = 0cout << endl;return

N = 5cout << “5 “;

N = 4cout << “4 “;

N = 3cout << “3 “;

N = 2cout << “2“;

N = 1cout << “1 “;

N = 0cout << endl;return

Page 18: Excersize DataStructure

18

// Size <= 0 do nothing;} // end WriteBackward

Page 19: Excersize DataStructure

19

5 void PrintIntegers(int N, int Limit)// ---------------------------------------------// Prints out the integers from 1 through N as a// comma separated list followed by a newline.// Preconditions: N >= 0 and Limit == N.// Postcondition: The integers from 1 through N// are printed out followed by a// newline.// ---------------------------------------------{ if(N > 0) { // print out the rest of the integers PrintIntegers(N - 1, Limit);

// now print out this integer cout << N;

// test for end of string if(N != Limit)

cout << ", "; else

cout << "." << endl; // end of string } // end if

// N <= 0 do nothing;} // end PrintIntegers

6 const int NUMBER_BASE = 10;

void ReverseDigits(int Number)// -----------------------------------------------// Prints out the decimal digits of Number in// reverse order.// Precondition: Number >= 0.// Postcondition: The decimal digits of Number// are printed in reverse order.// This function does not output a// newline character at the end of// a string.// -----------------------------------------------{ // check for input bounds if(Number >= 0) { // base case if(Number < NUMBER_BASE) cout << Number; else { // print out rightmost digit cout << Number % NUMBER_BASE;

// pass remainder of digits to next call ReverseDigits(Number / NUMBER_BASE); } // end if } // end if} // end ReverseDigits

Page 20: Excersize DataStructure

20

7a void WriteLine(char Ch, int N)// ---------------------------------------------------------// Outputs a line of N characters where Ch is the character.// Precondition: N >= 0.// Postcondition: A line of N characters Ch is output// followed by a newline.// ---------------------------------------------------------{ // base case if(N <= 0) cout << endl;

// write rest of line else { cout << Ch;

WriteLine(Ch, N - 1); } // end if} // end WriteLine

7b void WriteBlock(char Ch, int M, int N)// --------------------------------------------------------// Outputs a block of M rows by N columns of character Ch.// Preconditions: M >= 0 and N >= 0.// Postconditions: A block of M rows by N columns of// character Ch is printed.// --------------------------------------------------------{ if(M > 0) { WriteLine(Ch, N); // write first line WriteBlock(Ch, M - 1, N); // write rest of block }

// base case: M <= 0 do nothing.} // end WriteBlock

8 Running the given program produces the following output:

Enter: A = 1 B = 7Enter: A = 1 B = 3Leave: A = 1 B = 3Leave: A = 1 B = 72

9 Running the given program produces the following output:

Enter: First = 1 Last = 30Enter: First = 1 Last = 14Enter: First = 1 Last = 6Enter: First = 4 Last = 6Leave: First = 4 Last = 6Leave: First = 1 Last = 6Leave: First = 1 Last = 14Leave: First = 1 Last = 305

Page 21: Excersize DataStructure

21

10 The algorithm first checks to see if N is a positive number: if not it immedi ainteger division of N by 8 is taken and if the result is greater than 0 (i.e.: called again with N/8 as an argument. This call processes that portion of the powers of 8. After this call, the residue for the current power, N % 8, is pri

The given function computes the number of times 8 0, 8 1, 8 2, ... will divide N. recursively and are printed out in the reverse of the order of computation. Th eexecution with N = 100:

N = 100DisplayOctal(12) N = 12 DisplayOctal(1) N = 1 cout << 1 cout << 4cout << 4

Output: 144

11 Even though the precondition states that N is nonnegative, there is no actual cfor N from being used as the argument in the function.

A call to function F() will produce a further call to F() with a negative argum eis not within the subrange of 0 to 2, the else will execute, and the function wand F(-1). Because the value for F(N) is based on the values for F(N-2) and F(N-4

addends will be the next two smaller even integers; likewise, if N is odd, F(N)

two smaller odd integers. Thus any odd nonnegative integer will eventually ca u

Theoretically, calling F with an odd integer will cause an infinite sequence of practical level, the computer's run-time stack will overflow, or an integer und e

The following is the exact output of the program:

Function entered with N = 8Function entered with N = 6Function entered with N = 4Function entered with N = 2Function entered with N = 0Function entered with N = 2Function entered with N = 4Function entered with N = 2Function entered with N = 0The value of F(8) is 27

12 The following output is produced when X is a value argument:

6 27 18 08 07 16 2

Page 22: Excersize DataStructure

22

Changing X to a reference argument produces:

6 27 18 08 08 18 2

13a The call BinSearch(5) produces the following box trace:

13b The call BinSearch(13) produces the following box trace:

13c The call BinSearch(16) produces the following box trace:

14 a For a binary search to work the array must first be sorted in either ascendi n

b Index = (0 + 101)/2 = 50.

c Number of comparisons = lg 101 = 6.

15a double Power1(double X, int N)// Returns the value of X raised to the Nth power.// Preconditions: N >= 0// Postcondition: The computed value is returned.{ double Result = 1; // value of X^0

while(N > 0) // iterate until N == 0 { Result *= X; --N; } return Result;} // end Power1

Value = 5First = 1Last = 8Middle = 4Value < A[4]

Value = 5First = 1Last = 3Middle = 2Value = A[2]return 2

Value = 13First = 1Last = 8Middle = 4Value > A[4]

Value = 13First = 5Last = 8Middle = 6Value < A[6]

Value = 13First = 5Last = 5Middle = 5Value < A[5]

Value = 13First = 5Last = 4First > Lastreturn 0

Value = 16First = 1Last = 8Middle = 4Value > A[4]

Value = 16First = 5Last = 8Middle = 6Value < A[6]

Value = 16First = 5Last = 5Middle = 5Value > A[5]

Value = 16First = 6Last = 5First > Lastreturn 0

Page 23: Excersize DataStructure

23

15b double Power2(double X, int N)// -----------------------------------------------// Returns the value of X raised to the Nth power.// Preconditions: N >= 0// Postcondition: The computed value is returned.// -----------------------------------------------{ // base case if(N == 0) return 1;

// else, multiply X by rest of computation else return X * Power2(X, N-1);} // end Power2

15c double Power3(double X, int N)// -----------------------------------------------// Returns the value of X raised to the Nth power.// Preconditions: N >= 0// Postcondition: The computed value is returned.// -----------------------------------------------{ if(N == 0) return 1;

else { // do this computation only once!! double HalfPower = Power3(X, N/2);

// if N is even... if(N % 2 == 0)

return HalfPower * HalfPower;

// if N is odd... else

return X * HalfPower * HalfPower; }} // end Power3

15d The following table lists the number of multiplications performed by each of th ethe values on the top line:

332 319

Power1 32 19Power2 32 19Power3 7 8

15e The following table lists the number of recursive calls made by each of the alg operform the computation on the inputs given on the top line:

332 319

Power2 32 19Power3 6 5

Page 24: Excersize DataStructure

24

16 Maintain a count of the recursive depth of each call by passing this count as a nfunction call and print that many spaces or tabs in front of each message:

int Rabbit(int N, int Tab)// ---------------------------------------------------------------------------// Computes a term in the Fibonacci sequence.// Preconditions: N is a positive integer and Tab = 0.// Postconditions: The progress of the recursive function call is displayed// as a sequence of increasingly nested blocks. The function// returns the Nth Fibonacci number.// ---------------------------------------------------------------------------{ int Value;

// Indent the proper distance for this block for(int I = 0; I < Tab; ++I) cout << '\t';

// Display status of call cout << "Enter: N = " << N << endl;

if(N <= 2) Value = 1;

else // N > 2, so N-1 > 0 and N-2 > 0 // indent by one for next call Value = Rabbit(N-1, Tab+1) + Rabbit(N-2, Tab+1);

// Indent the proper distance for this block for(int I = 0; I < Tab; ++I) cout << '\t';

// Display status of call cout << "Leave: N = " << N << " Value = " << Value << endl;

return Value;}

17 Since we only need the five most recently computed values, we will maintain a " celement array indexed modulus 5.

F(6) is 8; F(7) is 11; F(12) is 95; F(15) is 320.

18a A function to compute N! iteratively:

long Fact(int N){ int I; long Result;

if (N<1) // base case Result = 0;

else { Result = 1; for (I=2; I<=N; I++) Result *= I; } // end if

return Result;} // end Fact

Page 25: Excersize DataStructure

25

18b A simple iterative solution to writing a string backwards:

#include <string.h>

void WriteBackward(char S[]){ for (int I = strlen(S)-1; I>= 0; I--) cout << S[I];

cout << endl;} // end WriteBackward

18c A routine to do iterative binary search:

int BinarySearch(int A[], int Key, int Low, int High)// -------------------------------------------------------// Searches a sorted array and returns the index in the// array corresponding to the value Key if Key is in the// array, -1 otherwise.// Preconditions: A is sorted in ascending order. Low// = 0 and High = the size of A - 1.// Postconditions: If Key is found, its location index// in A is returned, else -1 is returned.// -------------------------------------------------------{ int Mid, Result;

while(Low < High) { Mid = (Low + High)/2;

if (A[Mid] == Key) { Low = Mid; High = Mid; } else if (A[Mid] < Key)

Low = Mid + 1; // search the upper half else High = Mid - 1; // search the lower half } // end while loop

if (Low > High) Result = -1; // if not found, return -1 else if (A[Low] != Key) Result = -1; else Result = Low;

return Result;} // end BinarySearch

Page 26: Excersize DataStructure

26

18d A function to find the kth smallest element of an array. We implement with an selection sort up to k times. Assume a standard integer Swap function.

int KSmall(int K, int A[], int Size){ for ( int I=0; I<K; I++) for ( int J=I+1; J<Size; J++) if (A[J] < A[I]) Swap(A[I], A[J]);

return A[k-1];} // end KSmall

19 The for loop invariant is:

3 ≤ I ≤ N

So the sum = Rabbit I Rabbit II

N

( ) ( )− + −=∑ 1 2

3

.

20a We must verify that the equation holds for both the base case and the recursive

For the base case, let GCD(a, b) = b. Then, a mod b = 0 and, since 0/n = 0 f ob. Hence, GCD(b, a mod b) = b.

For the recursive case, let GCD(a, b) = d, i.e.: a = dj and b = dk for integerinteger n = a mod b such that (n - a)/b = q, where q is an integer. Then, n -i.e., n = d(kq + j). Then, ( n/d) = kq + j, where (kq + j) is an integer. S omod b).

To show that d is the greatest common divisor of b and a mod b, suppose for co ninteger g > d such that b = gr and (a mod b) = gs for integers r and s. Then,an integer. So gs - a = grq', i.e.: a = g(s - rq'). Thus, g divides a and by hypothesis. Therefore, GCD(b, a mod b) = d.

The proof is symmetrical where GCD(b, a mod b) = d is taken for the hypothesis .

20b If b > a in the call to GCD, then a mod b = a and so the recursive call effecti

20c When a > b, the actual argument associated with the formal argument a decreases If b > a then the next recursive call will swap the actual arguments so that a will eventually equal the second and so eventually a mod b will be 0.

21a C n

if n

if n

C n i elsei

n

( )

( ( ) )

===

− +

=

0 1

1 2

11

1

22 int Acker(int M, int N)

Page 27: Excersize DataStructure

27

{ int Result;

if (M == 0) Result = N+1;

else if (N == 0) Result = Acker(M-1, 1);

else Result = Acker(M-1, Acker(M, N-1));

return Result;} // end Acker

Page 28: Excersize DataStructure

28

Data Abstraction

1 int AddList(listClass& L)// ----------------------------------------------------------// Computes the sum of the integers in the list L.// Precondition: L is a list of integers.// Postcondition: The sum of the integers in L is returned.// ----------------------------------------------------------{ int Sum = 0, NextItem; boolean Success;

for(int I = 1; I <= L.ListLength(); ++I) { // Invariant: Sum is the total of the first // I elements in L. Success = true;

L.ListRetrieve(I, NextItem, Success);

if(Success) Sum += NextItem; } // end for} // end AddList

2 void Swap(listClass& L, int I, int J, boolean& Success)// -------------------------------------------------------// Swaps the Ith and the Jth items in the list L.// Precondition: L is a list of type listItemType.// Postconditions: If the swap is successful, Success// returns true. Else, Success is false.// -------------------------------------------------------{ listItemType First, Second;

// Test each retrieval and insertion for Success. L.ListRetrieve(I, First, Success);

if(Success) L.ListRetrieve(J, Second, Success); if(Success) L.ListInsert(I, Second, Success); if(Success) L.ListInsert(J, First, Success);

// else, Success = false.} // end Swap

3 void ReverseList(listClass& L, boolean& Success)// ------------------------------------------------------// Reverses the order of the items in list L.// Preconditions: none.// Postconditions: If the contents of the list have been// reversed, then Success is true. Else// Success is false.// ------------------------------------------------------{ int High = L.ListLength();

Success = true; // initialize this for loop test

3

Page 29: Excersize DataStructure

29

for(int Low = 1; Low < High && Success; Low++, High--) // Invariant: The items with indices lower than Low // and higher than High have been swapped. Swap(L, Low, High, Success);} // end ReverseList

4 a A clear advantage to defining such operations externally to the ADT is the control that the client has in customizing the functionality. For example, the manner in which the list items are displayed can be adjusted or formatted or an additional test for replacement of a list item may be performed at the client's discretion.

The disadvantage of this implementation is that the client may fail to test such important procedures as indexing past the end of the list or performing the insertion into the list after the deletion fails.

b Defining these operations within the ADT obviously alleviates the disadvantage cited in part a. Proper bounds checking and other testing is performed within the ADT, removing such concerns from the client.

However, the client cannot control how these operations perform and if greater refinement of control is required he must write additional functionality making use of the suite of operations provided by the ADT.

5 Some ADT set operations:

CreateSet()// creates an empty set

DestroySet()// destroys a set

SetCopy(Set2)// copies Set2 to a set

SetIsEmpty()// determines whether a set is empty

SetSize()// returns the number of elements in a set (the cardinality)

IsSubsetOf(Set2)// determines whether a set is a subset of a Set2

IsAnElement(Item)// determines if Item is an element of a set

SetUnion(Set2)// inserts all items in Set2 into a set

SetIntersection(Set2)// deletes all items from a set that are not in Set2

6 Some ADT string operations:

Page 30: Excersize DataStructure

30

CreateString()// creates a null terminated empty string

DestroyString()// destroys a string

StringCopy(String2)// copies String2 to a string

StringLength()// returns the length of a string, excluding the null character

StringConcatenation(String2)// concatenates String2 to the end of a string

StringCompare(String2)// returns the result of a comparison between String2 and a string

LocateCharInString(Char)// returns the position of a character, Char, in a string

LocateStringInString(String2)// returns the starting position of a substring, String2, in a string

7a Change the purpose of an appointment:

ChangeAppointmentPurpose(AB, Date, Time, Purpose, Success) if(AB.IsAppointment(Date, Time)) AB.CancelAppointment(Date, Time, Success)

AB.MakeAppointment(Date, Time, NewPurpose, Success)

7b Display all the appointments for a given date:

DisplayAllAppointments(AB, Date, Success) Time = BegOfDay

while(Time < EndOfDay) if(AB.IsAppointment(Date, Time)) AB.DisplayAppointment(Date, Time, Success)

Time = Time + HalfHour

This implementation requires the definition of a new operation,DisplayAppointment (), as well as definitions for the constantsBegOfDay , EndOfDay and HalfHour .

8 a Display(P.Coefficient(P.Degree()))

b P.ChangeCoefficient(P.Coefficient(3) + 8, 3)

c for(Power = 0; Power < P.Degree() || Power < Q.Degree(); ++Power) // Invariant: R is the sum of polynomials P and Q to degree Power. R.ChangeCoefficient(P.Coefficient(Power) + Q.Coefficient(Power), Power)

9 In the following implementation, the 0th power corresponds to thefirst item in the member list of the ADT polynomial.

Page 31: Excersize DataStructure

31

Degree()// Returns the degree of a polynomial return L.ListLength() - 1

Coefficient(Power)// Returns the coefficient of the x^Power term. L.ListRetrieve(Power + 1, Coefficient, Success) if(Success) return Coefficient else // Power may be greater than Degree return 0

ChangeCoefficient(NewCoefficient, Power)// Replaces the coefficient of the x^Power term with NewCoefficient L.ListDelete(Power + 1, Success) if(Success) L.ListInsert(Power + 1, NewCoefficient, Success)

10 boolean Success = true;

for(int I = 0; I < N && Success; ++I)// Invariant: L contains the first I elements of A in ascending order L.SortedListInsert(A[I], Success);

for(int I = 0; I < N && Success; ++I)// Invariant: A contains the first I elements of L in ascending order L.SortedListRetrieve(I, A[I], Success);

11 The first sequence of insertions is written as follows:

((L.ListInsert(2, A)).ListInsert(2, B)).ListInsert(2, C)

It is sufficient to show the characters A, B, and C are at positions 4, 3, and

Let M represent L.ListInsert(2, A) and N represent M.ListInsert(2, B)

Now retrieve the second, third, and fourth items in the list N.ListInsert(2, C) as

Show the second item, C: (N.ListInsert(2, C)).ListRetrieve(2) = C by axiom 9

Show the third item, B: (N.ListInsert(2, C)).ListRetrieve(3) = N.ListRetrieve(2) by axiom 10 = (M.ListInsert(2, B)).ListRetrieve(2) by definition of N = B by axiom 9

Show the fourth item, A: (M.ListInsert(2, B)).ListRetrieve(3) = M.ListRetrieve(2) by axiom 10 = (L.ListInsert(2, A)).ListRetrieve(2) by definition of M = A by axiom 9

Page 32: Excersize DataStructure

32

13 int F( int N )// Note: list items are accessed beginning at position 1// rather than position 0. This introduces an additional// offset after taking the mod of N for the retrieval and// updating of the proper values.{ listClass Last5; boolean Success; int I, result = 0, temp1, temp2;

// insert items 1 through 5 into list Last5.ListInsert(1, 1, Success); Last5.ListInsert(2, 1, Success); Last5.ListInsert(3, 1, Success); Last5.ListInsert(4, 3, Success); Last5.ListInsert(5, 5, Success);

if (N>=0 && N<5) // base case Last5.ListRetrieve(N+1, result, Success); else if(N >= 5) { for (I=5; I<N; I++) { Last5.ListRetrieve((I-1)%5+1, temp1, Success);

Last5.ListRetrieve((I-5)%5+1, temp2, Success); Last5.ListDelete(I%5+1, Success); Last5.ListInsert(I%5+1, temp1+3*temp2, Success);

} Last5.ListRetrieve((N-1)%5+1, result, Success); } // else result = 0

return result;} // end F

14 for(Index = 1 through A.ListLength() or B.ListLength()){ A.SortedListRetrieve(Index, DataItem, Success) if(Success) C.SortedListInsert(DataItem, Success)

B.SortedListRetrieve(Index, DataItem, Success) if(Success) C.SortedListInsert(DataItem, Success)}

Page 33: Excersize DataStructure

33

Linked Lists

1 Starting from the list that results from Self-Test Exercise 3, and assuming the

struct node; typedef node* ptrType;

struct node { char Ch; ptrType Next; };

ptrType Head, Prev, Cur, P;

we have the following:

a ‘F’ gets inserted into the middle as follows:

P = new node; P->Next = Cur; Prev->Next = P; P->Ch = 'F';

b To delete the last node (containing J) on the list resulting from the previ o

Prev->Next = NULL; delete Cur;

c ‘G’ gets inserted at the end of the list resulting from the abovestatements by executing

Prev->Next = new node; Prev->Next->Ch = 'G'; Prev->Next->Next = NULL;

2a Insert and delete at the head of the linked list:

void InsertNode (ptrType& Head, ptrType NewNode){ if (Head == NULL) { Head = NewNode; Head->Next = NULL; } else { NewNode->Next = Head; Head = NewNode; }} // end InsertNode

4

Page 34: Excersize DataStructure

34

void DeleteNode (ptrType& Head){ ptrType Cur;

Cur = Head;

if (Cur != NULL) { Head = Head->Next; delete Cur; }} // end DeleteNode

2b Insert and delete at the end of the linked list:

void InsertEndNode (ptrType& Head, ptrType NewNode){ ptrType Cur, Prev;

Cur = Head; Prev = NULL;

while (Cur != NULL) { Prev = Cur; Cur = Cur->Next; }

if (Prev == NULL) Head = NewNode; else Prev->Next = NewNode;} // end InsertEndNode

void DeleteEndNode (ptrType& Head){ ptrType Cur, Prev;

Cur = Head; Prev = NULL;

if (Cur != NULL) { while (Cur->Next != NULL) { Prev = Cur; Cur = Cur->Next; }

// Cur points to node to delete if (Prev == NULL) // only one node to delete Head = NULL; else Prev->Next = NULL;

Cur->Next = NULL; delete Cur; }} // end DeleteEndNode

Page 35: Excersize DataStructure

35

Page 36: Excersize DataStructure

36

2c Insert and delete at the end of the linked list with a tail pointer:

void InsertEndNode (ptrType& Head, ptrType& Tail, ptrType NewNode){ if (Head == NULL) { Head = NewNode; Tail = Head; } else { Tail->Next = NewNode; Tail = Tail->Next; }} // end InsertEndNode

void DeleteEndNode (ptrType& Head, ptrType& Tail){ ptrType Temp;

Temp = Head;

if (Head != NULL) { if (Tail == Head) // only one node to delete { delete Head; Head = Tail = NULL; } else { while (Temp->Next != Tail) Temp = Temp->Next;

// Temp points to node previous to the node to delete Temp->Next = NULL; delete Tail; Tail = Temp; } }} // end DeleteEndNode

3a int ListCount(ptrType Head)// --------------------------------------------------// Returns the number of items in a linked list.// Precondition: Head points to a list of type node.// Postcondition: The number of items in the list// is returned.// --------------------------------------------------{ int Count = 0;

for(ptrType Cur = Head; Cur; Count++, Cur = Cur->Next);

return Count;} // end ListCount

Page 37: Excersize DataStructure

37

3b int ListCount(ptrType Head)// --------------------------------------------------// Returns the number of items in a linked list.// Precondition: Head points to a list of type node.// Postcondition: The number of items in the list// is returned.// --------------------------------------------------{ if(Head) return 1 + ListCount(Head->Next); else // base case return 0;}

4 typedef struct node* ptrType;typedef int itemType;

struct node{ itemType Data; ptrType Next;};

void DeleteHighestItem(ptrType& Head)// ----------------------------------------------------------// Deletes the largest item from the list pointed to by Head.// Precondition: Head points to a list of type node.// Postcondition: The largest item in the list pointed to by// Head is removed.// ----------------------------------------------------------{ ptrType Prev, Curr, HighPrev, HighCurr;

Curr = HighCurr = Head; Prev = HighPrev = NULL;

if(Curr != NULL) // if there is a list { if(Curr->Next == NULL) // if there is only one item { delete Head; Head = NULL; } else { while(Curr->Next != NULL) { Prev = Curr; Curr = Curr->Next;

// keep track of highest item if(Curr->Data > HighCurr->Data) { HighCurr = Curr; HighPrev = Prev; } }

// delete node containing highest item if(HighPrev) HighPrev->Next = HighCurr->Next; else // first node is the highest Head = HighCurr->Next; delete HighCurr; } } // end if

Page 38: Excersize DataStructure

38

} // end DeleteHighestItem

5a The following is an iterative implementation of WriteString. This version, li kproceeds in linear fashion from the beginning of the string to the end.

typedef struct node* ptrType;

struct node{ char Item; ptrType Next;};

ptrType StringPtr;

void WriteString(ptrType StringPtr)// ---------------------------------------------------------// Writes a string.// Precondition: The string is represented as a linked list// to which the pointer StringPtr points.// Postcondition: The string is displayed. The linked list// and StringPtr are unchanged.// ---------------------------------------------------------{ for(ptrType Curr = StringPtr; Curr; Curr = Curr->Next) cout << Curr->Item;}

5b The following is an iterative implementation of WriteBackward2 . Unlike the recuriterative approach is not straightforward: while the recursive version takes N the iterative version must first take N steps to get to the last character, th eto the last, and so on taking N + (N-1) + ... + 1 or N*(N+1)/2 steps altogeth e

typedef struct node* ptrType;

struct node{ char Item; ptrType Next;};

ptrType StringPtr;

void WriteBackward2(ptrType StringPtr)// ---------------------------------------------------------// Writes a string backward.// Precondition: The string is represented as a linked list// to which the pointer StringPtr points.// Postcondition: The string is displayed backward. The// linked list and StringPtr are unchanged.// ---------------------------------------------------------{ int Count = 0; ptrType Curr = StringPtr;

if(Curr != NULL) { Count++; // string is at least one character long

while(Curr->Next != NULL) { Count++;

Page 39: Excersize DataStructure

39

Curr = Curr->Next; }

cout << Curr->Item; // print last character Count--; // decrement length of rest of string

while(Count > 0) // for whatever remains of the string { int Temp = 1; Curr = StringPtr; // reset pointer to beg. of string

while(Temp < Count) { Temp++; Curr = Curr->Next; } cout << Curr->Item; // print last character Count--; // decrement length of rest of string } // end while } // end if} // end WriteBackward2

6 void MergeSortedLists(ptrType Head1, ptrType Head2, ptrType& MergeHead)// ------------------------------------------------------------------// Merges two lists sorted in ascending order into a third list.// Preconditions: The lists pointed to by Head1 and Head2 are sorted// in ascending order. Result points to no list.// Postconditions: Result points to a sorted list containing the// contents of the lists pointed to by Head1 and Head2 in ascending// order. The original lists pointed to by Head1 and Head2 are// unchanged.// ------------------------------------------------------------------{ boolean FirstNode = true; ptrType Cur1, Cur2, MergeCurr;

Cur1 = Head1; Cur2 = Head2;

// if neither list is empty merge them while(Cur1 != NULL && Cur2 != NULL) { if(FirstNode) { MergeHead = new node; MergeCurr = MergeHead; FirstNode = false; } else { MergeCurr->Next = new node; MergeCurr = MergeCurr->Next; }

MergeCurr->Next = NULL; // remember to terminate the list

if(Cur1->Item < Cur2->Item) // copy item from list 1 { MergeCurr->Item = Cur1->Item; Cur1 = Cur1->Next; } else // copy from list 2 { MergeCurr->Item = Cur2->Item; Cur2 = Cur2->Next; } } // end while

if(Cur1 != NULL) // determine which list is not completely traversed

Page 40: Excersize DataStructure

40

Cur2 = Cur1

Page 41: Excersize DataStructure

41

while(Cur2) { if(FirstNode) // in case one of the lists was empty { MergeHead = new node; MergeCurr = MergeHead; FirstNode = false; } else { MergeCurr->Next = new node; MergeCurr = MergeCurr->Next; }

MergeCurr->Item = Cur2->Item; MergeCurr->Next = NULL; Cur2 = Cur2->Next; } //end while} // end MergeSortedLists

7 If Head points to a non-empty linked list, then the contents of that list beco mis reassigned. It is important to note that these nodes are not deallocated b yso the memory they occupy cannot, as a result, be reallocated to another point ea "memory leak".

8 Traversing an array of size N and traversing a linked list of N nodes both req uwill differ by a constant factor for increasing N. You may be inclined to think faster by a constant factor since only a cout is executed each time through the

for (I=0; I<N; I++) cout << A[I];

However, since a for loop has implicit comparison and increment operations, it wimplement the array traversal as follows for comparison purposes.

I = 0; while (I < N) { cout << A[I]; I++; }

This array traversal loop executes the same number of C++ statements as does thprogram fragment cited. A more detailed analysis would require looking at the a sproduced by the compiler.

9 Consider first the case where Position = 1. In an array based implementation tis deleted by overwriting with the value of the second position and this value ,third position until, if the List is of size N, then N-1 overwrites must occur decremented. In the pointer-based implementation, the special case for deletio nlist is invoked, assigning the address of the first node to a temporary pointe rto the next node in the list, and then deleting what was the first node. The esmall, constant number of steps versus the O(N) steps required by the array im p

For the case where Position = N, in an array-based implementation this becomes address of the item to be deleted can be found immediately by indexing into th eat the end of the list, only the value for Size need be reduced, all of which tthe pointer-based implementation, by contrast, the entire list must be travers eis accessed. (Note that this would be true even if the list implemented a Tai lpointer to be reassigned following the deletion, the address of the preceding n

Page 42: Excersize DataStructure

42

after N-1 pointer assignments can the last node be reassigned to a temporary po ipreceding node reassigned to NULL, and the last node deleted. This forms the wbased list, taking O(N) time.

For the average case where position = N/2, both implementations fare similarly.access the N/2th position with one assignment but must then perform another N/ 2reduction of the value Size. By contrast, the pointer-based list must do N/2- 1finds the node to delete but then performs a constant number of operations for dconnecting the list. Thus both require somewhere in the vicinity of N/2 steps

If it is known where deletions will be performed in the list in general, then t himplementation will result in an increase in efficiency. If for example more d ehalf of the list than from the first, then an array-based implementation will i nthe pointer-based list. If no predictable pattern of deletions is known in adv aof an array-based versus a pointer-based list will have less impact on the over a

10 Print the contents of one of our circular lists.

void PrintCircular (ptrType List){ ptrType Stop;

Stop = List;

if (List != NULL) do { cout << List->Data; List = List->Next; } while (List != Stop);} // end PrintCircular

11a listClass::~listClass() // destructor{ if(Head) { ptrType Curr = Head;

Curr = Curr->Next; // advance curr pointer past Head Head->Next = NULL; // make Head the last node in list

while(Curr != Head) // Curr cannot be NULL in a circular list { ptrType Temp = Curr; Curr = Curr->Next; delete Temp; Temp = NULL; } // end while

delete Head; // delete last node Head = Curr = NULL; } // end if} // end destructor

11b listClass::listClass (listClass& L) // copy constructor{ ptrType P, Stop;

if (L.Head != NULL) { Stop = L.Head;

Page 43: Excersize DataStructure

43

// copy first node Head = new node; Head->Data = L.Head->Data; P = Head; Stop = Stop->Next;

// copy rest of the list while (L.Head != Stop) { // Stop is one node ahead of P P->Next = new node; P = P->Next; P->Data = Stop->Data; Stop = Stop->Next; } P->Next = Head; // complete the circle } else Head = NULL;} // end function ListCopy

12 This routine must deal with the event that I is larger than the number of node sthe nodes on a list of N nodes are implicitly numbered 1, ..., N. We also assu"last" node in the list.

void DeleteItem (ptrType& List, int I){ ptrType Prev, Cur; int J; boolean Done;

Done = boolean ((I < 1) || (List == NULL); Prev = List; Cur = List->Next; J = 1;

while ((J < I) && (!Done)) { Prev = Cur; Cur = Cur->Next;

Done = boolean (Cur == List->Next); // check for a completely // traversed list

J++; }

if (!Done) // Cur points to the node to be deleted { if (Cur == List) List = Prev; // move the List pointer to the new "last" node Prev->Next = Cur->Next; Cur->Next = NULL; delete Cur; } // end if} // end DeleteItem

13 Scan the list with current and previous pointers and change current’s Next to pstep.

void Reverse (ptrType& List){ ptrType Cur, Prev, Temp;

Page 44: Excersize DataStructure

44

if (List != NULL) { Prev = List; Cur = List->Next;

do { Temp = Cur->Next; Cur->Next = Prev; Prev = Cur; Cur = Temp; } while (Cur != List);

Cur->Next = Prev; List = Cur; // reset List to point to lowest integer }} // end Reverse

14 Implementing ListInsert() and ListDelete() using a dummy head node:

void listClass::ListInsert(int NewPosition, listItemType NewItem, bool& Success){ int NewLength = ListLength() + 1;

Success = bool((NewPosition >= 1) && (NewPosition <= NewLength));

if (Success) { // create new node and place NewItem in it ptrType NewPtr = new listNode; Success = bool(NewPtr != NULL);

if (Success) { Size = NewLength; NewPtr->Item = NewItem;

// attach new node to list if (NewPosition == 1) { // insert new node after the dummy head node NewPtr->Next = Head->Next; Head->Next = NewPtr; } else { ptrType Prev = PtrTo(NewPosition-1); // insert new node after node // to which Prev points NewPtr->Next = Prev->Next; Prev->Next = NewPtr; } // end if } // end if } // end if} // end ListInsert

Page 45: Excersize DataStructure
Page 46: Excersize DataStructure

46

while(!Fin.eof()) { P->Next = new listNode; P = P->Next; P->Next = NULL; Fin >> P->Data; } // end while

Fin.close(); } else { cerr << "Could not open " << Filename << endl; } // end if} // end RestoreList

16 // insertion of a node into a doubly linked list with a dummy head node

ptrType Dummy = ListHead; // assumes ListHead points to dummy nodeptrType Cur = Dummy->Next;

// compare names and position in circular list to find insertion pointwhile((strcmp(Cur->Data, NewName) < 0) && (Cur != Dummy)) Cur = Cur->Next;

// after insertion point is found, insert node and copy dataptrType Temp = new listNode;Temp->Next = Cur;Temp->Precede = Cur->Precede;Cur->Precede->Next = Temp;Cur->Precede = Temp;strcpy(Temp->Data, NewName);

17 // deletion of a node from a doubly linked, circular linked list.// Assumes ListHead points to dummy head node.

ptrType Dummy = ListHead;ptrType Cur = Dummy->Next;

// advance until NewName is found or dummy node is reachedwhile((strcmp(Cur->Data, NewName) != 0) && (Cur != Dummy)) Cur = Cur->Next;

// if NewName has been found, reset pointers and delete nodeif(strcmp(Cur->Data, NewName)){ ptrType Temp = Cur; Cur->Precede->Next = Cur->Next; Cur->Next->Precede = Cur->Precede; Temp->Next = Temp->Precede = NULL; delete Temp; Temp = NULL;} // end if

Page 47: Excersize DataStructure

47

18 // insertion of a node into a doubly linked list without a dummy head// node

ptrType Cur = ListHead;

// compare names in list to find insertion pointwhile((Cur != NULL) && (Cur->Next != NULL) && (strcmp(Cur->Data, NewName) < 0)) Cur = Cur->Next;

ptrType Temp = new listNode;

// if insertion point is at beginning of list...if(Cur == ListHead){ Temp->Next = ListHead; Temp->Precede = NULL; ListHead = Temp;}

// if insertion point is at end of list...else if(Cur->Next == NULL){ Temp->Next = NULL; Temp->Precede = Cur; Cur->Next = Temp;}

else{ Temp->Next = Cur; Temp->Precede = Cur->Precede; Cur->Precede->Next = Temp; Cur->Precede = Temp;}

strcpy(Temp->Data, NewName);

// deletion of a node from a doubly linked list.

ptrType Cur = ListHead;

// advance until NewName is found or dummy node is reachedwhile((Cur != NULL) && (strcmp(Cur->Data, NewName) != 0)) Cur = Cur->Next;

// if NewName has been found, reset pointers and delete nodeif(Cur != NULL){ ptrType Temp = Cur;

if(Cur->Precede != NULL) Cur->Precede->Next = Cur->Next; else // at beginning of list ListHead = Cur->Next; if(Cur->Next != NULL) Cur->Next->Precede = Cur->Precede; Temp->Next = Temp->Precede = NULL; delete Temp; Temp = NULL;} // end if

Page 48: Excersize DataStructure

48

19 If Person is saved as a C++ structure, then the listItemType need only be redefine dPerson . The remaining implementation will then handle Person as a simple data t ythough one of the fields in Person is a character string (i.e.: Name), the assig nautomatically copy ALL of the internal data from one struct Person to another stru

If Person is saved as a C++ class, then it should be designed as an Abstract Da tattributes of a Person must be supplied with individual, well-defined accessor f uretrieving the values of those attributes.

20 // At this point, Cur points to the desired stock item.

if(Cur->WaitHead == NULL){ Cur->WaitHead = new waitNode; Cur->WaitTail = Cur->WaitHead;}else{ Cur->WaitTail->Next = new waitNode; Cur->WaitTail = Cur->WaitTail->Next;}

Cur->WaitTail->Next = NULL;strcpy(Cur->WaitTail->Who, NewName);

Page 49: Excersize DataStructure

49

Recursion as a Problem-Solving Technique

1a The call IsPal(abcdeba) produces the following box trace:

The initial call is made and the function begins execution:

At the else if stmt., the call IsPal(“bcdeb”) is made:

At the else if stmt., the call IsPal(“cde”) is made:

Base case: IsPal(“cde”) returns false:

The call IsPal(“bcdeb”) returns false:

The call IsPal(“abcdeba”) returns false and the initial call completes.

1b The call IsAnBn(AABB) produces the following box trace:

The initial call is made and the function begins execution:

The call to IsAnBn(“AB”) is made:

The call to IsAnBn(“”) is made:

5

W = “abcdeba”

W = “abcdeba” W = “bcdeb”

W = “abcdeba” W = “bcdeb” W = “cde”

W = “abcdeba” W = “bcdeb”W = “cde”

return false;

W = “abcdeba”W = “bcdeb”

return false;

W = “cde”

return false;

W = “abcdeba”

return false;

W = “bcdeb”

return false;

W = “cde”

return false;

W = “AABB”

W = “AABB” W = “AB”

W = “AABB” W = “AB” W = “”

Page 50: Excersize DataStructure

50

Base case: W = empty string, returns true:

The call IsAnBn(“AB”) returns true:

The call IsAnBn(“AABB”) returns true and the initial call completes.

1c The call EndPre(-*/ABCD) produces the following box trace:

S = “-*/ABCD”;

W = “AABB”

First = 0Last = 6

X:EndPre(S,1,6)

W = “AB”

First = 1Last = 6FirstEnd = 4Y:EndPre(S,5,6)

W = “”

return true;

First = 5Last = 6

W = “AABB”W = “AB”

return true;

W = “”

return true;

W = “AABB”

return true;

W = “AB”

return true;

W = “”

return true;

First = 0Last = 6

First = 0Last = 6

X:EndPre(S,1,6)

First = 1Last = 6

First = 0Last = 6

X:EndPre(S,1,6)

First = 1Last = 6

X:EndPre(S,2,6)

First = 2Last = 6

First = 0Last = 6

X:EndPre(S,1,6)

First = 1Last = 6

X:EndPre(S,2,6)

First = 2Last = 6

X:EndPre(S,3,6)

First = 3Last = 6

First = 0Last = 6

X:EndPre(S,1,6)

First = 1Last = 6

X:EndPre(S,2,6)

First = 2Last = 6FirstEnd = 3

First = 3Last = 6return 3

First = 0Last = 6

X:EndPre(S,1,6)

First = 1Last = 6

X:EndPre(S,2,6)

First = 2Last = 6FirstEnd = 3Y:EndPre(S,4,6)

First = 4Last = 6

First = 0Last = 6

X:EndPre(S,1,6)

First = 1Last = 6

X:EndPre(S,2,6)

First = 2Last = 6FirstEnd = 3return 4

First = 4Last = 6return 4

First = 0Last = 6

X:EndPre(S,1,6)

First = 1Last = 6FirstEnd = 4

First = 2Last = 6FirstEnd = 3return 4

Page 51: Excersize DataStructure

51

2 The following lists all of the strings of length 7 or less that may be constru c

$ abb aabbbb$$ $abb $aabbbb$$$ $$abb$$$$ $ $$abb$$$$$ $$$$abb$$$$$$$$$$$$$

3 <S> = <U> | <U> <L><U> = A | B | … | Z<L> = a | b | … | z | a <L> | b <L> | …| z <L>

4 <S> = - - <C> . | . . <C> -<C> = . | - | . <C> | - <C>

5a - - .- . .. . .

First = 0Last = 6

X:EndPre(S,1,6)

First = 1Last = 6FirstEnd = 4return 5

First = 5Last = 6return 5

First = 0Last = 6FirstEnd = 5

First = 1Last = 6FirstEnd = 4return 5

First = 0Last = 6FirstEnd = 5Y:EndPre(S,6,6)

First = 6Last = 6

First = 0Last = 6FirstEnd = 5return 6

First = 6Last = 6return 6

First = 0Last = 6FirstEnd = 5return 6

Page 52: Excersize DataStructure

52

5b The string . . . . - - is not in the language because it is not possible for aanywhere except at the beginning.

5c word0 = - - - - - - .

Word0 is legal because it is of the form <dash><word>. We may recursively rem oeach subword thus discovered until we get to the terminal subword “.” which is

5d IsIn(s)// Returns true if S is in the indicated language, false otherwise Size = length of string S

if(Size == 1 and S[0] == Dot) return true else if (Size > 1 and S[0] == Dash) return IsIn( S minus first character ) else if (Size > 1 and S[Size - 1] == Dot) return IsIn( S minus last character) else return false

6 Let L = {S: S is of the form A nB2n, for some n > 0}

a <S> = ABB | A <S> BB

b #include <string.h>

const int MAX_LENGTH = 80;typedef char stringType[MAX_LENGTH];typedef int boolean; . . .boolean IsInL(stringType S)// Determines it the string S is in the language L.// Precondition: none.// Postcondition: returns true if S is in L, false otherwise.{ int Size = strlen(S);

if (Size < 3) // no strings shorter than 3 are in L. return false; else if (strcmp(S, "ABB") == 0) // base case return true; else { stringType Substring;

// trim off first and last two characters of S strncpy(Substring, &S[1], Size - 3); return IsInL(Substring); }} // end IsInL

Page 53: Excersize DataStructure

53

7 Let S = "+*A-B/C++DE-FG".

S is not a prefix expression since it is defined neither by the form <identifie<operator><prefix><prefix>. The first case is clear by inspection. To show t hcomponent prefix substrings by the following.

Let S = +E 1E2. We continue recursively by deriving the expressions E i :

E1 = *E 3E4

E3 = A

E4 = -E 5E6

E5 = B

E6 = /E 7E8

E7 = C

E8 = +E 9E10

E9 = +E 11E12

E11 = D

E12 = E

E10 = -E 13E14

E13 = F

E14 = G

This exhausts the string S before the prefix expression E 2 is defined. Thus S iexpression.

8 The string S = "AB/C*EFG*H/+D-+" is a valid postfix string. To show this we fir ssimple identifier and so it must be an expression of the form

E xEy

where the terminal symbol "+" is preceded by two postfix expressions. We atte mexpressions by proceeding from the front of the string as follows:

E1 = A

E2 = B

E3 = E 1E2/E4 = C

E5 = E 3E4*E6 = E

E7 = F

E8 = G

E9 = E 7E8*E10 = H

E11 = E 9E10/E12 = E 6E11+E13 = D

E14 = E 12E13-E15 = E 5E14+

Thus, E 5 = E x and E 14 = E y and so S is a valid postfix expression.

9 a 1AA 2AA1AB 2AB1BA 2BA

Page 54: Excersize DataStructure

54

1BB 2BB

b One such string is the following:

12AAB

We note that this is of the form <D><S><S> where <D> = 1, <S> = 2AA and <S> = <S> is also of the form <D><S><S> where <D> = 2, <S> = A and the other <S> al s

10 a <S> = A | B | C <S> | D <S>

b CAB is not in the language since both A and B are terminals and there is no ex psequence of terminals.

c #include <string.h>

const int MAX_LENGTH = 80;typedef int boolean;typedef char stringType[MAX_LENGTH];

boolean IsInL(stringType S)// Determines if S is in L// Preconditions: none.// Postcondition: returns true if S is in L, false otherwise.{ int Size = strlen(S);

// base case if ((Size == 1) && ((S[0] == 'A') || (S[0] == 'B'))) return true; else if ((Size > 0) && ((S[0] == 'C') || (S[0] == 'D'))) { strType Substring;

// trim off initial character from S strncpy(Substring, &S[1], Size - 1); return IsInL(Substring); } else return false;} // end IsInL

11 The recognition algorithm uses recursion to backtrack, reading in the character calling the function recursively on the substring indexed by First+1 and Last- 1compares the character at index Last with that of First. A C++ implementation

boolean IsPal(stringType S, int First, int Last){ if (Last < First) return false;

else if ((First == Last) && // base case (S[First] == '$')) return true; else if (First < Last) return (IsPal(S, First+1, Last-1) && (S[First] == S[Last])); else

Page 55: Excersize DataStructure

55

return false;} // end IsPal

12 a

m XX

m X m X X( )

( ) ( )=

<− + − + ≥

0 3

1 3 1 3

b Base case: By definition, m(X) returns 0 for the case X < 3.

Inductive hypothesis: Let m(X) = m(X-1) + m(X-3) + 1, X ≥3.

Consider m(X+1): this function returns the number of multiplications performe dknow X+1 > 3 since X ≥ 3 by inductive hypothesis. Therefore the function P() will mto itself with the arguments P((X+1)-1) and P((X+1)-3) and then perform an addi tof the return values of these function calls. We also know from inductive hypo tperforms m(X) multiplications and P((X+1)-3) or P(X-2) performs m(X-2) multipli cnumber of multiplications for m(X+1) = m(X) + m(X-2) + 1, i.e.: m(X+1) = m((X +

13 a

C n

n

n

C n n

( )

( )

===

⋅ − >

1 0

26 1

26 2 1

b Base case(s): The null string is the same backwards and forwards so it counts number of lowercase letters is 26, this is the number of possible palindromes o

Inductive hypothesis: C(n) = 26*C(n-2) , n > 1

Consider C(n+1): Since the string is a palindrome we know that its starting a nidentical and that there are 26 possible letters for this repeated character. Scharacter may be chosen independently from the characters in the the substring ecount of all possible palindromes of length n+1 is then 26 times the count of athe length of this substring, (n+1)-2 or n-1. By hypothesis we know that the ei, 1 < i ≤ n. Thus, C(n+1) = 26*C((n+1)-2) or C(n+1) = 26*C( n-1).

14 If E is a prefix expression, then EY is not a prefix expression for any nonempt ycannot be the initial substring of another prefix expression). We will give a pnumber of characters in E.

(the null string is a

Page 56: Excersize DataStructure

56

Basis |E| = 1: Definition of prefix implies E is a single letter and definitio nbegin with an operator.

Inductive hypothesis: For all E with 1 < |E| < n and for all nonempty Y, if E prefix.

Inductive step: Say |E| = n, then E = op E 1 E 2 for some E 1 and E 2, which implie sexpressions and that | E 1 |, | E 2 | < n. If EY is prefix for some Y, then EY = and W1 and W2 are prefix expressions.

We claim that E 1 = W1; if not, then one is a substring of the other, so both ca nhypothesis (|E 1| < n).

Summarizing what we have so far:E = op E 1 E 2

andE = op W 1 W2

E = op E 1 W2

E = op E 1 E 2 Y

But this implies that W 2 = E 2Y, which cannot be because E 2 and W 2 are both prefix esubstring of W 2.

15 Prove by induction on n that

C n kn

n k k( , )

!

( )! !=

for all n and k such that 0 ≤ k ≤ n.

Basis: Show true for n = 0. That is, show

C kk k

( , )!

( )! !0

0

0=

−for all k such that 0 ≤ k ≤ 0.

If n = 0, then k must equal 0 and we have C(0,0) = 1 by definition. And, 0!/(0!0!) = 1, so the basis isestablished.

Inductive hypothesis: Assume true for n = m–1. That is, assume

C m km

m k k( , )

( )!

( )! !− =

−− −

11

1

for all k such that 0 ≤ k ≤ m–1.

Page 57: Excersize DataStructure

57

Inductive conclusion: We must show the claim to be true for n = m. That is, show

C m km

m k k( , )

!

( )!!=

−for all k such that 0 ≤ k ≤ m.

There are three cases to consider:

Case 1: If k = 0, then we have C(m,0) = 1 by definition and m!/(( m–0)!0!) = 1.

Case 2: If k = m, then we have C(m,m) = 1 by definition and m!/((m–m)!m!) = 1.

Case 3: If 0 < k < m, then we have C(m,k) = C(m–1,k) + C(m–1,k–1) by definition, and so by theinductive hypothesis (note k m–1), we have

C m km

m k k

m

m k k

m

m k k( , )

( )!

( )! !

( )!

(( ) ( ))!( )!

!

( )!!− =

−− −

+−

− − − −=

−1

1

1

1

1 1 1

This establishes that the inductive hypothesis implies the inductive conclusion and completes theproof.

Page 58: Excersize DataStructure

58

PART II: Problem Solving with Abstract Data Types

Stacks

1a All parts of Exercise 1 assume the standard stack operations as defined in the c

void PrintReverse(stackClass& S)// Displays the contents of the stack S in reverse order.{ stackItemType StackItem; stackClass T; boolean Success;

// put items into reverse order while(!S.StackIsEmpty()) { S.GetStackTop(StackItem, Success); T.Push(StackItem, Success); S.Pop(Success); } // end while

// restore the original stack and display the items while(!T.StackIsEmpty()) { T.GetStackTop(StackItem, Success); cout << StackItem; S.Push(StackItem, Success); T.Pop(Success); } // end while} // end PrintReverse

1b int CountItems(stackClass& S)// Counts the number of items in the stack S.{ stackItemType StackItem; stackClass T; boolean Success; int counter = 0;

// put items into reverse order and count the items while(!S.StackIsEmpty()) { S.GetStackTop(StackItem, Success); T.Push(StackItem, Success); S.Pop(Success); counter++; } // end while

// restore the original stack while(!T.StackIsEmpty()) { T.GetStackTop(StackItem, Success); S.Push(StackItem, Success); T.Pop(Success); } // end while

return counter;} // end CountItems

6

Page 59: Excersize DataStructure

59

1c void RemoveItem(stackClass& S, stackItemType Item)// Removes all occurences of Item from the stack S.{ stackItemType StackItem; stackClass T; boolean Success;

// put items into reverse order removing all occurrences of Item while(!S.StackIsEmpty()) { S.GetStackTop(StackItem, Success); if (StackItem != Item) T.Push(StackItem, Success); S.Pop(Success); } // end while

// restore the original order of the remaining stack items while(!T.StackIsEmpty()) { T.GetStackTop(StackItem, Success); S.Push(StackItem, Success); T.Pop(Success); } // end while} // end RemoveItem

2 There are three stacks: the upper-left, the upper-right, and the lower-middle s ethe upper-left and the upper-right stacks are pushed onto the lower-middle stac kmiddle stack can be pushed onto either the upper-left or the upper-right stack. cars can be constructed.

3a void stackClass::Display(boolean& Success)// Displays the contents of a stack.// Preconditions: None// Postconditions: The stack items are displayed.// The original stack remains unchanged.// Note: This function is independent of the stack's implementation.{ stackItemType StackItem; stackClass Temp;

Success = boolean(!StackIsEmpty()); if (Success) { // put items into reversed order and display the stack items while(!StackIsEmpty()) { GetStackTop(StackItem, Success); cout << StackItem; Temp.Push(StackItem, Success); Pop(Success); } // end while

// restore the original stack while(!Temp.StackIsEmpty()) { Temp.GetStackTop(StackItem, Success); Push(StackItem, Success); Temp.Pop(Success); } // end while } // end if} // end Display

Page 60: Excersize DataStructure

60

3b void stackClass::Display(boolean& Success)// Displays the contents of a stack. // Preconditions: None// Postconditions: The stack items are displayed.// The original stack remains unchanged.// Note: This function assumes a pointer based stack implementation.{ ptrType Cur;

Success = boolean(TopPtr != NULL); if (Success) { // display the items Cur = TopPtr; while(Cur != NULL) { cout << Cur->Item; Cur = Cur->Next; } // end while } // end if} // end Display

4 In the array-based implementation of the ADT list, the worst case for a list ininsertion occurs at the beginning of the list since each insertion here forces tlist one index down. If the ADT stack operations maintain the Top of the stac kthen each Push() and Pop() call will take O(n) time.

If, however, the ADT stack maintains a member variable Top which contains the i nlist, then the stack can take advantage of the best case for a list insertion othe list at position Top and incrementing Top (employing, of course, the prope rend of the array). This operation can be done in O(1) time which is comparableoperations when a pointer-based implementation is used.

5a Contents of the stack during input:

Contents of the stack during output:

The final output is hfba.

5b // Assume stack S contains the items to be displayedT.CreateStack()

// shift contents of S to temporary stackwhile(!S.StackIsEmpty()){ T.Push(S.GetStackTop()) S.Pop()}

// Now shift them back to S, displaying each itemwhile(!T.StackIsEmpty())

aba

dba

cba

ba

edba

dba

ba

fba

gfba

fba

hfba

hfba

fba

ba a

Page 61: Excersize DataStructure

61

{ Item = T.GetStackTop() Write (Item) S.Push(Item) T.Pop()}

5c #include <iostream.h>#include <string.h>

const int MAX_LENGTH = 80;typedef char stringType[MAX_LENGTH];typedef char stackItemType;

void ReadAndCorrect(stringType Str)// Reads in a string of characters and uses the backspaces// in the string to correct the final contents of the string.// Precondition: Backspaces are represented by the paired// sequence of characters '<' and '-'.// Postcondition: The string Str is corrected.{ int Size = strlen(Str); stackClass S, T;

for (int I = 0; I < Size; ++I) { // if not a backspace, add character to stack if(Str[I] != '<') S.Push(Str[I]);

// else, it is a backspace: pop a character and // increment the counter past the '-' of the backspace else if(!S.StackIsEmpty()) { S.Pop(); I++; }

// else, "ignore the '<-'" } // end for

// now, reconstruct the string while(!S.StackIsEmpty()) { T.Push(S.GetStackTop()); S.Pop(); }

for(int I = 0; !T.StackIsEmpty(); ++I) { Str[I] = T.GetStackTop(); T.Pop(); }

// terminate the string Str[I] = '\0';} // end ReadAndCorrect

6 Modified pseudocode solution for parenthesis matching to include three types (

S.CreateStack()Continue = TRUEI = 0

while (I < strlen(Str) and Continue){ // ignore all characters but (, {, [, ], } and )

Page 62: Excersize DataStructure

62

if ( (Str[I] != ')') and (Str[I] != '(') and (Str[I] != '}') and (Str[I] != '{') and (Str[I] != ']') and (Str[I] != '[') ) ++I

// process open parenthesis else if( (Str[I] == '(') or (Str[I] == '{') or (Str[I] == '[') ) { S.Push(Str[I], Success) ++I }

// process close parenthesis else if(!S.StackIsEmpty()) { S.GetStackTop(StackItem, Success)

// try to match open and close parenthesis of the same type if ( ((Str[I] == ')') and (StackItem == '(')) or ((Str[I] == '}') and (StackItem == '{')) or ((Str[I] == ']') and (StackItem == '[')) ) { S.Pop(Success) ++I } else // open and close parenthesis are not of the same type Continue = FALSE }

else // unmatched open and close parenthesis Continue = FALSE} // end while

// Note that if Continue is FALSE, I < strlen(Str),// so no test of Continue is necessary

if ( (I >= strlen(Str)) and S.StackIsEmpty() ) report the string has matching parenthesiselse report the string does not have matching parenthesis

7a Stack contents are

String rejected: unmatched characters

b Stack contents are

String rejected: unmatched characters

7c Stack contents are

x

x

yx

yx

y

Page 63: Excersize DataStructure

63

String rejected: stack empty with input still to be scanned

d Stack contents are

String recognized

e Stack contents are

String rejected: stack not empty but all input scanned

8a IsInL(S)// Determines if the string S is in the language L.// Returns true if the number of A's match the number of B's

S.CreateStack()I = 0Size = length of SItem = S[0] // determine which item is first in string

while (I < Size){ if(S[I] == Item) // if match, put in stack S.Push(Item) else // else, remove item from stack S.Pop()}

// if the numbers match, the stack should be emptyreturn S.StackIsEmpty()

8b IsInL(S)// Determines if the string S is in the language L.// Returns true if S consists of a number of A's followed by the// same number of B's.

S.CreateStack()I = 0Size = length of S

// while there are A's in the string, push onto stackwhile(I < Size and S[I] == 'A') S.Push(S[I]) I++

// should only be B's in rest of stringwhile(I < Size and !S.StackIsEmpty and S[I] == 'B')

xxx x

xyx x

Page 64: Excersize DataStructure

64

S.Pop() I++

// if A's and B's match, stack should be emptyreturn boolean(S.StackIsEmpty() and I == Size)

9a For the following: A = 7; B = 3; C = 12; D = -5; E = 1.

ABC+-

Character read Action Stack----------------------------------------------------------------A push A 7B push B 7 3C push C 7 3 12+ op2 = top of stack (12) 7 3 12

pop 7 3op1 = top of stack (3) 7 3pop 7result = op1 + op2 (15) 7

push result 7 15- op2 = top of stack (15) 7 15

pop 7op1 = top of stack (7) 7popresult = op1 - op2 (-8)push result -8 // **DONE**

9b ABC-D*-

Character read Action Stack----------------------------------------------------------------A push A 7B push B 7 3C push C 7 3 12- op2 = top of stack (12) 7 3 12

pop 7 3op1 = top of stack (3) 7 3pop 7result = op1 - op2 (-9) 7

push result 7 -9D push D 7 -9 -5* op2 = top of stack (-5) 7 -9 -5

pop 7 -9op1 = top of stack (-9) 7 -9pop 7result = op1 * op2 (45) 7push result 7 45

- op2 = top of stack (45) 7 45pop 7op1 = top of stack (7) 7popresult = op1 - op2 (-38)push result -38 // **DONE**

9c AB+C-DE*+

Character read Action Stack----------------------------------------------------------------

Page 65: Excersize DataStructure

65

A push A 7B push B 7 3+ op2 = top of stack (3) 7 3

pop 7op1 = top of stack (7) 7popresult = op1 + op2 (10)push result 10

C push C 10 12- op2 = top of stack (12) 10 12

pop 10op1 = top of stack (10) 10popresult = op1 - op2 (-2)

push result -2D push D -2 -5E push E -2 -5 1* op2 = top of stack (1) -2 -5 1

pop -2 -5op1 = top of stack (-5) -2 -5pop -2result = op1 * op2 (-5) -2push result -2 -5

+ op2 = top of stack (-5) -2 -5pop -2op1 = top of stack (-2) -2popresult = op1 + op2 (-7)push result -7 // **DONE**

10 a A–B+C ==> AB–C+ b A/( B* C) ==> ABC*/

Stack Output Stack Outputempty A empty A- A / A- AB / ( A+ AB- / ( AB+ AB-C / ( * ABempty AB-C+ / ( * ABC

/ ABC*empty ABC*/

c ( A+B)* C ==> AB+C* d A–( B+C) ==> ABC+–

Stack Output Stack Output( nothing empty A( A - A( + A - ( A( + AB - ( AB( AB+ - ( / AB* AB+ - ( / ABC* AB+C - ( * ABC/empty AB+C* - ( * ABC/D

- ABC/D*empty ABC/D*-

Page 66: Excersize DataStructure

66

e A–(B/C*D) ==> ABC/D*- f A/B/C–(D+E)*F ==> AB/C/DE +F *–

Stack Output Stack Outputempty A empty A- A / A- ( A / AB- ( AB / AB/- ( / AB / AB/C- ( / ABC - AB/C/- ( ABC/ - ( AB/C/- ( * ABC/ - ( + AB/C/D- ( * ABC/D - ( + AB/C/D- ABC/D* - ( + AB/C/DEempty ABC/D*- - AB/C/DE+

- * AB/C/DE+- * AB/C/DE+F

g A*(B/C/D)+E ==> ABC/D/* E+ h A-( B+C*D)/ E ==> ABCD*+ E/–

Stack Output Stack Outputempty A empty A* A - A* ( A - ( A* ( AB - ( AB* ( / AB - ( + AB* ( / ABC - ( + ABC* ( ABC/ - ( + * ABC* ( / ABC/ - ( + * ABCD* ( / ABC/D - ( + ABCD** ABC/D/ - ABCD*++ ABC/D/* - / ABCD*++ ABC/D/*E - / ABCD*+Eempty ABC/D/*E+ - ABCD*+E/

empty ABCD*+E/-empty AB/C/DE+F*-

11a Fly from A to F:

Action Reason Stack------------------------------------------------------Push A Initialize APush B Next adjacent city A BPush D Next adjacent city A B DPush E Next adjacent city A B D EPush I Next adjacent city A B D E IPush C Next adjacent city A B D E I CPop C No unvisited neighbor A B D E IPop I No unvisited neighbor A B D EPop E No unvisited neighbor A B DPush F Next adjacent city A B D F **DONE**

Page 67: Excersize DataStructure

67

b Fly from D to A:

Action Reason Stack------------------------------------------------------Push D Initialize DPush E Next adjacent city D EPush I Next adjacent city D E IPush C Next adjacent city D E I CPop C No unvisited neighbor D E IPop I No unvisited neighbor D EPop E No unvisited neighbor DPush F Next adjacent city D FPush G Next adjacent city D F GPop G No unvisited neighbor D FPop F No unvisited neighbor DPush H Next adjacent city D HPop H No unvisited neighbor DPop D No unvisited neighbor - **FAIL**

c Fly from A to G:

Action Reason Stack------------------------------------------------------Push A Initialize APush B Next adjacent city A BPush D Next adjacent city A B DPush E Next adjacent city A B D EPush I Next adjacent city A B D E IPush C Next adjacent city A B D E I CPop C No unvisited neighbor A B D E IPop I No unvisited neighbor A B D EPop E No unvisited neighbor A B DPush F Next adjacent city A B D FPush G Next adjacent city A B D F G **DONE**

d Fly from I to G:

Action Reason Stack------------------------------------------------------Push I Initialize IPush C Next adjacent city I CPush B Next adjacent city I C BPush D Next adjacent city I C B DPush E Next adjacent city I C B D EPop E No unvisited neighbor I C B DPush F Next adjacent city I C B D FPush G Next adjacent city I C B D F G **DONE**

e Fly from F to H:

Action Reason Stack------------------------------------------------------Push F Initialize FPush G Next adjacent city F GPush C Next adjacent city F G CPush B Next adjacent city F G C BPush D Next adjacent city F G C B DPush E Next adjacent city F G C B D EPush I Next adjacent city F G C B D E IPop I No unvisited neighbor F G C B D EPop E No unvisited neighbor F G C B DPush H Next adjacent city F G C B D H **DONE**

Page 68: Excersize DataStructure
Page 69: Excersize DataStructure

69

13 stackClass::~stackClass() // destructor{ stackNodePtr Cur = TopPtr;

while(Cur != NULL) { TopPtr = TopPtr->Next; delete Cur; Cur = TopPtr; }

Cur = TopPtr = NULL;} // end destructor

Page 70: Excersize DataStructure

70

Queues

1 The while loop needs only to compare the contents of the stack and the queue up the string, i.e.: half the contents of the stack and queue, since the back half stack has already been compared with the front half of the string as read from t

2 The following pseudocode performs the string recognition:

queueClass Q;stackClass S;boolean Qsuccess, SSuccess;int Index = 1;

if (the length of InputString == 0) reject the string // empty string not in L

while (InputString[Index] != '$') // save the first half of the string{ Q.QueueAdd(InputString[Index], QSuccess) increment Index}

// Index points to '$' or its value is greater than length of InputStringwhile (Index < the length of InputString)// save the second half of the string{ ++Index S.Push(InputString[Index], SSuccess)}

do// match the first half of the string with the second half of the string{ if ((Q.QueueIsEmpty() && !S.StackIsEmpty()) || (!Q.QueueIsEmpty() && S.StackIsEmpty())) reject the string

Q.GetQueueFront(QItem, QSuccess); S.GetStackTop(SItem, SSuccess); if (QItem != SItem) reject the string if (!Q.QueueIsEmpty()) Q.QueueRemove(QSuccess) if (!S.StackIsEmpty()) S.Pop(SSuccess)} while one of the structures is not empty

if (Q.QueueIsEmpty() && S.StackIsEmpty()) string is in Lelse reject the string

7

Page 71: Excersize DataStructure

71

3 queueClass PE // queue will hold the Postfix ExpressionstackClass S

for each character Ch in the infix expression switch (Ch) { case operand: Add to queue PE; break; case '(': Push to stack S; break; case ')': { // pop down to the matching open parenthesis while (the Top of stack S != '(') { Add the top of stack S to the queue PE Pop the top item off of stack S } // end while

Pop the top item off of stack S to remove open parenthesis } break; case operator: { while ( (stack S is not empty) && (the Top of stack S != '(') && (Precedence (StackTop()) >= Precedence (Ch))) { Add the top of stack S to the queue PE Pop the top item off of stack S } // end while

Push Ch on to the stack S } break; } // end switch

// add to PE the operators remaining on the stackwhile the stack S is not empty{ Add the top of stack S to the queue PE Pop the top item off of stack S} // end while

4 queueClass::queueClass(const queueClass& Q){ if (!Q.QueueIsEmpty()) { // copy first node ptrType OrigCur = Q.BackPtr->Next; // pt to first node ptrType NewHead = new queueNode;

NewHead->Item = OrigCur->Item; NewHead->Next = NewHead;

// copy rest of list ptrType NewCur = NewHead;

while (OrigCur != Q.BackPtr) { OrigCur = OrigCur->Next; NewCur->Next = new queueNode; NewCur = NewCur->Next; NewCur->Item = OrigCur->Item; NewCur->Next = NewHead; BackPtr = NewCur; } // end while } // end if} // end copy constructor

Page 72: Excersize DataStructure

72

5 queueClass::~queueClass() // destructor{ if(BackPtr != NULL) { ptrType Cur = BackPtr->Next; // start with front end of queue

BackPtr->Next = NULL; // reset last pointer to NULL

while(Cur != BackPtr) { ptrType Temp = Cur->Next; delete Cur; Cur = Temp; Temp = NULL; } // end while

delete Cur; // delete last node Cur = BackPtr = NULL; } // end if} // end destructor

6a It is important to note that the use of an ADT list with an array-based implem enot the same as the use of an array in the ADT queue. The QueueInsert operation operation which adds a new item to the end of the array. Since this is an O(1optimal and comparable to that of the ADT queue which directly manipulates a daQueueDelete operation, however, a ListDelete operation is called which removes the beginning of the array, forcing each remaining element of the array to be copie dtakes N-1 steps or O(N) time in comparison with the O(1) time required when th emanipulated.

6b Again, the use of an ADT list with a pointer-based implementation is different of a linked list. In this case, the QueueDelete operation which calls, in turn, takes O(1) time since it simply resets the head of the list to the next node d onode. The QueueInsert operation, on the other hand, calls a ListInsert operation the entire list before it finds the last node at which point the new node can btime compared with the O(1) time for inserting into the circular linked list.

7a The implementation of Display below uses a temporary queue to store the contents as they are removed and displayed. Then, the contents of the temporary queue a rinto the original. This "inefficient" procedure is necessary since there is no by the ADT queue that would inform a looping construct when to stop removing a nand reinserting it in the same queue. Another possible solution, that of savin gitem for comparison and terminating a loop on finding the same item, is not faiequal value can be in the same queue.

queueClass::Display(boolean& Success){ queueItemType Item; queueClass Temp;

// get contents of original queue and display them while(!QueueIsEmpty()) { QueueDelete(Item, Success); if(Success) { cout << Item << " "; // output items on single line Temp.QueueInsert(Item, Success); } } // end while

// reconstruct original queue

Page 73: Excersize DataStructure

73

while(!Temp.QueueIsEmpty()) { Temp.QueueDelete(Item, Success); if(Success) QueueInsert(Item, Success); } // end while

cout << endl; // terminate output with an end of line} // end Display

7b queueClass::Display(boolean& Success){ if(BackPtr != NULL) // if there is a queue... { ptrType Cur = BackPtr->Next; // start at the front of the queue

while(Cur!= BackPtr) { cout << Cur->Item << " "; // display items separated by spaces Cur = Cur->Next; } // end while

cout << Cur->Item << endl; // terminate output with last element } // end if} // end Display

8 ReadAndCorrect(String)// Reads a string of characters and, if a backspace (i.e. "<-") is found,// the character before the backspace as well as the backspace is removed// from the string.

Q.CreateDeque()Length = length of String

for(Index = 0 through Length){ if(String[Index] != '<') // if this is not the backspace character Q.DequeAddRear(String[I]) else if(Index > 0 and String[Index] == '<') { Q.DequeRemoveRear() // remove previous character from deque Index++ // increment Index past rest of backspace } else ignore backspace character}

Index = 0

// now reset the string from the dequewhile(!Q.DequeIsEmpty){ Q.GetDequeFront(Item) Q.DequeRemoveFront() String[Index] = Item Index++}

String[Index] = NULL // terminate the string

Page 74: Excersize DataStructure

74

9 E: A|5|9 Simulation beginsQ:

E: A|7|5 D|14 Processing arrival at time 5Q: 5|9

E: A|14|5 D|14 Processing arrival at time 7if there is a tie, arrivals are processed first

Q: 5|9 7|5

E: D|14 A|30|5 Processing arrival at time 14Q: 5|9 7|5 14|5

E: D|19 A|30|5 Processing departure at time 14Q: 7|5 14|5

E: D|24 A|30|5 Processing departure at time 19Q: 14|5

E: A|30|5 Processing departure at time 24Q: empty

E: A|32|5 D|35 Processing arrival at time 30Q: 30|5

E: A|34|5 D|35 Processing arrival at time 32Q: 30|5 32|5

E: D|35 Processing arrival at time 34Q: 30|5 32|5 34|5

E: D|40 Processing departure at time 35Q: 32|5 34|5

E: D|45 Processing departure at time 40Q: 34|5

E: empty Processing departure at time 45Q: empty

10 The event list cannot be an ADT queue since the ProcessArrival operation places event list before it reads the input file for the next arrival event and placestime may precede the departure time of an event already in the list, this arriv ainto place, overruling the insertion policy used by a queue.

The event list could be an ADT list although all of the functionality for sort ibe externally defined. The event list could also be an ADT sorted list except ordering of arrival vs. departure events for the same time may not be enforced bspecial precautions are taken (e.g.: introducing a "perturbation factor" of 0. 5departure event time for sorting purposes, remembering of course to remove this

Page 75: Excersize DataStructure

75

11 Starting at node P, we have

Action Reason Queue Contents(front to rear)

Add P initialize PAdd R next unvisited adjacent city PRAdd W next unvisited adjacent city PRWRemove P no unvisited adjacent city RWAdd X next unvisited adjacent city RWXRemove R no unvisited adjacent city WXAdd S next unvisited adjacent city WXSAdd Y next unvisited adjacent city WXSYRemove W no unvisited adjacent city XSYRemove X no unvisited adjacent city SYAdd T next unvisited adjacent city SYTRemove S no unvisited adjacent city YTAdd Z next unvisited adjacent city YTZRemove Y no unvisited adjacent city TZRemove T no unvisited adjacent city ZRemove Z no unvisited adjacent city empty

12a To simplify notation, QueueFront is treated as a valued function that returns th ethe argument Success is omitted.

Base cases:(Q.CreateQueue()).QueueFront() = error((Q.CreateQueue()).QueueInsert(Item)).QueueFront() = Item

Recursive step:if (Q.QueueIsEmpty() == FALSE) then (Q.QueueInsert(Item)).QueueFront() = Q.QueueFront()

The QueueIsEmpty test is needed to prevent the recursive axiom from being applie done item. Without it, QueueFront could be shown to be equal to error for any que uStackTop returns the last item that was added to a stack, i.e., the "outermost" representation. QueueFront returns the first item that was added to a queue, i.eInsert of the representation. Thus, QueueFront must be defined to "skip over" ap pfinds the first (innermost) one.

12b Any queue can be represented with only Insert operations, shown by these axioms

(Q.CreateQueue()).QueueRemove() = error

((Q.CreateQueue()).QueueInsert(Item)).QueueRemove() = Q.CreateQueue()

if (Q.QueueIsEmpty() == FALSE)then (Q.QueueInsert(Item)).QueueRemove() = (Q.QueueRemove()).QueueInsert(Item)

Page 76: Excersize DataStructure

76

Class Relationships

1a Each DisplayStatistics () function invokes the Area () function in its own class. Th eballClass DisplayStatistics () function can invoke the inherited sphereClass Area ()function by writing sphereClass::Area ().

1 b SPtr->DisplayStatistics() ; ==> calls the sphereClass versionSPtr = &Ball;

SPtr->DisplayStatistics(); ==> still calls the sphereClass versionBPtr->DisplayStatistics(); ==> calls the ballClass version

SPtr is defined as a pointer to sphereClass ; since Ball is of type ballClass which sphereClass , and DisplayStatistics was not declared as a virtual member function in SPtr accesses the functionality inherited from sphereClass rather than the redefin eballClass .

2 The completed penClass which has-a member ballClass .

// File: pen.h// This file contains the interface for an object of type penClass.

#include <iostream.h>#include "ball.h"

const float INK_CAPACITY = 10.0;enum colorType {BLACK, RED, BLUE, GREEN};

class penClass{public: // constructors penClass(); penClass(colorType NewColor, float NewInkAmount); penClass(const penClass& P); virtual ~penClass();

// pen operations boolean ClickPen(); boolean IsClickedOn(); boolean IsEmpty(); void Write(int LineLength, boolean& Success); void FillPen(colorType NewColor, float NewInkAmount, boolean&

Success); void ReplaceInk(colorType NewColor, float NewInkAmount); colorType GetColor(); float GetInkAmount();

private: ballClass Ball; colorType Color; boolean ClickedOn; float InkAmount; float ComputeInkPerLineLength(int LineLength);}; // end class

8

Page 77: Excersize DataStructure

77

// Implementation of pen.cpp

const int BALL_RADIUS = 3;

penClass::penClass(){ Ball(BALL_RADIUS, ""); // call constructor for member class Color = BLACK; ClickedOn = false; InkAmount = INK_CAPACITY;} // end constructor

penClass::penClass(colorType NewColor, float NewInkAmount){ Ball(BALL_RADIUS, ""); // call constructor for member class Color = NewColor; ClickedOn = false; InkAmount = NewInkAmount;} // end constructor

penClass::penClass(const penClass& P){ Ball(P.Ball); // call copy constructor for member class Color = P.Color; ClickedOn = P.ClickedOn; InkAmount = P.InkAmount;} // end copy constructor

boolean penClass::ClickPen(){ ClickedOn = !ClickedOn;

return ClickedOn;} // end ClickPen

boolean penClass::IsClickedOn(){ return ClickedOn;} // end IsClickedOn

boolean penClass::IsEmpty(){ return (InkAmount <= 0.0);} // end IsEmpty

void penClass::Write(int LineLength, boolean& Success){ float Amount = InkAmount - ComputeInkPerLineLength(LineLength);

Success = (Amount >= 0.0);

if(Success) InkAmount = Amount;} // end Write

void penClass::FillPen(colorType NewColor, float NewInkAmount, boolean& Success){ // prevent ink from mixing in pen Success = ((NewColor == Color) || (NewColor != Color && IsEmpty()));

Page 78: Excersize DataStructure
Page 79: Excersize DataStructure

79

Implementation of the modified sphere class member functions is as follows:

sphereClass::sphereClass(double R): equidistantClass(R){} // end constructor

sphereClass::sphereClass(): equidistantClass(1.0){} // end default constructor

sphereClass::sphereClass(const sphereClass& S): equidistantClass(S.Radius()){} // end copy constructor

sphereClass::~sphereClass(){} // end destructor

double sphereClass::Diameter(){ return 2.0 * Radius();} // end Diameter

double sphereClass::Circumference(){ return PI * Diameter();} // end Circumference

double sphereClass::Area(){ return 4.0 * PI * Radius() * Radius();} // end Area

double sphereClass::Volume(){ double R = Radius();

return (4.0 * PI * R * R * R)/3.0;} // end Volume

void sphereClass::DisplayStatistics(){ cout << "\nRadius = " << Radius() << "\nDiameter = " << Diameter() << "\nCircumference = " << Circumference() << "\nArea = " << Area() << "\nVolume = " << Volume() << endl;} // end DisplayStatistics

Page 80: Excersize DataStructure

80

3b A circle class is similar to the sphere class without a volume member.

#include <iostream.h>#include "equidist.h"

const double PI = 3.14159;

class circleClass: public equidistantClass{public: circleClass(double R); circleClass(); circleClass(const circleClass& S); virtual ~circleClass();

virtual double Diameter(); virtual double Circumference(); virtual double Area(); virtual void DisplayStatistics();}; // end class

Implementation of the circle class member functions is as follows:

circleClass::circleClass(double R): equidistantClass(R){} // end constructor

circleClass::circleClass(): equidistantClass(1.0){} // end default constructor

circleClass::circleClass(const circleClass& S): equidistantClass(S.Radius()){} // end copy constructor

circleClass::~circleClass(){} // end destructor

double circleClass::Diameter(){ return 2.0 * Radius();} // end Diameter

double circleClass::Circumference(){ return PI * Diameter();} // end Circumference

double circleClass::Area(){ return PI * Radius() * Radius();} // end Area

void circleClass::DisplayStatistics(){ cout << "\nRadius = " << Radius() << "\nDiameter = " << Diameter() << "\nCircumference = " << Circumference() << "\nArea = " << Area() << endl;} // end DisplayStatistics

Page 81: Excersize DataStructure

81

3c When the data member TheRadius is made a protected variable, then any derived cl asphereClass will have access to this data member. Thus it is possible for all o fequidistantClass to be redeclared as pure virtual functions, i.e., none of the fu nimplemented.

class equidistantClass // abstract base class{public: virtual void SetRadius(double NewRadius) = 0; virtual double Radius() const = 0; virtual void DisplayStatistics() const = 0;protected: double TheRadius;}; // end class

3d The following is a revised version of sphereClass where the data member TheRadi umember of the abstract base class equidistantClass.

#include <iostream.h>#include "equidist.h"

const double PI = 3.14159;

class sphereClass: public equidistantClass{public: sphereClass(double R); sphereClass(); sphereClass(const sphereClass& S); virtual ~sphereClass();

virtual double Diameter(); virtual double Circumference(); virtual double Area(); virtual double Volume(); virtual void DisplayStatistics();}; // end class

Implementation of the modified sphere class member functions is as follows:

sphereClass::sphereClass(double R){ TheRadius = R;} // end constructor

sphereClass::sphereClass(){ TheRadius = 1.0;} // end default constructor

sphereClass::sphereClass(const sphereClass& S){ TheRadius = S.TheRadius;} // end copy constructor

sphereClass::~sphereClass(){} // end destructor

double sphereClass::Diameter(){ return 2.0 * TheRadius;} // end Diameter

double sphereClass::Circumference()

Page 82: Excersize DataStructure

82

{ return PI * Diameter();} // end Circumference

double sphereClass::Area(){ return 4.0 * PI * TheRadius * TheRadius;} // end Area

double sphereClass::Volume(){ double R = TheRadius;

return (4.0 * PI * R * R * R)/3.0;} // end Volume

void sphereClass::DisplayStatistics(){ cout << "\nRadius = " << TheRadius << "\nDiameter = " << Diameter() << "\nCircumference = " << Circumference() << "\nArea = " << Area() << "\nVolume = " << Volume() << endl;} // end DisplayStatistics

The following is a revised version of circleClass where the data member TheRadi uof the abstract base class equidistantClass.

#include <iostream.h>#include "equidist.h"

const double PI = 3.14159;

class circleClass: public equidistantClass{public: circleClass(double R); circleClass(); circleClass(const circleClass& S); virtual ~circleClass();

virtual double Diameter(); virtual double Circumference(); virtual double Area(); virtual void DisplayStatistics();}; // end class

Implementation of the circle class member functions is as follows:

circleClass::circleClass(double R){ TheRadius = R;} // end constructor

circleClass::circleClass(){ TheRadius = 1.0;} // end default constructor

circleClass::circleClass(const circleClass& S)

Page 83: Excersize DataStructure

83

{ TheRadius = S.TheRadius;} // end copy constructor

circleClass::~circleClass(){} // end destructor

double circleClass::Diameter(){ return 2.0 * TheRadius;} // end Diameter

double circleClass::Circumference(){ return PI * Diameter();} // end Circumference

double circleClass::Area(){ return PI * TheRadius * TheRadius;} // end Area

void circleClass::DisplayStatistics(){ cout << "\nRadius = " << TheRadius << "\nDiameter = " << Diameter() << "\nCircumference = " << Circumference() << "\nArea = " << Area() << endl;} // end DisplayStatistics

4 a IsBlank should be protected. Its primary use is as a utility operation used algExprClass . At the same time, it is unnecessary for a client using an instance access to the IsBlank method.

b The client declaring InfixExpr cannot invoke EndExpression () since it is a prot eand is inaccessible to the client.

c Add the keyword virtual before the prototype for IsExpression () in the algExprC l

5 Assume the following objects have been declared in a main function:

stringClass S;algExprClass AE;infixClass InE;

a Length () is a public member function declared within stringClass that, althoug hredefined in any of the descendents of stringClass . Thus, all three objects may correctly.

b AE calls the function declared within the algExprClass definition correctly. I

declared within the infixClass definition correctly.

c Only InE can invoke the member function ValueOf ().

d// function declaration

Page 84: Excersize DataStructure

84

void F(algExprClass& E); . . .void main(){ infixClass InE; // declare object of derived type . . F(InE); // legal call}

6a The only methods that change are ListInsert , ListDelete , and ListRetrieve .

#include <iostream.h>#include "boolean.h"

typedef int listItemType; // type of list item

class baseFrontListClass // abstract base class{public: virtual ~baseFrontListClass(); // destructor virtual int ListLength() = 0; virtual boolean ListIsEmpty() = 0; virtual void DisplayList() = 0;}; // end class

struct listNode;typedef listNode* ptrType;

class frontListClass : public baseFrontListClass{public: // constructors and destructor: frontListClass(); frontListClass(const frontListClass& L); virtual ~frontListClass();

virtual int ListLength() const; virtual boolean ListIsEmpty() const; virtual void ListInsert(listItemType NewItem, boolean& Success); virtual void ListDelete(boolean& Success); virtual void ListRetrieve(listItemType& DataItem, boolean& Success); virtual void DisplayList() const; virtual void operator=(const frontListClass& L);

protected: void SetSize(int NewSize); // sets Size ptrType ListHead() const; // returns Head void SetHead(ptrType NewHead); // sets Head listItemType ListItem(ptrType P) const; // returns a list item ptrType ListNext(ptrType P) const; // returns list node's Next ptr

private: ptrType PtrTo(int Position) const;

int Size; // number of items on the list ptrType Head; // pointer to the linked list}; // end class

Implementation of the front list class member functions are as follows:

Page 85: Excersize DataStructure

85

struct listNode{ listItemType Item; ptrType Next;}; // end struct

baseFrontListClass::~baseFrontListClass() {} // end destructor

frontListClass::frontListClass(): Size(0), Head(NULL) {}// end constructor

frontListClass::frontListClass(const frontListClass& L): Size(L.Size){ if (L.Head == NULL) Head = NULL;

// original list is empty else { // copy first node Head = new listNode; Head->Item = L.Head->Item;

// copy rest of list ptrType NewPrev = Head;

// new list pointer for (ptrType OrigCur = L.Head->Next; OrigCur != NULL;

OrigCur = OrigCur->Next) { NewPrev->Next = new listNode; NewPrev = NewPrev->Next; NewPrev->Item = OrigCur->Item; } // end for

NewPrev->Next = NULL; } // end if} // end copy constructor

frontListClass::~frontListClass(){ boolean Success;

for ( int Position = 1; Position <= ListLength(); ++Position) ListDelete(1, Success);} // end destructor

boolean frontListClass::ListIsEmpty() const{ return boolean(Size == 0);} // end ListIsEmpty

int frontListClass::ListLength() const{ return Size;} // end ListLength

void frontListClass::ListInsert(listItemType NewItem, boolean& Success){ ++Size;

// create new node and place NewItem in it ptrType NewPtr = new listNode; NewPtr->Item = NewItem;

// insert new node at beginning of list NewPtr->Next = Head; Head = NewPtr; Success = true;

Page 86: Excersize DataStructure

86

} // end ListInsert

void frontListClass::ListDelete(int Position, boolean& Success){ ptrType Cur;

--Size;

// delete the first node from the list and return it to the system Cur = Head; if(Head != NULL) Head = Head->Next; Cur->Next = NULL; delete Cur; Cur = NULL; Success = true;} // end ListDelete

void frontListClass::ListRetrieve(listItemType& DataItem, boolean& Success){ DataItem = Head->Item; // get data in front node Success = true;} // end ListRetrieve

void frontListClass::DisplayList() const{ for (ptrType Cur = Head; Cur != NULL; Cur = Cur->Next) cout << Cur->Item << " ";

cout << endl;} // end DisplayList

void frontListClass::SetSize(int NewSize){ Size = NewSize;} // end SetSize

ptrType frontListClass::ListHead() const{ return Head;} // end ListHead

void frontListClass::SetHead(ptrType NewHead){ Head = NewHead;} // end SetHead

listItemType frontListClass::ListItem(ptrType P) const{ return P->Item;} // end ListItem

ptrType frontListClass::ListNext(ptrType P) const{ return P->Next;} // end ListNext

Page 87: Excersize DataStructure

87

ptrType frontListClass::PtrTo(int Position) const// Locates a specified node on a list.// Precondition: Position is the number of the desired node.// Postcondition: Returns a pointer to the node at position Position. If// Position < 1 or Position > the number of nodes on the list, returns NULL.{ if ( (Position < 1) || (Position > ListLength()) ) return NULL; else // count from the beginning of the list { ptrType Trav = Head;

for (int Skip = 1; Skip < Position; ++Skip) Trav = Trav->Next; // above could be combined into one for

return Trav; } // end if} // end PtrTo

void frontListClass::operator=(const frontListClass& L){ Size = L.Size;

if (L.Head == NULL) Head = NULL; // original list is empty else { // copy first node Head = new listNode; Head->Item = L.Head->Item;

// copy rest of list ptrType NewPrev = Head;

// new list pointer for (ptrType OrigCur = L.Head->Next; OrigCur != NULL;

OrigCur = OrigCur->Next) { NewPrev->Next = new listNode; NewPrev = NewPrev->Next; NewPrev->Item = OrigCur->Item; } // end for

NewPrev->Next = NULL; } // end if} // end operator=

6b // *************************************************************// Header file StackFL.h for the ADT stack.// Derived from ADT frontList// *************************************************************#include "frontList.h"

typedef listItemType stackItemType;

Page 88: Excersize DataStructure

88

class stackClass: public frontListClass{public:// constructors and destructor: stackClass(); // default constructor stackClass(const stackClass& S); // copy constructor ~stackClass(); // destructor

// stack operations: boolean StackIsEmpty() const; void Push(stackItemType NewItem, boolean& Success); void Pop(boolean& Success); void Pop(stackItemType& StackTop, boolean& Success); void GetStackTop(stackItemType& StackTop, boolean& Success) const;

private:// no private members -- stackClass inherits what it// needs from frontListClass

}; // end class

// end header file

// *************************************************************// Implementation file StackFL.cpp for the ADT stack.// Derives from the ADT frontList.// *************************************************************#include "StackFL.h" // header file

stackClass::stackClass(){} // end default constructor

stackClass::stackClass(const stackClass& S): frontListClass(S){} // end copy constructor

stackClass::~stackClass(){} // end destructor

boolean stackClass::StackIsEmpty() const{ return ListIsEmpty();} // end StackIsEmpty

void stackClass::Push(stackItemType NewItem, boolean& Success){ ListInsert(NewItem, Success);} // end Push

void stackClass::Pop(boolean& Success){ ListDelete(Success);} // end Pop

Page 89: Excersize DataStructure

89

void stackClass::Pop(stackItemType& StackTop, boolean& Success){ ListRetrieve(StackTop, Success); if(Success) ListDelete(Success);} // end Pop

void stackClass::GetStackTop(stackItemType& StackTop, boolean& Success) const{ ListRetrieve(StackTop, Success);} // end GetStackTop

// end of implementation file

7 The person class has basic information like name, age, gender.

class personClass{public: // constructors and destructor: personClass(); personClass(const personClass& P); virtual ~personClass();

virtual stringType Name(); virtual void SetName(stringType N); virtual int Age() const; virtual void SetAge(int A); virtual char Gender() const; virtual void SetGender(char G); virtual void DisplayPerson();

private: stringType TheName; int TheAge; char TheGender;}; // end class

The student class has the basic person class information, but adds year of gra dlist of classes, etc.

class studentClass: public personClass{public: // constructors and destructor: studentClass(); studentClass(const studentClass& P); virtual ~studentClass();

virtual stringType StudentID() const; virtual void SetStudentID(stringType ID); virtual stringType Major() const; virtual void SetMajor(stringType M); virtual int YearOfGraduation() const; virtual void YearOfGraduation(int YOG); virtual void DisplayClasses(); virtual void AddClass(listType C); virtual void RemoveClass(listType C); virtual void UpdateClass(listType OldClass, listType NewClass); virtual float GradePointAverage() const;

private:

Page 90: Excersize DataStructure

90

stringType TheStudentID, TheMajor; int TheYearOfGraduation; listClass TheClassList;}; // end class

The graduate student class has the basic student class information, but adds an the thesis option.

enum thesisType {MASTERS_NON_THESIS, MASTERS_THESIS, DOCTORATE};

class gradStudentClass: public studentClass{public: // constructors and destructor gradStudentClass(); gradStudentClass(const gradStudentClass& G); virtual ~gradStudentClass();

virtual thesisType ThesisOption() const; virtual void SetThesisOption(thesisType T);

private: thesisType ThesisOption;}; // end class

8 The overloaded assignment operator for the stack template is as follows:

stackClass& stackClass::operator=(const stackClass<TYPE>& S);// overloaded assingment operator

template<class TYPE> stackClass<TYPE>& stackClass<TYPE>::operator=( conststackClass<TYPE>& S)

// overloaded assignment operator{ ptrType OrigCur; ptrType NewPrev;

if (S.TopPtr == NULL) TopPtr = NULL; else { // copy first node TopPtr = new stackNodeType; TopPtr->Item = S.TopPtr->Item;

// copy rest of list OrigCur = S.TopPtr->Next;

// point to next node on list NewPrev = TopPtr;

// new list pointer while (OrigCur != NULL) { NewPrev->Next = new (stackNodeType); NewPrev = NewPrev -> Next; NewPrev->Item = OrigCur->Item; OrigCur = OrigCur->Next; } // end while

NewPrev->Next = NULL; return (*this); } // end if} // end stackClass::operator=

Page 91: Excersize DataStructure

91

The overloaded assignment operator for the queue template is as follows:

queueClass& queueClass::operator=(const queueClass<TYPE>& S);// overloaded assingment operator

template<class TYPE> queueClass<TYPE>& queueClass<TYPE>::operator=( constqueueClass<TYPE>& Q)// overloaded assignment operator{ if (!Q.QueueIsEmpty()) { // copy first node ptrType OrigCur = Q.BackPtr->Next;

// pt to first node ptrType NewHead = new queueNode;

NewHead->Item = OrigCur->Item; NewHead->Next = NewHead;

// copy rest of list ptrType NewCur = NewHead;

while (OrigCur != Q.BackPtr) { OrigCur = OrigCur->Next;

NewCur->Next = new queueNode; NewCur = NewCur->Next; NewCur->Item = OrigCur->Item; NewCur->Next = NewHead; BackPtr = NewCur; } // end while } // end if

else BackPtr = NULL;

return (*this);} // end queueClass::operator=

Page 92: Excersize DataStructure

92

Algorithm Efficiency and Sorting

1 a O(N)b O(N)c O(N)d O(N)e O(1)f O(N) Worst case: the entire list must be traversed first.g O(log N)h O(N log N)i O(N) Worst case: the stack is implemented with an array.j O(N) Worst case: the queue is implemented with an ADT list.

2 The algorithm is O(N 2). Suppose the computation in the innermost for loop tak esome function f(x), where x is independent of N. Then, the innermost loop mus t10 * f(x) steps to compute. Since x is independent of N by hypothesis, the va lconstant c. The overall computation then requires c passes for each of the N p aloop and the middle loop requires N passes in turn for each of the N passes of the overall time complexity is c*N*N or O(N 2).

3 The outer loop makes N+1 comparisons. The first N of them precede another passthe for loop and the last one fails the test and forces the loop to stop.

For each of the N passes through the loop, J+1 comparisons are made by the tes tbeing the value of the index for the for loop, i.e.: J = [0, ... , N-1]. W icomparison is made by the if statement so 2*J + 1 total comparisons are made b y

Since J increases from 0 to N-1, the overall total of comparisons is:

[2*(0) + 1] + [2*(1) + 1] + ... + [2*(N-1) + 1] + 1

the last being the comparison that bumps us out of the outer for loop. Thus t h

( )2 1 10

1

ii

N

+ +=

∑ = + +=

∑2 10

1

i Ni

N

= − + +2 1 2 1N N N( )/

= − + +N N N( )1 1

= − + +N N N2 1 = O N( )2

4 Selection sort is moderately faster than Insertion sort. This is due to the c oterm in the count of comparisons and data moves each algorithm performs. As deselection sort takes N 2/2 + 5*N/2 - 3 steps for the worst case while insertion For large N, this confers a 2:1 advantage for selection sort.

5 Let c = c[n] + c[n-1] + ... + c[0]. Then, f(x) <= c*x n and is thus O(x n).

9

Page 93: Excersize DataStructure

93

6 Let a > 1 and b > 1. To show: f(N) is O (log a N) => f(N) is O(log b N).Define c = 1/(log b a). Then, f(N) is O(log a N) = c * O(log b N) = O(log b N).

The proof is symmetrical for f(N) is O(log b N) => f(N) is O(log a N).

7 Any operations outside of loops contribute a constant amount of time and would nbehavior of the selection sort for a large N.

8 Apply insertion sort to: 20 80 40 25 60 40

array action20 80 40 25 60 40 initial array20 80 40 25 60 40 copy 20 on top of itself20 80 80 25 60 40 copy 40 and shift 8020 40 80 25 60 40 insert 4020 40 40 80 60 40 copy 25 and shift 40, 8020 25 40 80 60 40 insert 2520 25 40 80 80 40 copy 60 and shift 8020 25 40 60 80 40 insert 6020 25 40 60 60 80 copy 40 and shift 60, 8020 25 40 40 60 80 insert 40; final array

9a Apply selection sort, bubble sort and insertion sort to sorted and inverse sor t

Inverse sorted array: 8 6 4 2

i selection sort

action arrayinitial array 8 6 4 2first swap 2 6 4 8second swap 2 4 6 8no swap 2 4 6 8

Page 94: Excersize DataStructure

94

ii. bubble sort

action arrayinitial array 8 6 4 2pass 1 6 8 4 2

6 4 8 26 4 2 8

pass 2 4 6 2 84 2 6 84 2 6 8

pass 3 2 4 6 82 4 6 82 4 6 8

iii. insertion sort

action arrayinitial array 8 6 4 2copy 6 and shift 8 8 8 4 2insert 6 6 8 4 2copy 4 and shift 6, 8 6 6 8 2insert 4 4 6 8 2copy 2 and shift 4, 6, 8 4 4 6 8insert 2 2 4 6 8

9b Sorted array: 2 4 6 8

i selection sort

action arrayinitial array 2 4 6 8no swap 2 4 6 8no swap 2 4 6 8no swap 2 4 6 8

ii. bubble sort

action arrayinitial array 2 4 6 8pass 1 2 4 6 8

2 4 6 82 4 6 8

ii i. insertion sort

action arrayinitial array 2 4 6 8copy 2 on itself 2 4 6 8copy 4 on itself 2 4 6 8copy 6 on itself 2 4 6 8

10 1000 5 10 20 30 40 50 60

Page 95: Excersize DataStructure

95

11 Revision of SelectionSort using the data member Key as a sort key:

const int MAX_NAME_LEN = 20;const int MAX_SIZE = 8;

typedef struct node dataType;struct node{ char Name[MAX_NAME_LEN]; int Age; float GPA; int Key; // sorting key};

int IndexOfLargest(dataType A, int Size){ int Max = 0; for (int Cur=1; Cur<Size; Cur++) { if(A[Cur].Key > A[Max].Key) Max = Cur; } // end for loop

return Max;} // end IndexOfLargest

void Swap(dataType& X, dataType& Y) // standard Swap function{ dataType Temp = X; X = Y; Y = Temp;} // end Swap

void SelectionSort(dataType InA[], int N){ int L;

for (int Last=N-1; Last>0; Last--) { L = IndexOfLargest(InA, Last); Swap(InA[L], InA[Last]); }} // end SelectionSort

Revision of IndexOfLargest where dataType is a class with member function SortK e

int IndexOfLargest(dataType A, int Size){ int Max = 0; for (int Cur=1; Cur<Size; Cur++) { if(A[Cur].SortKey() > A[Max].SortKey()) Max = Cur; } // end for loop

return Max;} // end IndexOfLargest

12 The following recursive version of SelectionSort uses the IndexOfLargest and Sw aprevious solution.

Page 96: Excersize DataStructure

96

void SelectionSort(dataType InA[], int Last){ int Current;

if (Last > 0) { Current = IndexOfLargest(InA, Last); Swap (InA[Current], InA[Last]); SelectionSort (InA, Last-1); }} // end SelectionSort

A recursive version of BubbleSort:

void Bubble(dataType A[], int N, int Index, boolean& Sorted)// helping function{ if(N > Index+1) { int NextIndex = Index + 1; if(A[Index] > A[NextIndex]) { Swap(A[Index], A[NextIndex]); Sorted = false; } Bubble(A, N, Index+1, Sorted); } // end if} // end Bubble

void BubbleSort(dataType A[], int N){ if(N > 1) { boolean Sorted = true; Bubble(A, N, 0, Sorted); if(!Sorted) BubbleSort(A, N-1); } // end if} // end BubbleSort

A recursive version of InsertionSort. Here the sorted region is at the endrather than at the beginning of the array.

void Shift(dataType A[], dataType NextItem, int& Loc){ if((Loc > 0) && (A[Loc-1] > NextItem)) { A[Loc] = A[Loc-1]; Loc--; Shift(A, NextItem, Loc); } // end if} // end Shift

void InsertionSort(dataType A[], int Unsorted, int N)// Preconditions: Unsorted = 1, N = size of A.// Postcondition: A is sorted in ascending order.{ if(Unsorted < N) { dataType NextItem = A[Unsorted]; int Loc = Unsorted;

Shift(A, NextItem, Loc); A[Loc] = NextItem; InsertionSort(A, Unsorted+1, N); } // end if} // end InsertionSort

13 Trace of mergesort on the array 20 80 40 25 60 30 :

20 80 40 25 60 30

Page 97: Excersize DataStructure

97

20 80 40 25 60 30RECURSIVE STEPS

20 80 40 25 60 30

20 80 40 25 60 30

20 80 40 25 60 30MERGE STEPS

20 40 80 25 30 60

20 25 30 40 60 80

14a The recursive calls to Mergesort simply subdivide the array A until it can be diwhen the size of the subdivided array is one element) at which point the simple ra larger array. Only the dimension of the array, the relative values of its fi rwhether another pair of recursive calls to Mergesort takes place. The values wi timpact on this mechanism.

14b The items in the array are only swapped during the call to Merge when the two s ofrom the previous two calls to Mergesort are merged together. More specifically ,first for loop of Merge where two index values, First1 and First2 , maintain the l oyet unmerged items in the first and second sub-arrays respectively. The lesser by these indices is merged into the new array, the selected index is incrementemade until one index or the other exceeds the length of the sub-array, whereupo nthe other sub-array are copied over.

15 Trace of quicksort on the array 20 80 40 25 60 10 15:

pivot|20 80 40 25 60 10 1520 15 40 25 60 10 8020 15 10 25 60 40 80

S1 S215 10 | 20 | 25 60 40 80

Item 20 is now in its correct position and quicksort is now applied recursivel y

16 All of the actual sorting is done in the merge steps; the array will not be so r

17 If the actual median of the elements is selected as the pivot at each step, th erecursive calls will be made to sort the original N elements. Approximating th e

Page 98: Excersize DataStructure

98

values can still lead to a worst case of N recursive calls.

18 We need only add a single comparison to guard the Swap statement.

20 An iterative version of Mergesort would work from the bottom up by dividing the aof sorted sections and merging the runs to form larger runs. In the first pass, size 1 (already sorted). The second pass would form sorted sections of size 2 b ysections of size 1. The third pass would form sorted sections of size 4 by merg2, and so on. An invariant: given N items to sort, there will be N / 2 k sorted pass.

21 Insertionsort and Mergesort can be implemented to be stable. Heapsort and Quicksort a

22 a Trace the radix sort for the following cards: S2, HT, D6, S4, C9, CJ, D

S2, HT, D6, S4, C9, CJ, DQ, ST, HQ, DK original cards(S2) (S4) (D6) (C9) (HT, ST) (CJ) (DQ, HQ) (DK) sorted by rankS2, S4, D6, C9, HT, ST, CJ, DQ, HQ, DK combined(S2, S4, ST) (HT, HQ) (C9, CJ) (D6, DQ, DK) sorted by suitS2, S4, ST, HT, HQ, C9, CJ, D6, DQ, DK combined (sorted)

b All 10’s would become sorted before all 2’s in rank because of the 0 in twould get sorted before or after all of the suits, depending on the precedence awith respect to S, H, C, and D.

Page 99: Excersize DataStructure

99

Trees

1 The following lists the operations for the ADT binary tree:

CreateBinaryTree()// Creates an empty binary tree.// Preconditions: none.// Postconditions: an empty binary tree is prepared to accept new// insertions.

CreateBinaryTree(RootItem)// Creates a one-node binary tree whose root contains RootItem.// Preconditions: RootItem is of a type recognizable by ADT binary tree// operations.// Postconditions: the tree contains a root node containing RootItem.

CreateBinaryTree(RootItem, LeftTree, RightTree)// Creates a binary tree whose root contains RootItem and has LeftTree// and RightTree, respectively, as its left and right subtrees.// Preconditions: RootItem is of a type recognizable by ADT binary tree// operations. LeftTree and RightTree are both ADT binary trees.// Postconditions: the tree whose root contains RootItem and whose left// child is LeftTree and whose right child is RightTree has been created.

DestroyBinaryTree()// Destroys a binary tree.// Preconditions: a binary tree has been created.// Postconditions: the binary tree has been destroyed.

BinaryTreeIsEmpty()// Determines whether a binary tree is empty.// Preconditions: a binary tree has been created.// Postconditions: returns true if the tree is empty, false otherwise.

RootData()// Returns the data item in the root of a nonempty binary tree.// Preconditions: a nonempty binary tree has been created.// Postconditions: the contents of the root node are returned.

SetRootData(NewItem)// Replaces the data item in the root of the binary tree with NewItem, if// the tree is not empty. However, if the tree is empty, creates a root// node whose data item is NewItem and inserts the new node into the// tree.// Preconditions: a binary tree has been created.// Postconditions: the root node of the binary tree contains NewItem.

AttachLeft(NewItem, Success)// Attaches a left child containing NewItem to the root of a binary tree.// Success indicates whether the operation was successful.// Preconditions: a nonempty binary tree has been created.// Postconditions: the left child of the root of the tree contains// NewItem and Success is true. Else, Success is false.

10

Page 100: Excersize DataStructure

100

AttachRight(NewItem, Success)// Attaches a right child containing NewItem to the root of a// binary tree. Success indicates whether the operation was successful.// Preconditions: a nonempty binary tree has been created.// Postconditions: the right child of the root of the tree contains// NewItem and Success is true. Else, Success is false.

AttachLeftSubtree(LeftTree, Success)// Attaches a copy of LeftTree as the left subtree of the root of a// binary tree. Success indicates whether the operation was successful.// Preconditions: a nonempty binary tree has been created and LeftTree// is an ADT binary tree.// Postconditions: LeftTree is the left child of the root and Success// is true. Else, Success is false.

AttachRightSubtree(RightTree, Success)// Attaches a copy of RightTree as the right subtree of the root of a// binary tree. Success indicates whether the operation was successful.// Preconditions: a nonempty binary tree has been created and RightTree// is an ADT binary tree.// Postconditions: RightTree is the right child of the root and Success// is true. Else, Success is false.

DetachLeftSubtree(LeftTree, Success)// Detaches the left subtree of a binary tree’s root and retains it in// LeftTree. Success indicates whether the operation was successful.// Preconditions: a nonempty binary tree has been created and LeftTree// is an ADT binary tree.// Postconditions: the left child of the root is removed and stored in// LeftTree and Success is true. Else, LeftTree is empty and Success is// false.

DetachRightSubtree(RightTree, Success)// Detaches the right subtree of a binary tree’s root and retains it in// RightTree. Success indicates whether the operation was successful.// Preconditions: a nonempty binary tree has been created and RightTree// is an ADT binary tree.// Postconditions: the right child of the root is removed and stored in// RightTree and Success is true. Else, RightTree is empty and Success // is false.

LeftSubtree()// Returns a copy of the left subtree of a binary tree’s root without// detaching the subtree.// Preconditions: a nonempty binary tree has been created.// Postconditions: a copy of the left subtree of the root has been// returned.

RightSubtree()// Returns a copy of the right subtree of a binary tree’s root without// detaching the subtree.// Preconditions: a nonempty binary tree has been created.// Postconditions: a copy of the right subtree of the root has been// returned.

PreorderTraverse(Visit)// Traverses a binary tree in preorder and calls the function Visit once// for each node.// Preconditions: a binary tree has been created. Visit is a function// which performs operations which are non-destructive to the structure// of the tree.// Postconditions: the tree has been traversed in preorder and the// function Visit has been performed on each node.InorderTraverse(Visit)// Traverses a binary tree in inorder and calls the function Visit once

Page 101: Excersize DataStructure

101

// for each node.// Preconditions: a binary tree has been created. Visit is a function// which performs operations which are non-destructive to the structure// of the tree.// Postconditions: the tree has been traversed in inorder and the// function Visit has been performed on each node.

PostorderTraverse(Visit)// Traverses a binary tree in postorder and calls the function Visit once// for each node.// Preconditions: a binary tree has been created. Visit is a function// which performs operations which are non-destructive to the structure// of the tree.// Postconditions: the tree has been traversed in postorder and the// function Visit has been performed on each node.

2preorder inorder postorder

a for Figure 10-42 MGDAHKLTRVUW ADHGKLMRUVTW AHDLKGUVRWTMb for Figure 10-6b ABDFGEC GFDBEAC GFDEBCAc for Figure 10-6c ABCDEFG ACEGFDB GFEDCBA

3 aThe node (6) must contain the inorder successor of the root because it is the lchild.

b 4, 2, 5, 8, 1, 6, 9, 3, 7.

4 W W A

T T B

N N W

J A J

E B E N

B E T

A J

a) insert order b) insert order c) insert orderW T N J E B A W T N A B E J A B W J N T E

Page 102: Excersize DataStructure

102

5

6 60

20 70

10 40 65 80

30 50 75

25 35 45a) insert order 80 65 75 45 35 25

60

25 70

10 40 65 80

30 45 75

35b) delete items 50 and 20

A

F

C

E

L

V

Z

F

C V

A E L Z

Maximum heightinsert orderACEFLVZ

Minimum heightinsert orderFCVAELZ

Page 103: Excersize DataStructure

7 Deleting an item from a leaf of a binary search tree and then inserting it back into the tree does notalter the shape of the tree. Deleting and inserting an item from a node with one or two children willalter the shape of a binary search tree. Referring to the tree from Exercise 5b, inserting the items 20and 50 back into the binary search tree results in the following tree structure, which is obviouslydifferent in shape.

60

25 70

10 40 65 80

20 30 45 75

35 50

reinserting items 50 and 20

8 The following tree is produced after all the statements are executed.

4

9 1

10 8 2 3

2 6 7

5 3

9a bool IsLeaf();// Returns true if the binary tree is a leaf node.

b bool binTreeClass::IsLeaf()// Returns true if the binary tree is a leaf node.{ // empty tree is not a leaf if(Root == NULL) return false;

if(Root->LChildPtr == NULL && Root->RChildPtr == NULL) return true;

// else... return false;} // end IsLeaf

c The client could implement a version of IsLeaf by performing the operations LeftS u

RightSubtree and testing both subtrees returned to see if they are empty.

Page 104: Excersize DataStructure

104

10a SearchTreeReplace(ReplacementItem, Success)// Locates, if possible, the item in a binary search tree with the same// search key as ReplacementItem. If found, the item is replaced with// ReplacementItem and Success is true. Else, Success is false.

if(search key of RootItem equals search key of ReplacementItem) RootItem = ReplacementItem

else if(search key of ReplacementItem < search key of RootItem and Root->LChildPtr != NULL) Root->LChildPtr->SearchTreeReplace(ReplacementItem, Success)

else if(Root->RChildPtr != NULL) Root->RChildPtr->SearchTreeReplace(ReplacementItem, Success)

else Success = false

b SearchTreeReplace(Root, ReplacementItem, Success)// Locates, if possible, the item in the binary search tree Root with the // samesearch key as ReplacementItem. If found, the item is replaced// with ReplacementItem and Success is true. Else, Success is false.

if(search key of RootData() equals search key of ReplacementItem) SetRootData(ReplacementItem)

else if(search key of ReplacementItem < search key of RootItem and Root.LeftSubtree() != NULL) SearchTreeReplace(Root.LeftSubtree(), ReplacementItem, Success)

else if(Root.RightSubtree() != NULL) SearchTreeReplace(Root.RightSubtree(), ReplacementItem, Success)

else Success = false

Since no insertions or deletions are performed by this algorithm, only resetti nnode, the shape of the binary tree will remain the same.

11 The tree should be traversed using a preorder traversal and the contents of the

60 20 10 40 30 50 70

12a Array-based implementation of tree in Figure 10-18a of the text.

Root contains address 1 and Free contains address 8.

address 1 2 3 4 5 6 7 8 9name Tom Jane Wendy Bob Nancy Alan EllenLChild 2 4 0 6 0 0 0RChi ld

3 5 0 7 0 0 0 9 0

Page 105: Excersize DataStructure

105

b Operations on the above implementation.

T.SearchTreeInsert (“Doug”, Success);Root contains address 1 and Free contains address 9.

address 1 2 3 4 5 6 7 8 9name Tom Jane Wendy Bob Nancy Alan Ellen DougLChild 2 4 0 6 0 0 0 0RChi ld

3 5 0 7 0 0 0 0 0

T.SearchTreeDelete (“Nancy”, Success);Root contains address 1 and Free contains address 5.

address 1 2 3 4 5 6 7 8 9name Tom Jane Wendy Bob Alan Ellen DougLChild 2 4 0 6 0 0 0RChi ld

3 0 0 7 9 0 0 0 0

T.SearchTreeDelete (“Bob”, Success);Root contains address 1 and Free contains address 6.

address 1 2 3 4 5 6 7 8 9name Tom Jane Wendy Alan Ellen DougLChild 2 4 0 0 0 0RChi ld

3 0 0 7 9 5 0 0 0

T.SearchTreeInsert (“Sarah”, Success);Root contains address 1 and Free contains address 5.

address 1 2 3 4 5 6 7 8 9name Tom Jane Wendy Alan Sarah Ellen DougLChild 2 4 0 0 0 0 0RChi ld

3 6 0 7 9 0 0 0 0

12c Array-based implementation of tree in Figure 10-18b of the text.

Root contains address 2 and Free contains address 8.

address 1 2 3 4 5 6 7 8 9name Tom Jane Wendy Bob Nancy Alan EllenLChild 0 4 0 6 0 0 0RChi ld

3 5 0 7 1 0 0 9 0

Operations on the above implementation.

T.SearchTreeInsert (“Doug”, Success);Root contains address 2 and Free contains address 9.

address 1 2 3 4 5 6 7 8 9name Tom Jane Wendy Bob Nancy Alan Ellen DougLChild 0 4 0 6 0 0 8 0RChi ld

3 5 0 7 1 0 0 0 0

Page 106: Excersize DataStructure

106

T.SearchTreeDelete (“Nancy”, Success);Root contains address 2 and Free contains address 5.

address 1 2 3 4 5 6 7 8 9name Tom Jane Wendy Bob Alan Ellen DougLChild 0 4 0 6 0 8 0RChi ld

3 1 0 7 9 0 0 0 0

Page 107: Excersize DataStructure
Page 108: Excersize DataStructure

108

15 void binTreeClass::InorderTraverse(functionType Visit)// Traverses the binary tree inorder and calls the function Visit once on// each node.// Iterative version.{ // Initialize stackClass S; ptrType Cur = Root; bool Done = false, Success = true;

while(!Done) { if(Cur != NULL) { // place pointer to node on stack before // traversing node’s left subtree S.Push(Cur, Success);

// traverse the left subtree Cur = Cur->LChildPtr; }

else // backtrack from the empty subtree and visit // the node at the top of the stack; however, // if the stack is empty, you are done { if(!S.StackIsEmpty()) { S.GetStackTop(Cur, Success); Visit(Cur->Item); S.Pop(Success);

// traverse the right subtree // of the node just visited Cur = Cur->RChildPtr; }

else Done = true; } // end else backtrack } // end while} // end InorderTraverse

Visit 5 0

NULL>50>40>20>60

>50>40>20>60

>40>20>60

>20>60 >60 Visit 6 0

>70>60

NULL>70>60

>70>60 Visit 7 0

NULL>70>60

>70>60 >60

Page 109: Excersize DataStructure

109

16 The following solutions use the functions Max and Min which return the maximum and minimumbetween two integers.

a Recursive computation of the number of nodes in the tree.

int NumNodes(binTreeClass T){ if(T.BinaryTreeIsEmpty()) return 0; else return 1 + NumNodes(T.LeftSubtree()) + NumNodes(T.RightSubtree());} // end NumNodes

b Recursive computation of the height of a binary tree:

int Height (binTreeClass T){ if (T.BinaryTreeIsEmpty()) return 0; else return Max(Height(T.LeftSubtree(),T.RightSubtree()))+1;} // end Height

c Recursive computation of the maximum element of a binary tree:

int MaxElement (binTreeClass T){ int Temp;

if (T.BinaryTreeIsEmpty()) return -maxint; else { Temp = MaxElement(T.LeftSubtree());

if (Temp > T.RootData()) return Max(Temp,MaxElement(T.RightSubtree())); else return Max(T.RootData(),MaxElement(T.RightSubtree())); } // end if} // end MaxElement

d Recursive computation of the sum of all elements of a binary tree:

int Sum (binTreeClass T){ if (T.BinaryTreeIsEmpty()) return 0; else return Sum(T.LeftSubtree()) + Sum(T.RightSubtree()) + T.RootData();} // end Sum

e Recursive computation of the average of all elements of a binary tree. (The Count routine is used to countthe number of nodes in the tree.)

int Count (binTreeClass T){ if (T.BinaryTreeIsEmpty()) return 0; else return Count(T.LeftSubtree()) + Count(T.RightSubtree()) + 1;} // end Count

float Average (binTreeClass T)

Page 110: Excersize DataStructure

110

{ int N;

N = Count (T); if (N == 0) return 0.0; else return Sum(T)/(float)N;} // end Average

f Recursive item search in a (unordered) binary tree, returns a tree rooted at the node where the item is found:

binTreeClass Find (binTreeClass T, int FindItem){ binTreeClass Temp;

if (T.BinaryTreeIsEmpty()) { Temp = T; return Temp; } else if (T.RootData() == FindItem) return T; else { Temp = Find (T.LeftSuntree, FindItem); if (Temp.BinaryTreeIsEmpty()) return (Find (T.RightSubtree, FindItem)); else return Temp; } // end if} // end Find

g Recursive ancestor relationship computation in a binary tree:

boolean Ancestor(binTreeClass T, int Item1, int Item2){ binTreeClass Temp1, Temp2;

if (T.BinaryTreeIsEmpty()) return false; else if (T.RootData == Item1) { Temp1 = Find(T.LeftSubtree(), Item2); Temp2 = Find(T.RightSubtree(), Item2); return(Temp1.BinaryTreeIsEmpty() || Temp2.BinaryTreeIsEmpty()); } else return (Ancestor(T.LeftSubtree(), Item1, Item2) || Ancestor (T.RightSubtree(), Item1, Item2));} // end Ancestor

h Recursive computation of highest full level in a binary tree:

int FullLevel (binTreeClass T){ if (T.BinaryTreeIsEmpty()) return 0; else

return Min(FullLevel(T.LeftSubtree()), FullLevel(T.RightSubtree()))+1;} // end FullLevel

17a The value of the whole tree is 23.

Page 111: Excersize DataStructure

111

b int Minimax(binTreeClass T){ if(T.BinaryTreeIsEmpty()) return 0;

if(T.IsLeaf()) return T.RootData();

if(T.RootIsMaxNode()) return Max(Minimax(T.LeftSubtree()), Minimax(T.RightSubtree())); else // root is min node return Min(Minimax(T.LeftSubtree()), Minimax(T.RightSubtree()));} // end Minimax

18 There is no binary search tree (BST) that gives a preorder traversal of 2 3 1. A preorder traversaluniquely specifies a BST.

19 There is a 1-1 mapping between BSTs and binary trees. Let T(N) denote the number of trees with Nnodes; then we have

T( )0 0=

T N T i T N ii

N

( ) ( () ( ) )= × − −=

∑ 10

1

20 Visit all items in a binary search tree that have a key value in the range Low ... High :

void RangeQuery(bstClass T, keyType Low, keyType High, functionType Visit){ if (!T.BinaryTreeIsEmpty()) { if (Low < T.RootData) RangeQuery (T.LeftSubtree(), Low, High, Visit); else if ((Low <= T.RootData) and (T.RootData <= High)) Visit (T.RootData); else if (High > T.RootData) RangeQuery (T.RightSubtree, Low, High, Visit) }} // end RangeQuery

21 The proofs of Theorem 10-1 in Chapter 10 and Theorems 10-2 and 10-3 given here use Axiom D-2, asstated in Appendix D, but with a slight change in notation.

The inductive step of Axiom D-2 is

If P(0), P(1), . . . , P(k) are true for any k ≥0, then P( k + 1) is true.

However, you can also write this step as

Page 112: Excersize DataStructure

112

If P(0), P(1), . . . , P(k –1) are true for any k ≥0, then P(k) is true

or as

If P(0), P(1), . . . , P(h –1) are true for any h ≥ 0, then P( h) is true.

The previous form is equivalent to

If P( k) is true for all k such the 0 ≤ k < h, then P( h) is true.

The proof of Theorem 10-2 uses this last form of the inductive step.

THEOREM 10-2. A full binary tree of height h (h ≥ 0) has 2 h –1 nodes.

PROOF: The proof is by induction on h.

Basis. When h = 0, the full binary tree is empty, and it contains 0 = 2 0 –1 nodes.

Inductive hypothesis. Assume that the theorem is true for all k, 0 ≤ k < h. That is, assume for all k, 0≤ k < h, that a full binary tree of height k has 2k-1nodes.

Inductive conclusion. You must show that the theorem is true for h (h > k ≥ 0). That is, you mustshow that a full binary tree of height h has 2h-1nodes.

If T is a full binary tree of height h > 0, then, from definition of a full tree, its form is:r

TL TR

where TL and TR are full binary trees of height h – 1. The number of nodes in T is thus

1 (for the root) + (number of nodes in TL) + (number of nodes in TR)

By the inductive hypothesis, TL and TR each have 2h-1– 1 nodes because each is a full binary tree of height h–1. Thus, the number of nodes in T is

1 + (2h-1–1) + (2h-1– 1) = 1 + 2 * (2h-1–1) = 2h-1

which is what you needed to show. (End of proof.)

THEOREM 10-3. The maximum number of nodes that a binary tree of height h can have is 2h-1.

The proof of Theorem 10-3 is virtually identical to the proof of Theorem 10-2. You argue that themaximum number of nodes in T equals the maximum number of nodes in T’s left subtree plus themaximum number in its right subtree plus one for the root. By the inductive hypothesis, the left andright subtrees can have at most 2h-1– 1 nodes. The arithmetic is identical to that used in the proof ofTheorem 10-2.

Page 113: Excersize DataStructure

113

22 The maximum number of nodes that can exist at level N of a binary tree is 2N - 1 .

Proof by induction on the level number:

Base: At level 1, there is one node (the root). 21 - 1 = 2 0 = 1

Inductive hypothesis: For all levels k, 1 ≤ k < N, the maximum number of nodes on a level is 2k - 1.

Inductive conclusion: The maximum number of nodes at level N is 2N - 1. By the inductivehypothesis, the maximum number of nodes on level N–1 is 2N - 2. Each node on level N–1 can have atmost two children. Therefore, the maximum number of nodes at level N is 2 * 2N - 2 = 2N - 1, which is whatwe want to show.

a Part 1 of the formal definition of a complete binary tree can be rewritten:

(1) all levels N, 1 ≤ N < h, have 2N - 1nodes

b The closed form of the formula given in 2h - 1, which is the number of nodes in a full binary tree (abinary tree is full if all levels have the maximum number of nodes). This closed form can be provenby induction.

23 A proof that a binary tree with N nodes has exactly N+1 empty subtrees:

Base: A binary tree with one node has two empty subtrees.

Induction : Assume that a binary tree with N–1 nodes has N empty subtrees. If we add a node to this tree,we will replace one of the N empty subtrees with a node, but we will add two empty subtrees (the subtreesof the added node). Therefore, the tree (with N nodes) will have N–1+2 = N+1 empty subtrees.

2 4 A proof that a strictly binary tree with N leaves has 2N –1 nodes.

Base: A strictly binary tree with one leaf has one node.

Induction : Assume that a strictly binary tree with N–1 leaves has 2(N–1) – 1 = 2N – 3 nodes. Wecannot add one node and preserve the strict binary tree property. So we add two nodes, but the neteffect is to add one leaf (we change one leaf from a leaf to an interior node by adding two children).Therefore, we have N leaves and 2N –3 + 2 = 2N –1 nodes.

25a Traversing the tree of Figure 10-17 in the text:

i. Algorithm 1: Jane, Tom, Wendy, Nancy, Bob, Ellen, Alanii. Algorithm 2: Jane, Bob, Tom, Alan, Ellen, Nancy, Wendy

b Use a stack for algorithm 1 and a queue for algorithm 2. The data item for the stack or queue should be apointer to the node being added. There is no need to store the entire tree node since the traversal does notchange the tree (the stored pointer will indicate the correct tree node when the pointer is retrieved from thestack or queue).

Page 114: Excersize DataStructure

114

2 6 Perform a preorder traversal on the binary tree, saving the data to a line in the file for each node visited.When the file is read, a new node is inserted for each line encountered, recapitulating the order of theoriginal tree. This operation is linear in the number of nodes of the tree for both the binary tree and thebinary search tree.

2 7 Consider the case when the node to be deleted has two children:

// two-child case of deleteProcessLeftmost(DelPtr, ReplacementItem);ReplacementItem->LChildPtr := DelPtr->LChildPtr;ReplacementItem = DelPtr;DelPtr := DelPtr->RChild;delete ReplacementItem;

28 An iterative BST insert routine:

void bstClass::InsertItem(ptrType& TreePtr, treeItemType NewItem, boolean& Success)

{ ptrType Parent = NULL, Cur = TreePtr; while(Cur != NULL) // loop until a leaf is hit { Parent = Cur; if (NewItem.Key < Cur->Item.Key) Cur = Cur->LChildPtr; else Cur = Cur->RChildPtr; } Cur = new treeNode(NewItem, NULL, NULL);

if (Cur != NULL) Success = true; else { Success = false; return; }

// Parent points to the node that will be the parent of NewItem if (Parent != NULL) Parent->LChildPtr = Cur; else Parent->RchilePtr = Cur; // else just inserted into an empty tree} // end function InsertItem

29 In addition to the ADT table operations, ADT binary search tree operations could include postorder andpreorder traversals, subtree deletion, tree balancing, etc.

30

Page 115: Excersize DataStructure

115

31 BST with parent pointers. The only operations that need to be modified are included.

void bstClass::InsertItem(ptrType& TreePtr, treeItemType NewItem, ptrType& Parent, boolean& Success){ if (TreePtr == NULL) // position of insertion found; insert after leaf { // create a new node TreePtr = new treeNode(NewItem, NULL, NULL, Parent);

// was allocation successful? Success = boolean(TreePtr != NULL); } // else search for the insertion position else if (NewItem.Key < TreePtr->Item.Key) // search the left subtree InsertItem(TreePtr->LChildPtr, NewItem, TreePtr, Success); else // search the right subtree InsertItem(TreePtr->RChildPtr, NewItem, TreePtr, Success);} // end InsertItem

void bstClass::DeleteRootItem(ptrType& NodePtr)// Algorithm note: There are four cases to consider:// 1. The root is a leaf.// 2. The root has no left child.// 3. The root has no right child.// 4. The root has two children.// Calls: ProcessLeftmost.{ ptrType DelPtr; treeItemType ReplacementItem; if (NodePtr != NULL) { // test for a leaf if ( (NodePtr->LChildPtr == NULL) && (NodePtr->RChildPtr == NULL) ) { delete NodePtr; NodePtr = NULL; } // end if leaf // test for no left child else if (NodePtr->LChildPtr == NULL) { DelPtr = NodePtr; NodePtr = NodePtr->RChildPtr; NodePtr->Parent = DelPtr->Parent; // added DelPtr->RChildPtr = NULL; delete DelPtr; } // end if no left child // test for no right child else if (NodePtr->RChildPtr == NULL) { DelPtr = NodePtr; NodePtr = NodePtr->LChildPtr; NodePtr->Parent = DelPtr->Parent; // added DelPtr->LChildPtr = NULL; delete DelPtr; } // end if no right child // there are two children: // delete and retrieve the inorder successor else { ProcessLeftmost(NodePtr->RChildPtr, ReplacementItem); NodePtr->Item = ReplacementItem; } // end if two children } // end if NodePtr != NULL} // end DeleteRootItem

Page 116: Excersize DataStructure

116

32a A recursive preorder traversal:

void bstClass::Traverse (ptrType T);{ if (T != NULL) { Visit (T->Item); for (int I=0; I<T.ChildNum;I++) Traverse (T->Children[I]); }} // end Traverse

Advantages: Access to the children is easy; direct access to each child is available.

Disadvantages: Limits the number of children to a fixed maximum. If the maximum number ofchildren possible is higher than the average number of children, then memory is wasted. If thechildren are kept in order, insertions and deletions may require shifting pointers in the array.

b An implementation of a tree using oldest child/next sibling representation:

void bstClass::Traverse (ptrType T); // pre-order{ if (T != NULL) { Visit (T->Item); Traverse (T->Child); Traverse (T->Sib) }} // end Traverse

c If a tree is known to be binary, the implementation described in the chapter is a better representation, as itsheight is smaller. For example, consider the tree

A A

B C B C

The first has a height of 2, the second (the same tree in oldest child/next sibling representation) has a heightof 3. Inorder traversals are easier; binary search tree algorithms are easier since one can godirectly from the parent to the right subtree. The representations of the two types of trees would bethe same for a left linear tree (no right children).

33 Inorder traversal that allows Visit to delete the current node. We assume that DeleteItem has beenmodified in the two-child case to replace the node to be deleted with its inorder predecessor.

void bstClass::Inorder(ptrType TreePtr, functionType Visit){ boolean DeleteIt = false; if (TreePtr != NULL) { Inorder(TreePtr->LChildPtr, Visit); Visit(TreePtr->Item, DeleteIt); if (DeleteIt) Inorder(TreePtr->RChildPtr, Visit); } // end if TreePtr != NULL} // end Inorder

34

Page 117: Excersize DataStructure

117

35

Page 118: Excersize DataStructure

118

Tables and Priority Queues

1 // *********************************************************// Implementation file Table.cpp for the ADT table.// Sorted Array-based implementation.// *********************************************************#include "Table.h" // header file

tableClass::tableClass(){ Size = 0; // set count field to 0} // end constructor

tableClass::tableClass(const tableClass& T) : Size(T.Size){ for ( int Index = 0; Index < T.Size; ++Index) Items[Index] = T.Items[Index];} // end copy constructor

tableClass::~tableClass(){} // end destructor

boolean tableClass::TableIsEmpty(){ return boolean(Size == 0);} // end TableIsEmpty

int tableClass::TableLength(){ return Size;} // end TableLength

void tableClass::TableInsert(tableItemType NewItem, boolean& Success)// Note: Insertion is unsuccessful if the table is full, that// is, the table already contains MAX_TABLE items.// Calls: Position.{ // is there room for insertion? Success = boolean(Size < MAX_TABLE); if (Success) { // there is room to insert; // locate the position where NewItem belongs int Spot = Position(NewItem.Key); // shift up to make room for the new item for ( int Index = Size-1; Index >= Spot; --Index) Items[Index+1] = Items[Index]; // make the insertion Items[Spot] = NewItem; ++Size; } // end if} // end TableInsert

void tableClass::TableDelete(keyType SearchKey, boolean& Success)// Calls: Position.{ // locate the position where SearchKey exists/belongs int Spot = Position(SearchKey);

// is Searchkey present in the table?

11

Page 119: Excersize DataStructure
Page 120: Excersize DataStructure

120

2a For the unsorted array-based implementation, the only function that needs to change is KeyIndex . Becausethe order of items is not known, the searching technique changes from a binary search to a sequential search.

int tableClass::KeyIndex(int First, keyType SearchKey){ if (First > (Size-1)) return First; // Value not in original array, return its proper

// position else { // Invariant: If Value is in A, A[First] <= Value <= A[Last] if (SearchKey == Items[First].Key) return First; // Value found at A[First] else return KeyIndex(First+1, SearchKey); } // end else} // end KeyIndex

The sorted and unsorted versions of TableReplace are the same for pointer-based and array-based tables(the differences are in the KeyIndex routines). If KeyIndex succeeds, then replace the item by copyingover it.

b TableReplace preserves the existing structure of a binary-tree-based implementati onode is a leaf node, unless the function is re-written to replace all of the fi echanging the values of any of the pointer variables in the node.

3 If the word can be evaluated to generate an index in constant time, the sorted- athe the table may be the most efficient. It is more likely, however, that a b icomparing the value of the word with the various search keys generated by the sn time for either the sorted-array based or the binary-search-tree based implem e

4 The binary search tree offers the most efficient implementation for the spell ch einsertions in O(log n) time.

5 The pointer-based binary search tree implementation would be the best suited for the task. A binarysearch is used for retrieval and insert point location, and insertion is done without moving data in an array.

6 // put the header file here

// *********************************************************// Implementation file TableT.cpp for the ADT table.// Sorted Array-based implementation.// *********************************************************#include "TableT.h" // header file

template <class T>tableClass::tableClass(){ Size = 0; // set count field to 0} // end constructor

template <class T>tableClass::tableClass(const tableClass<T>& Table) : Size(Table.Size){

Page 121: Excersize DataStructure

121

for ( int Index = 0; Index < Table.Size; ++Index) Items[Index] = Table.Items[Index];} // end copy constructor

template <class T>tableClass::~tableClass(){} // end destructor

template <class T>boolean tableClass::TableIsEmpty(){ return boolean(Size == 0);} // end TableIsEmpty

template <class T>int tableClass::TableLength(){ return Size;} // end TableLength

template <class T>void tableClass::TableInsert(T NewItem, boolean& Success)// Note: Insertion is unsuccessful if the table is full, that// is, the table already contains MAX_TABLE items.// Calls: Position.{ // is there room for insertion? Success = boolean(Size < MAX_TABLE); if (Success) { // there is room to insert; // locate the position where NewItem belongs int Spot = Position(NewItem.Key); // shift up to make room for the new item for ( int Index = Size-1; Index >= Spot; --Index) Items[Index+1] = Items[Index]; // make the insertion Items[Spot] = NewItem; ++Size; } // end if} // end TableInsert

template <class T>void tableClass::TableDelete(keyType SearchKey, boolean& Success)// Calls: Position.{ // locate the position where SearchKey exists/belongs int Spot = Position(SearchKey);

// is Searchkey present in the table? Success = boolean((Spot <= Size) && (Items[Spot].Key == SearchKey));

if (Success) { // Search Key in Table --Size; // delete the item // shift down to fill the gap for ( int Index = Spot; Index < Size; ++Index) Items[Index] = Items[Index+1]; } // end if} // end TableDelete

template <class T>void tableClass::TableRetrieve(keyType SearchKey,

T& TableItem,

Page 122: Excersize DataStructure
Page 123: Excersize DataStructure

123

8a In the absence of secondary keys, the most sane method for implementing TableRetrieve andTableDelete when duplicates are allowed is to retrieve and delete all items with the given key. ForTableRetrieve , a dynamic structure would have to be returned that could hold a variable number of items.

b If duplicate keys are to be inserted, then each node will have to possess an a dlist of similarly tagged nodes. Thus a TableInsert , in addition to its search fcheck if there is a node with the same key and, if so, insert the new node int onode in the table. Similarly, TableDelete , in finding the target key, must the nsimilar keys and delete only the node whose secondary values duplicate the valu eTableRetrieve must also traverse these lists of similar keys, again deciding on tsecondary information.

9 The most efficient, and simplest, would involve two tables, one indexed by Nam eSecurity Number. For each deletion on TableDeleteN , once the target record is f othe Number field is used as the search key to delete from the other table, thus deleted from both tables. Do the reverse when performing TableDeleteS .

10 Here, the record which is stored in the binary search tree will be found more q uthe linked list. However, since deletions will occur from both tables on the s aof the deletion depends on the longer operation on the linked list, which take s

11 void tableClass::TraverseTable(functionType Visit){ boolean Success, DeleteIt = true; for ( int Index = 0; Index < Size; ++Index) { Visit(Items[Index], DeleteIt); if (DeleteIt) TableDelete(Items[Index].Key, Success); } // end for} // end TraverseTable

12 If the heap contains only a single item, then the assertion is obviously true. For an inductive step,suppose that the assertion is true for all heaps with n–1 or fewer items, and consider a heap, H,containing n items. By definition, the root of H is larger than either of its children, and each of itschildren are roots of a heap of size n–1. Thus, the children of the root of H have the largest value intheir subtrees by the inductive hypothesis. Since the root of H is larger than either of its children, theassertion is true for a heap of size n.

Page 124: Excersize DataStructure

124

13 The order of item insertion does not affect the shape of the resultant binary tree; it does affect thedistribution of values in the individual nodes. The following diagram illustrates this point.

10 10

9 6 9 5

5 2 3 3 6 2

The tree resulting from The tree resulting from the insert order: the insert order: 10 9 3 5 2 6 6 3 5 10 9 2

1 4 Implement the heap as an actual binary tree. In this manner, RebuildHeap and HeapInsert reassignpointers rather than swap items.

1 5 The order in which two items with the same priority value are inserted in a heap does not necessarily affectthe order in which they are removed. To remove duplicate priorities in first in, first out (FIFO) order, theorder in which the items were inserted must be maintained as a secondary key.

1 6 Changing to a minheap only affects HeapAdd and RebuildHeap . In HeapAdd, the item should trickle up ifit is smaller than its parent, and in RebuildHeap , the item should trickle down if it is larger than one of itschildren. Only comparison operators need be changed.

1 7 Maintaining an index to the minimum item in the heap can be achieved by comparing the value of anewly inserted item with the current minimum (the current minimum is maxint initially). If the value issmaller than the current minimum, then update the minimum value and store its position after the trickleup process has terminated. If the value is not smaller than the current minimum, then as the new item isinserted check to see whether the location of the current minimum changes as the result of a swap. During adelete, check to see if the location of the current minimum changes during the adjust process (e.g., when thecurrent minimum is the last element in the heap).

1 8 If the priority value increases, trickle the item up (as in insert). If the priority value decreases, trickle itdown (as in adjust).

1 9 // templates

2 0 HeapSort calls RebuildHeap (A, i, N) , with i being passed to Root and N being passed to Size inRebuildHeap . RebuildHeap does nothing if 2 * Root > Size . When i is between N and N/2, 2 * i

will always be larger than N; therefore the call to RebuildHeap does nothing and the for loop could beshortened.

Page 125: Excersize DataStructure

125

2 1 The original order 5 1 2 8 6 10 3 9 4 7

After the heap is created 10 9 8 6 7 2 3 1 4 5 |

After swap 1 and RebuildHeap 9 7 8 6 5 2 3 1 4 | 10

After swap 2 and RebuildHeap 8 7 4 6 5 2 3 1 | 9 10

After swap 3 and RebuildHeap 7 6 4 1 5 2 3 | 8 9 10

After swap 4 and RebuildHeap 6 5 4 1 3 2 | 7 8 9 10

After swap 5 and RebuildHeap 5 3 4 1 2 | 6 7 8 9 10

After swap 6 and RebuildHeap 4 3 2 1 | 5 6 7 8 9 10

After swap 7 and RebuildHeap 3 1 2 | 4 5 6 7 8 9 10

After swap 8 and RebuildHeap 2 1 | 3 4 5 6 7 8 9 10

After swap 9 and RebuildHeap 1 | 2 3 4 5 6 7 8 9 10

The array is sorted 1 2 3 4 5 6 7 8 9 10

2 2 // Heapsort

#include <stdlib.h> // for rand()#include <iostream.h>

typedef int dataType;const int MAX_SIZE = 10;typedef dataType arrayType[MAX_SIZE];

void RebuildHeap(arrayType H, int Root, int N)// Converts a semiheap into a heap.// Precondition: H is an array representation of a semiheap// rooted at index Root and containing N items.// Postcondition: H is an array representation of a heap// rooted at index Root and containing N items.// Method: Recursively trickles the item at index Root// down to its proper position by swapping it with its larger// child, if the child is larger than the item. If the item// is at a leaf, nothing needs to be done.{ // if the root is not a leaf and the root's value is less // than the larger of the values in the root's children int Child = 2 * Root + 1; // index of root's left child, if any

if ( Child < N ) { // root is not a leaf, so it has a left child at Child int RightChild = Child + 1; // index of right child, if any

// if root has a right child, find larger child if ( (RightChild < N) && (H[RightChild] > H[Child]) ) Child = RightChild;

// Child is the index of larger child of root // if the root's value is smaller than the // value in the larger child, swap values if (H[Root] < H[Child]) { // swap dataType Temp = H[Root];

Page 126: Excersize DataStructure

126

H[Root] = H[Child]; H[Child] = Temp; // transform the new subtree into a heap RebuildHeap(H, Child, N); } // end if } // end if // else if root is a leaf, do nothing} // end RebuildHeap

void HeapSort(arrayType A, int N)// Sorts the elements of an array into ascending order.// Precondition: A is an array of N elements.// Postcondition: A is sorted into ascending order; N is unchanged.{ // build the initial heap for ( int Index = N/2; Index >= 0; --Index) // invariant: tree rooted at Index is a semiheap RebuildHeap(A, Index, N); // transform tree into a heap

// sort for (int Last = N-1; Last >= 1; --Last) { // invariant: A[0..Last] is a heap, A[Last+1..N-1] is // sorted and contains the largest elements of A // swap A[0] and A[Last] dataType Temp = A[0]; A[0] = A[Last]; A[Last] = Temp; // Last is now 1 greater than index of last item in semiheap // Semiheap rooted at 0 contains Last items. // transform semiheap into a heap RebuildHeap(A, 0, Last); // assertion: A[0] is the largest element in A[0..Last-1] } // end for} // end HeapSort

23 Simply reset the comparison in RebuildHeap so that the root contains the smallesrepeated calls to HeapDelete are made, the sorted array is built from right to l eresulting in the array sorted in descending order.

Page 127: Excersize DataStructure

127

Advanced Implementations of Tables

1a Binary search tree (reading across, then down):

insert 10 insert 100 insert 30 insert 80 insert 50

10 10 10 10 10

100 100 100 100

30 30 30

80 80

50

delete 10 insert 60 insert 70 insert 40 delete 80

100 100 100 100 100

30 30 30 30 30

80 80 80 80 50

50 50 50 50 40 60

60 60 40 60 70

70 70

insert 90 insert 20 delete 30 delete 70

100 100 100 100

30 30 40 40

50 20 50 20 50 20 50

40 60 40 60 60 60

70 70 70 90

90 90 90

b 2-3 tree:

insert 10 insert 100 insert 30 insert 80

10 10|100 30 30

10 100 10 80|100

insert 50 delete 10 insert 60 insert 70

30|80 80 50|80 50|80

10 50 100 30|50 100 30 60 100 30 60|70 100

12

Page 128: Excersize DataStructure

128

Page 129: Excersize DataStructure

129

insert 40 delete 80 insert 90 insert 20

50|80 50|70 50|70 50

30|40 60|70 100 30|40 60 100 30|40 60 90|100 30 70

20 40 60 90|100

delete 30 delete 70

50|70 50|90

20|40 60 90|100 20|40 60 100

c 2-3-4 tree:

insert 10 insert 100 insert 30 insert 80

10 10|100 10|30|100 30

10 80|100

insert 50 delete 10 insert 60 insert 70

30 50 50 50|80

10 50|80|100 30 80|100 30 60|80|100 30 60|70 100

insert 40 delete 80 insert 90 insert 20

50|80 50|70 50|70 50|70

30|40 60|70 100 30|40 60 100 30|40 60 90|100 20|30|40 60 90|100

delete 30 delete 70

50|70 50|90

20|40 60 90|100 20|40 60 100

d A red-black tree :

insert 10 insert 100 insert 30 insert 80

10 10 30 30

100 10 100 10 100

80

insert 50 delete 10 insert 60 insert 70

30 50 50 50

10 80 30 80 30 80 30 80

50 100 100 60 100 60 100

70

Page 130: Excersize DataStructure
Page 131: Excersize DataStructure

131

implementation than a binary search tree. Maintaining a balanced binary search tree may becomevery expensive in the face of frequent inserts and deletions as the entire tree must be rebuilt in theworst case.

3 Visit all items in a binary search tree that have a key value in the range Low ... High:

void RangeQuery(bstClass T, keyType Low, keyType High, functionType Visit){ if (!T.BinaryTreeIsEmpty()) { if (Low < T.RootData) RangeQuery (T.LeftSubtree(), Low, High, Visit); else if ((Low <= T.RootData) and (T.RootData <= High)) Visit (T.RootData); else if (High > T.RootData) RangeQuery (T.RightSubtree, Low, High, Visit) }} // end RangeQuery

4 Insert 39, 38, 37, 36, 35, 34, 33, and 32 into the 2-3-4 tree of Figure 12-5b in the text.

37|50

30|35 39 70|90

10|20 32|33|34 36 38 40 60 80 100

5

6 Another red-black that represents Figure 12-20 in the text.

50

37 70

35 39 60 90

30 36 38 40 80 100

20 33

10 32 34

7 37 | 50

30|35 39 70|85|90

10|20 32|33|34 36 38 40|45 60|65 80 87|89 100

8

9 enum color {RED, BLACK};typedef rbTreeNode* rbPtrType;struct rbTreeNode

Page 132: Excersize DataStructure

132

{ treeItemType Item; rbPtrType LChildPtr, RChildPtr; color Lcolor, Rcolor;};rbPtrType Convert234toRBtree(PtrType T, bool& Success){ if (T == NULL) { Success = true; return NULL; }

if (T.RMidChildPtr == NULL) // leaf node, 1 child or 2 children { rbPtrType NewNode = new rbTreeNode; if(NewNode == NULL) { Success = false; return NULL; } NewNode.Item = T.SmallItem; NewNode.LChildPtr = Convert234toRBtree(T.LChildPtr, Success); if (Success) NewNode.RChildPtr = Convert234toRBtree(T.LMidChildPtr, Success); if (Success) { NewNode.LColor = NewNode.RColor = BLACK; return NewNode; } else return NULL; }

if (T.RChildPtr == NULL) // 3 children { rbPtrType NewChildNode = new rbTreeNode; if (NewChildNode == NULL) { Success = false; return NULL; } NewChildNode.Item = T.SmallItem; NewChildNode.LChildPtr = Convert234toRBtree(T.LChildPtr, Success); if (Success) NewChildNode.RChildPtr = Convert234toRBtree(T.LMidChildPtr, Success); if (!Success) return NULL;

NewChildNode.LColor = NewChildNode.RColor = BLACK;

rbPtrType NewNode = new rbTreeNode; if (NewNode == NULL) { Success = false; return NULL; } NewNode.Item = T.MiddleItem; NewNode.RChildPtr = Convert234toRBtree(T.RMidChildPtr, Success); if (Success) { NewNode.LChildPtr = NewChildNode; NewNode.LColor = RED; NewNode.RColor = BLACK; return NewNode; } else return NULL; }

// else, this node has 4 children rbPtrType NewLChildNode = new rbTreeNode; if (NewLChildNode == NULL)

Page 133: Excersize DataStructure

133

{ Success = false; return NULL; } NewLChildNode.Item = T.SmallItem; NewLChildNode.LChildPtr = Convert234toRBtree(T.LChildPtr, Success); if (Success) NewLChildNode.RChildPtr = Convert234toRBtree(T.LMidChildPtr, Success); if (!Success) return NULL;

NewLChildNode.LColor = NewLChildNode.RColor = BLACK;

rbPtrType NewRChildNode = new rbTreeNode; if (NewRChildNode == NULL) { Success = false; return NULL; } NewRChildNode.Item = T.LargeItem; NewRChildNode.LChildPtr = Convert234toRBtree(T.RMidChildPtr, Success); if (Success) NewRChildNode.RChildPtr = Convert234toRBtree(T.RChildPtr, Success); if (!Success) return NULL; NewRChildNode.LColor = NewRChildNode.RColor = BLACK;

rbPtrType NewNode = new rbTreeNode; if (NewNode == NULL) { Success = false; return NULL; } NewNode.Item = T.MiddleItem; NewNode.LChildPtr = NewLChildNode; NewNode.RChildPtr = NewRChildNode; NewNode.Lcolor = NewNode.RColor = RED; return NewNode;} // end Convert234toRBtree

10 The following pseudocode implements operations on a table which uses hashing a nresolve collisions:

TableInsert(NewItem, Success)

SearchKey = the search key of NewItem I = HashIndex(SearchKey)

if (T[I] is not empty) { do I = (I + 1)mod TableSize while(T[I] is not empty and I != HashIndex(SearchKey)) }

if (T[I] is empty) { T[I] = NewItem Success = true } else Success = false

TableDelete(SearchKey, Success)

I = HashIndex(SearchKey)

Page 134: Excersize DataStructure
Page 135: Excersize DataStructure

135

Graphs

1a The adjacency matrix for the weighted graph in Figure 13-33.

0 1 2 3 4 50 0 9 ∞ ∞ 1 ∞1 9 0 8 ∞ 6 ∞2 ∞ 8 0 5 ∞ 23 ∞ ∞ 5 0 ∞ ∞4 1 6 ∞ ∞ 0 75 ∞ ∞ 2 ∞ 7 0

b The adjacency matrix for the directed graph in Figure 13-34 (where a 1 indicates the existence of anedge and a 0 indicates the absence of an edge):

a b c d e f g h ia 0 1 1 0 0 0 0 0 0b 0 0 0 1 0 0 0 1 0c 0 0 0 1 1 0 0 0 0d 0 0 0 0 0 0 0 1 0e 0 0 0 0 0 0 1 0 0f 0 0 0 0 0 0 1 0 1g 0 0 1 0 0 0 0 0 0h 0 0 0 0 0 0 1 0 0i 0 0 1 0 0 0 0 0 0

The adjacency list:

node edges to:a b, cb d, hc d, ed he gf g, ig ch gi c

2 Let each integer require m bytes and assume that addresses are stored as integers. The size of the adjacencymatrix is then (9 * 9)m = 81m bytes. The adjacency list requires an array of 9 addresses of size m plus tennodes each composed of an integer for storing the vertex name and another integer for the address of the nextnode (if any). Thus the total is 9m + (10 * 2)m = 29m < 81m.

13

Page 136: Excersize DataStructure

136

3 Depth-first and breadth-first searches, where the possible vertices at each step are visited in sortedorder (increasing):

Graph in Figure 13-33.

depth-first search: 0, 1, 2, 3, 5, 4.breadth-first search: 0, 1, 4, 2, 5, 3.

Graph in Figure 13-31.

depth-first search: a, b, c, d, h, f, e, g, i.breadth-first search: a, b, c, d, e, f, h, g, i.

4 Within the while loop, insert the following just before the first if statement:

if (there is a visited vertex adjacent to the vertex on top of the stack) report a cycle

5 Depth-first search topological sort of the graphs in Figure 13-36:

aAction Stack(bottom -> top) Ordered Listpush a a emptypush b a b emptypush c a b c emptypop c a b cpop b a b cpush d a d b cpush e a d e b cpop e a d e b cpop d a d e b cpop a empty a d e b c

bA c t i o n Stack (bottom-

> t o p )Ordered List

push a a emptypush b a b emptypush c a b c emptypop c a b cpop b a b cpush d a d b cpop d a d b cpop a empty a d b c

Page 137: Excersize DataStructure

137

cA c t i o n Stack (bottom ->

t o p )Ordered List

push a a emptypush b a b emptypush c a b c emptypop c a b cpop b a b cpush d a d b cpop d a d b cpush e a e d b cpop e a e d b cpop a empty a e d b c

6 TopSort1(G, L)// Arranges the vertices of G into a// topological order and places them in list L.

N = number of vertices in G

for(Step = 1 through N) { Select a vertex v that has no predecessors L.ListInsert(Step, v, Success) Delete from G vertex v and its edges } // end for// end TopSort1

a a b c

d eRemove a from Add it to L

b c

d e

a

Remove b from Add it to L

c

d e

a b

Remove d from Add it to L

c

e

a b d

Remove e from Add it to L

c a b d e

Remove c from Add it to L

a b d e c

Done

Page 138: Excersize DataStructure

138

b

c

a

b

c

d Remove a from Add it to L

b

c

d

a

Remove b from Add it to L

c

d a b

Remove c from Add it to L

d

a b c

Remove d from Add it to L

a b c d

Done

b

e

d

ca Remove a from Add it to L

b

e

d

c

a

Remove b from Add it to L

e

d

c a b

Remove d from Add it to L

Page 139: Excersize DataStructure
Page 140: Excersize DataStructure

140

the top of the stack. S.Push(u, Success) Mark u as visited } // end if } // end while

10 Refer to Figure 13-22 in the text:

a) minimal spanning tree rooted at g b) minimal spanning tree rooted a

11 A trace of the shortest-path algorithm for the graph given in Figure 13-37 of the text.

Step v S W[0] W[1] W[2] W[3] W[4] W[5] W[6]1 - [0] 0 2 4 6 ∞ ∞ ∞2 1 [01] 0 2 4 6 5 ∞ ∞3 2 [012] 0 2 4 6 5 ∞ ∞4 4 [0124] 0 2 4 6 5 10 65 3 [01243] 0 2 4 6 5 9 66 6 [012436] 1 2 4 6 5 8 67 5 [0124365] 1 2 4 6 5 8 6

12 The following functions produce a spanning tree for a given (undirected) connected graph using BFS andDFS. We assume the standard graph operations are available:

BFS spanning tree. Assumes that the standard integer queue operations are available.

graphClass BFS (graphClass& G1, int N)// G2 will contain a spanning tree for the graph G1 upon return. N is the// number of vertices in graph G1, labeled 0..N-1{ graphClass G2; queueClass Q; boolean Success, visited[MaxVertices]; int V, W;

// mark all vertices as being unvisited for (V=0; V<N; V++) visited[V] = false; // start search at vertex 0 Q.QueueAdd(0, Success); visited[0] = true; while(!Q.QueueIsEmpty()) { // get next vertex to explore Q.GetQueueFront(V, Success); Q.QueueRemove(Success); for (W=0; W<N; W++)

c

b

d

a

he

f

i

g

c

b

d

a

he

f

i

g

Page 141: Excersize DataStructure

141

if (G1.IsEdge(V, W, Success) && !visited[W]) { // add a new branch to the spanning tree G2.InsertEdge (V, W, Success); Q.QueueAdd(W, Success); visited[W] = true; } } return G2;} // end function BFS

DFS spanning tree. Assumes the standard integer stack operations.

graphClass DFS (graphClass& G1, int N)// G2 will contain a spanning tree for the graph G1 upon return. N is the// number of vertices in graph G1, labeled 0..N-1{ graphClass G2; stackClass S; boolean visited[MaxVertices]; boolean Success; int V, W;

// mark all vertices as being unvisited for (V=0; V<N; V++) visited[V] = false; // start search at vertex 0 S.Push(0, Success); visited[0] = true; while(!S.StackIsEmpty()) { // get next vertex to explore S.GetStackTop(V, Success); S.Pop(Success); for (W=0; W<N; W++) if (G1.IsEdge(V, W, Success) && !visited[W]) { // add a new branch to the spanning tree G2.InsertEdge (V, W, Success); S.Push(W, Success); visited[W] = true; } } return G2;} // end function DFS

13 One such circuit is: a b f c d g e a We know the graph has an Euler circuit sand d is 2 and the degree of the remaining nodes is 4. Since all nodes have evmany in-edges as out-edges and so a circuit is possible.

Page 142: Excersize DataStructure

142

14 Consider any connected, undirected graph, G, not containing loops or multiple edges. If G has Nvertices and N–1 edges, then G must form a tree. Now add any additional edge, (i, j ), to G. Since G is atree, there is a path from i to j in G, and adding edge (i , j ) must then form a cycle.

15 A traversal visits every vertex in the graph if and only if the (undirected) graph is connected,regardless of where the traversal starts. Suppose that the traversal starts at vertex v and does not visit vertexw. Then there is no path from v to w and so the graph is not connected.

On the other hand, suppose that, when starting at vertex v, a traversal does visit every other vertex in thegraph. Then we assert that there is a path between every pair of vertices u and w. To get from u to w, notethat a) there is a path from v to u, and b) there is a path from v to w. Since the graph is undirected there isalso a path from u to v, and so a path from u to w proceeds from u to v and then from v to w. Hence, thegraph is connected.

16a The recursive BFS algorithm is not simple because the underlying data structure is a queue. It mustbe a queue to ensure that vertices close to the current vertex are visited before those further away.DFS uses a stack and so can naturally be implemented recursively.

16b BFS(v)// Traverses a graph beginning at vertex v by using a// breadth-first search: Recursive version.

Q.CreateQueue() Mark v as visited

for(each unvisited vertex u adjacent to v) Q.QueueInsert(u, Success)

// loop invariant: there is a path from vertex v // to every vertex in the queue Q while(!Q.QueueIsEmpty()) { Q.QueueDelete(w, Success) BFS(w) } // end while

17 Proof of the loop invariant of Dijkstra’s shortest-path algorithm:

The loop invariant: For v not in S, W[ v] is the smallest weight of all paths from 1 to v that passthrough only vertices in S before reaching v. For v in S, W[v] is the smallest weight of all paths from 1 tov (including paths outside S) and the shortest path from 1 to v lies entirely in S.

Proof by induction on Step: Basis: Step = 1. The initialization step sets S to 1 and W to the firstrow of the adjacency matrix. The paths that the invariant describes when S contains only 1 are simplysingle edges from 1 to any vertex, and the weights for these paths are in the array W. The invariant is true.

Inductive hypothesis: Assume the invariant is true during Steps 1 through k<N.

Inductive conclusion: At the beginning of Step k + 1, there are k vertices in S. Find the smallest W[v] such that v is not in S, and let P designate the path from 1 to v. By the inductive hypothesis(specifically, the first part of the invariant), W[v] is the smallest weight of all paths from 1 to v thatpass through only vertices in S before reaching v. Let v' be the last vertex on the path P that is in S.

Page 143: Excersize DataStructure

143

By the inductive hypothesis (the second part of the invariant), W[v' ] is the smallest weight of all pathsfrom 1 to v', including paths outside S, and the shortest path from 1 to v' — call it P' — lies entirely in S.Path P is thus obtained by adding to P' the edge from v' to v. Thus, W[ v] is obtained by adding to W[v']the weight of the edge from v' to v. Therefore, when the algorithm adds v to S and adjusts W such that

W[ u] ≤ W[v] + A[v, u]

for each vertex u not in S, W[ u] must be the smallest of all paths from 1 to u that pass through onlyvertices in S before reaching u.

We must now show that W[v] is the smallest weight of all paths from 1 to v (including paths outside S). Ifthis statement were untrue, there would be a path from 1 to v whose weight was less than W[v]. If thisshorter path passed only through vertices in S, then its existence would contradict the choice of v: v waschosen earlier so that W[v] would be a minimum of all paths that passed through vertices in S beforereaching v. On the other hand, if the shorter path leaves S before reaching v, it must pass through a vertexv' outside of S. Clearly, the path to v' is shorter than the path to v, so W[v' ]<W[ v]. This result alsocontradicts the earlier choice of v. Therefore, the statement that began this paragraph must be true.

Finally, we must show that the shortest path from 1 to v lies entirely in S. If the path left S beforereaching v, it would pass through a vertex v' outside of S. As you just saw, this eventually leads to acontradiction. (End of proof.)

Page 144: Excersize DataStructure

144

External Methods

1 void ShiftData (F, I, B)// Make a gap at record I in block B of sorted file F{ if (B == LastBlock-1) { // special case ReadBlock (F, B, B); for (J=LastRecord-1;J>I; J--) // assuming LastRecord + 1 < RecordsPerBlock B[J] = B[J-1] } else { // do block B first ReadBlock (F, B, B); // save the last record Temp1 = B [RecordsPerBlock]; // make a gap at location I for (J=RecordsPerBlock-1; J>I; J--) B[J] = B[J-1]; WriteBlock (F, B, B); // do all blocks except LastBlock for (K=B + 1; K<LastBlock; K++) { ReadBlock (F, K, B); // save the last record Temp2 = B [RecordsPerBlock-1]; // shift all records down one, leaving a gap at location 1} for (J=RecordsPerBlock-1; J>0; J--) B[J] = B[J-1]; // insert record saved from last location in previous block} B[0] = Temp1; // get ready for next block } Temp1 := Temp2; WriteBlock (F, K, B) } // do LastBlock ReadBlock (F, LastBlock, B); for (J=RecordsPerBlock-1; J>0; J--) B[J] = B[J-1]; B[0] = Temp1; WriteBlock (F, LastBlock, B) }} // end ShiftData

2 We can use a doubly linked list of blocks. When a record is deleted from a block that was previously full orwhen a new block is allocated, add that block to the front of the free block list. When a slot is needed, usethe block at the beginning of the list; if it becomes full then remove it from the list. When a record isdeleted from a block and that block becomes completely empty, then return the block to the system anddelete it from the free block list.

By allocating some space in the block for “pointers” (block numbers), the blocks themselves can bethe nodes on the free block list.

void GetSlot (F, BlockNum, RecNum)

14

Page 145: Excersize DataStructure

145

{ if (Freelist != 0) { // Free list is not empty; there is room in existing blocks BlockNum = FreeList; // Read first block on free list into internal array B ReadBlock (F, BlockNum, B); RecNum = EmptySlot (B); // Find an empty slot MarkUsed (B, RecNum); // Has the block become full? if (NumFreeSlots (B) == 0) Freelist := NextBlock (B) WriteBlock (F, BlockNum, B) } else { // Free list is empty; get a block from the system AllocateBlock (F, BlockNum); ReadBlock (F, BlockNum, B); RecNum = 1; MarkUsed (B, RecNum); // Start a free list NextBlockUpdate (B, NULL); PrevBlockUpdate(B, NULL); Freelist = BlockNum; WriteBlock (F, BlockNum, B) }} // end GetSlot

void FreeSlot (F, BlockNum, RecNum){ ReadBlock (F, BlockNum, B); if (BlockFull (B)) { // add to Freelist MarkUnused (B, RecNum); NextBlockUpdate (B, Freelist); PrevBlockUpdate (B, NULL); WriteBlock (F, BlockNum, B); ReadBlock (F, Freelist, B); PrevBlockUpdate (B, BlockNum); WriteBlock (F, Freelist, B); Freelist = BlockNum; } else { MarkUnused(B, RecNum); if (BlockEmpty(B)) { // detach from FreeList and return block to system } }} // end FreeSlot

3 Insert (TIndex, TData, NewItem, Success)// Insert into TData the NewItem and update the index. Find an empty slot // in TData;if no empty slot, get a new block. At this point, we would // use GetSlot to find anempty record: see Exercises 2 and 8.{ P = NumberOfBlockWithEmptySlot; ReadBlock (TData,P,D); D[EmptySlotNumber] = NewItem; WriteBlock (TData,P,D);

// apply hash function to NewItem's key I = hash (NewItem.Key); // get first block on chain of index blocks Q = T[I]; if (Q == 0) { // no items hashed there so far AllocateBlock (TIndex,Q);

Page 146: Excersize DataStructure

146

ReadBlock (TIndex, Q, B); B[1] = <NewItem.Key, P>; // P is TData block that NewItem is in T[I] = Q; // attach new block to hash table WriteBlock (TIndex, Q, B) } else { ReadBlock (TIndex, Q, B); while ((Q!=0) && (there_is_no_EmptySlot_in_Q)) { Q = block_number_of_NextBlock_on_chain; if (P != 0) ReadBlock (TIndex, Q, B) } if (Q != 0) { // block with empty slot B[J] = <NewItem.Key,P>; WriteBlock (TIndex,Q,B); } else { // allocate a new block AllocateBlock (TIndex,Q); ReadBlock(TIndex,Q,B); // attach Q to beginning of chain B[ptr] = T[I]; // the block must contain an indicator of the next block T[I] = Q; B[1] = <NewItem.Key,P>; WriteBlock (TIndex, Q, B); } // end else Q != 0 } // end else Q == 0} // end Insert

Delete (TIndex, TData, X, Success)// Delete item with key X from TData file, and update TIndex file.// Find the item as described in the Retrieve pseudocode in the text.{ if (P != 0) { // the item is present BlockNum := block_number_of_data_file_pointed_to_by_B[J]; mark_B[J]_deleted_and_do_whatever_memory_mgmt_is_appropriate;

// At this point, we would call FreeSlot. See Exercises 2 and 8. WriteBlock(TIndex,P,B);

// read in the appropriate block from the data file ReadBlock(TData, BlockNum, D); find_data_record_D[K]_with_search_key_X; mark_D[K]_deleted_and_do_appropriate_memory_mgmt; WriteBlock(TData,BlockNum,D); Success = true; } else Success = false} // end Delete

4 B-tree of order 5 (starting with the empty tree):

TableInsert (10) 10

Page 147: Excersize DataStructure

147

TableInsert (100) 10 | 100

TableInsert (30) 10 | 30 | 100

TableInsert (80) 10 | 30 | 80 | 100

TableInsert (50) 50

10 | 30 80 | 100

TableDelete (10) 30 | 50 | 80 | 100

TableInsert (60) 60

30 | 50 80 | 100

TableInsert (70) 60

30 | 50 70 | 80 | 100

TableInsert (40) 60

30 | 40 | 50 70 | 80 | 100

TableDelete (80) 60

30 | 40 | 50 70 | 100

TableInsert (90) 60

30 | 40 | 50 70 | 90 | 100

TableInsert (20) 60

20 | 30 | 40 | 50 70 | 80 | 90 | 100

TableDelete (30) 60

20 | 40 | 50 70 | 80 | 90 | 100

TableDelete (70) 60

20 | 40 | 50 80 | 90 | 100

Page 148: Excersize DataStructure

148

5 InorderSuccessor (TIndex, X, B, Succ, SuccBlock, SuccBlockNum)// Return in Succ the key value of the inorder successor of X. B contains // the blockcontaining X; SuccBlock contains the block containing Succ, // and SuccBlockNumcontains the block number of SuccBlock. If we do not // want to assume the blockcontaining X has already been read in, we can // pass in rootnum instead of B insteadof C. However, in order to swap X // with its inorder successor, it is useful to haveboth blocks in// memory.{ K = the_key_position_of_X; // 1..m-1 for an order m tree SuccBlockNum = block_number_containing_the_root_of_the_subtree _immediately_following_K; if (SuccBlockNum != 0) // if there is a subtree { ReadBlock(TIndex, SuccBlockNum, SuccBlock); SuccBlockNum = the_block_number_of_the_root_of_the_0th_subtree; while (SuccBlockNum != 0) { ReadBlock (TIndex, SuccBlockNum, SuccBlock); SuccBlockNum = the_block_number_of_the_root_of_the_0th_subtree; }

// When this loop exits, we're at the leftmost leaf of the// subtree immediately to the right of X. The leftmost key value// will be the inorder successor of X.

Succ = the_first_key_in_SuccBlock; } else // there is no right subtree { SuccBlockNum = 0; if (X_is_not_the_m-1th_key) Succ = Key_immediately_to_right_of_X; // else there is no inorder successor } // end InorderSuccessor

6 Pseudocode implementation of Insert for a table implemented with an index file organized as a B-tree oforder m. The deletion algorithm would similarly parallel the 2-3 tree deletion algorithm presented in thetext. An actual implementation would be complicated by memory considerations such as how many blockscan be in memory at one time.

Insert (TIndex, TData, NewItem);// Insert NewItem into table stored in TData and update index stored in // TIndex.{ X = search_key_of_NewItem; find_a_free_slot_in_TData; // use memory management routines // At this point, call GetSlot (see Exercises 2 and 8)

// B is the block number of the block in TData with a free slot ReadBlock (TData, B, D); D[J] = NewItem; // J is the free slot in block B WriteBlock (TData, B, D);

// update index locate_the_leaf_block_L_in_TIndex; // see Retrieve in text ReadBlock (TData, L, B); conceptually_add_NewItem_to_L;

if (L_now_has_m_items) Split(L);} // end Insert

Split (N)// Split node in block N, which contains m items. If N is an

Page 149: Excersize DataStructure

149

// internal node, then it has m+1 children.{ P := parent_of_N; // if N is the root, then get a new block for P

replace_N_by_two_blocks (N1, N2); // Note: we may have to be careful here, depending on how many blocks // can be in memory at one time. // give N1 the m div 2 items in N with smallest search key values // give N2 the m div 2 items in N with largest search key values if N (contains_an_internal_node) { // N1 becomes the parent of N's (m+1) div 2 leftmost children // N2 becomes the parent of N's (m+1) div 2 rightmost children } send_to_P(key_in_N_with_the_middle_search_key_value);

if (P_now_has_m_items) Split(P);} // end Split

7 RangeQuery (TIndex, RootNum, Low, High, Visit);// Visit (external function) the key values between Low and High// contained in TIndex, which is organized as a B-tree of order m.// Rootnum is the block number in TIndex of the root of the B-tree.{ ReadBlock (TIndex, RootNum, B); if (RootNum_is_a_leaf) { for (each_Key_value_in_leaf) if ((Key >=Low) and (Key <= High)) Visit (Key); } else // internal node { if (Low < Key1_of_the_root) RangeQuery (TIndex, subtree 0, Low, High, Visit); if (Key1 >= Low) && (Key1 <= High) Visit (Key1); for (I=1;I<number_of_keys_in_root-1; I++) { if (High >= Key[I]) || (Low <= Key[I+1]) // if any values in the I-th subtree are in the range RangeQuery (TIndex, subtree I, Low, High, Visit); if (Key[I+1] >= Low) && (Key[I+1] <= High) Visit (Key[I+1]); } if (High >> last_Key_in_root) RangeQuery(TIndex,last subtree in root,Low,High,Visit); }} // end RangeQuery

8 See Exercises 3 and 6. The locations for the memory management calls are indicated.

Page 150: Excersize DataStructure

150

9 This algorithm performs one block access per leaf plus for each internal node, one block access persubtree rooted at that node.

Traverse (BlockNum);// Traverse the index file of a B-tree in sorted order. BlockNum is the// block number of the root of the B-tree in the index file. B is a// global array—if it were local to Traverse, it would be part of the// recursive stack, and in this implementation, we're assuming that there// is not enough memory to accommodate a recursive stack containing h// blocks.{ // read the root into internal global array B if (BlockNum != 0) { ReadBlock (TIndex, BlockNum, B);

// traverse the children P = block_number_of_the_0th_child_of_B; Traverse(P);

// we must read in the block again only if // there is a subtree at the I-1st position for (I=1; I<m, I++) { if (P != 0) ReadBlock(TIndex, BlockNum, B); print(Key_Ki_of_B); P = block_number_of_the_ith_child_of_B; Traverse (P); } }} // end Traverse

10a Replace each Visit(Key) in Exercise 7 with

PData = pointer_in_Key_index_record_of_B;ReadBlock (TData, PDta, D);extract_from_D_the_data_record_with_appropriate_search_Key;Visit (data record); // where Visit is defined elsewhere

b If the data file records are sorted, one does not need to use the index file to traverse the records insorted order except possibly to get the block number of the first block in the data file. For RangeQuery , weneed to get the block number of the first block containing keys in the range.

Traverse (TIndex, TData, RootNum)// find the smallest Key in the index{ ReadBlock (TIndex, RootNum, B); P = block_number_of_the_root_of_the_0th_subtree; while (P != 0) ReadBlock (TIndex,RootNum,B); // traverse the data file PData = pointer_in_the_first_index_record_of_B; for (I=PData;I<=LastBlock;I++) // may want special case for last block which may not be full { ReadBlock(TData,I,D); for (J=0; J<RecordsPerBlock; J++) Visit(D[J]); }} // end Traverse

RangeQuery (TIndex,TData, Low, High, RootNum){

Page 151: Excersize DataStructure

151

ReadBlock (TIndex, RootNum, B); locate_the_leaf_where_Key_value_Low_would_be; find_first_Key_value_higher_than_Low; PData = pointer_in_the_appropriate_index_record of_B; Done = FALSE; while(!Done) { ReadBlock(TData,PData,D); J = location_of_the_first_record_in_D_with_Key_not_smaller_than_Low; while ((J <= RecordsPerBlock) && (D[J].Key <= High)) { Visit D[J]; J++; } PData++; Done = ((J != RecordsPerBlock) && (PData > LastBlock)); }} // end RangeQuery

c TableInsert (TIndex, TData, NewItem) where X is the search key of NewItem . SinceTData is now kept sorted, it is no longer possible to use any free slot to insert NewItem . It isprobably easier to insert NewItem’s Key into the index, find the inorder predecessor’s data blocknumber, and insert NewItem into that block (or successor blocks) in the data file, allocating a newblock if necessary.

Inserting into the data file can be done using the shift data algorithm developed in Exercise 1, with thefollowing differences:

We are shifting only until the end of the chain rather than the end of file, and we cannot assume that the lastblock in the chain will have room (it is possible that we must call AllocateBlock ).

Deleting from the data file now involves moving records to fill the empty slot. This could involvemoving records across block boundaries (similar to the shifting data necessary in TableInsert ),and could result in returning a block to the system if the last block in the chain becomes empty.

TableRetrieve need not be changed much; the function may need to search a chain of blocks to find thecorrect item.

TraverseTable and RangeQuery can take advantage of the sorted chains of blocks to do fewer blockaccesses than would be necessary if the data file were kept unsorted. For a traverse, use the B-tree to findthe location of first record. Visit each record in the chain (one or more block reads, depending on the lengthof the chain), and note the key value of the last record. Using the B-tree, find the inorder successor of thatkey value, and traverse the chain starting with that value. Repeat the process until all records have beenvisited. The same process can be used for RangeQuery , except that we start at Low and continue until wereached High .

11 Sort size elements in array A using an iterative merging technique. We start by merging runs of sizeone (already sorted) into sorted runs of size 2, then of size 4, etc.

Page 152: Excersize DataStructure

152

void Merge(int S1, int F1, int S2, int F2, int S3, arrayType& Source, arrayType& Dest)

// Merge: Merge two runs in array Source and place in Dest (starting at// s3). The first starts at s1 and ends at F1; the second starts at F2// and ends at s2. Assumptions: each run is sorted{ if (F2 > Size) F2 = Size; while ((S1 <= F1) && (S2 <= F2)) { if (Source[S1] <= Source[S2]) { Dest[S3] = Source[S1]; S3++; S1++; } else { Dest[S3] = Source[S2]; S3++; S2++; } } while (S1 <= F1) { Dest[S3] = Source[S1]; S3++; S1++; } while (S2 <= F2) { Dest[S3] = Source[S2]; S3++; S2++; }} // end Merge

void Mergesort (arrayType& A, int Size){ int RunSize; arrayType B; // Mergesort needs extra storage boolean Which; int I, P, Q, R; Which = TRUE;

// Flag to distinguish the source array from the destination array. // True indicates A is source; false indicates B is source. RunSize = 1; while (RunSize < Size) { P = 1; // pointer to beginning of first run Q = P + RunSize; // pointer to beginning of second run R = P; // pointer to location in second array to place merged run while (Q <= Size) { if (Which) Merge (P, (P+RunSize-1), Q, Q+RunSize-1, R, A, B) else Merge (P, (P+RunSize-1), Q, Q+RunSize-1, R, B, A); P = P + (RunSize * 2); Q = P + RunSize; R = P; } RunSize := RunSize * 2; Which = !Which; } // end while RunSize < Size if (!Which) // sorted array is in B for (I=0; I<Size; I++) A[I] = B[I];} // end MergeSort

Page 153: Excersize DataStructure

153

Review of C++ Fundamentals

1 char WhatTypeOfTriangle(int Side1, int Side2, int Side3){ char TriangleType;

if ((Side1 == Side2) && (Side2 == Side3))TriangleType = ‘E’;

else if((Side1 == Side2) || (Side1 == Side3) || (Side2 == Side3))TriangleType = ‘I’;

elseTriangleType = ‘S’;

return TriangleType;}

2 int QualityPointValue(char LetterGrade){ int QPV;

switch(LetterGrade) { case ‘A’: case ‘a’: QPV = 4; break; case ‘B’: case ‘b’: QPV = 3; break; case ‘C’: case ‘c’: QPV = 2; break; case ‘D’: case ‘d’: QPV = 1; break; case ‘F’: case ‘f’: QPV = 0; break; case ‘I’: case ‘i’: QPV = 0; break; default: QPV = -1; break; } return QPV;}

3 #include <iostream.h>#include <iomanip.h>

int GradeCount = 0, QPV;double QPVSum = 0.0;char LetterGrade;cout << “Enter a letter grade: ”;cin >> LetterGrade;while((LetterGrade != ‘Q’) || (LetterGrade != ‘q’)){ QPV = QualityPointValue(LetterGrade); if (QPV<0) cout << “Invalid letter grade.” << endl; else { QPVSum += (float)QPV; ++GradeCount; } cout << “Enter a letter grade: ”; cin >> LetterGrade;}if (GradeCount > 0){ cout.setf(ios::showpoint); cout << “Your quality point average is: ”; cout << setprecision(2) << (QPVSum/(float)GradeCount) << endl;}else cout << “You did not enter any grades.” << endl;

Appendix A

Page 154: Excersize DataStructure

154

4 After the character ‘Y’ is read into Response , the characters ‘E’ and ‘S’ are still in the input stream. Thenext time the cin stream variable is assigned a value, it is assigned the character ‘E’. The ‘E’ in this casewill cause the loop to terminate.

5a To map the two-dimensional array into a one-dimensional array as described in Part a of this exercise, usethe following formula:

ArrayIndex = ColumnIndex * TheNumberOfRows + RowIndex

Therefore, in this example 11 * 7 + 5 = 81.

5b To map the two-dimensional array into a one-dimensional array as described in Part b of this exercise, usethe following formula:

ArrayIndex = RowIndex * TheNumberOfColumns + ColumnIndex

Therefore, in this example 4 * 52 + 11 = 219.

6 double Average(weekType Week){ double Total = 0.0;

for (int i = 0; i < DAYS_PER_WEEK; i++) Total += Week[i]; return (Total/(double)DAYS_PER_WEEK);}

7 char* CreateName(char *FirstName, char *LastName){ // length of new string must allow for the space between // the names as well as the null terminator. int Length = strlen(FirstName) + strlen(LastName + 2; char *Result = new char[Length];

strcpy(Result, FirstName); strcat(Result, “ “); strcat(Result, LastName);

return Result;} // end CreateName

8a Repeating Self-Test Exercise 9:

a. CSC212[3].Address.State;

b. CSC212[3].Address.Zip[0];

c. CSC212[3].GPA;

d. CSC212[3].Address.Name[0];

8b for (int I = 0; I < MAX; I++){ cin >> NewName; strncpy(CSC212[I].Name, NewName, NAME_LENGTH);} // end for

Page 155: Excersize DataStructure

155

Page 156: Excersize DataStructure
Page 157: Excersize DataStructure

157

11 Note the following function assumes that the input files have at least one integer.

void MergeTwoSortedFiles(nameType InFileName1, nameType InFileName2, nameType OutFileName)

{ ifstream InFile1(InFileName1); ifstream InFile2(InFileName2); ofstream OutFile(OutFileName); int X1, X2; boolean Done = false;

cout << “Merging the files, ” << InFileName1 << “ and ” << InFileName2; cout << “, into one file, ” << OutFileName << endl; InFile1 >> X1; // get the first integer in each file InFile2 >> X2;

while(Done == false) { if (X1 < X2) { OutFile << X1 << endl; if (InFile1.peek() == EOF) Done = true; else InFile1 >> X1; } // end if else { OutFile << X2 << endl; if (InFile2.peek() == EOF) Done = true; else InFile2 >> X2; } // end else } // end while

while(InFile1.peek() != EOF) { InFile1 >> X1; OutFile << X1 << endl; }

while(InFile2.peek() != EOF) { InFile1 >> X2; OutFile << X2 << endl; }

InFile1.close(); InFile2.close(); OutFile.close();} // end MergeTwoSortedFiles

12 void AdvanceTo(ifstream& F, char Target){ boolean Found = false; char Ch;

while((Found == false) && F.get(Ch)) if (strcmp(Target, Ch) == 0) Found = true;

if (!Found) cout << “The character ” << Target << “ is not in the file.” << endl;} // end AdvanceTo

Page 158: Excersize DataStructure

158

13a void AppendTwentyIntegers(char *Filename){ ofstream Outfile(Filename, ios::app); int Temp;

for (int I = 1; I <= 20; ++I) { cout << “Enter integer “ << I << “: “; cin >> Temp; Outfile << Temp << endl; } // end for} // end AppendTwentyIntegers

13b void AppendTwentyIntegers(char *Filename){ ifstream Infile(Filename); ofstream Outfile(“temp.txt”); char Temp;

// read in original file while(Infile.get(Temp)) Outfile << Temp;

for (int I = 1; I <= 20; ++I) { cout << “Enter character “ << I << “: “; cin.get(Temp); Outfile << Temp << endl; } // end for

Infile.close(); Outfile.close();

// copy the temp file to the original Infile.open(“temp.txt”); Outfile.open(Filename);

while(Infile.get(Temp)) Outfile << Temp;} // end AppendTwentyIntegers

Page 159: Excersize DataStructure

159

Mathematical Induction

1 Inductive basis: The first positive even integer is 2 = 1(1 + 1), where n = 1

Inductive hypothesis: Let the sum of the first n positive even integers be n( n

Now, (n + 1)(n + 2) = n(n + 1) + 2(n + 1), where 2(n + 1) is the (n + 1)st ev eAnd so the identity is proved.

2 Prove: 1 2 + 2 2 + … + n 2 = n(n + 1)(2n + 1)/6.

Inductive basis: For n = 1, 1(1 + 1)(2(1) + 1)/6 = 6/6 = 1 = 1 2.

Inductive hypothesis: Let 1 2 + 2 2 + … + n 2 = n(n + 1)(2n + 1)/6.

Now, 1 2 + 2 2 + … + n 2 + (n + 1) 2 = n(n + 1)(2n + 1)/6 + (n + 1) 2 by hypothesi = (n + 1)/6[n(2n + 1) + 6(n + 1)] = (n + 1)/6[2n 2 + n + 6n + 6] = (n + 1)/6[2n 2 + 7n + 6] = (n + 1)/6(n + 2)(2n + 3) = (n + 1)[(n + 1) + 1][2(n + 1) + 1]/6.

3 Prove: 2n + 1 < n 2 for all n ≥ 3.

Inductive basis: For n = 3, 2(3) + 1 = 7 < 9 = 3 2.

Inductive hypothesis: Let 2n + 1 < n 2 for all n ≥ 3.

Now, 2(n + 1) + 1 = 2n + 3 ≤ 2n + n since n ≥ 3 < 2n + n 2

< n 2 + 2n + 1 = (n + 1) 2.

4 Prove: n 3 - n is divisible by 6 for all n ≥ 0.

Lemma: n 2 + n is divisible by 2 for all n ≥ 0.

Inductive basis: For n = 0, 0 2 + 0 = 0 = 0*2.

Inductive hypothesis: Assume 2 | (n 2 + n) such that n 2 + n = 2k for som e

Now, (n + 1) 2 + (n + 1) = n 2 + 2n + 1 + n + 1 = (n 2 + n) + (2n + 2) = 2k + 2(n + 1).

Appendix D

Page 160: Excersize DataStructure

160

Inductive basis: For n = 0, 0 3 - 0 = 0 = 0*6.

Inductive hypothesis: Assume 6 | (n 3 - n) such that n 3 - n = 2j for some inte g

Now, (n + 1) 3 - (n + 1) = (n 3 + 3n 2 + 3n + 1) - (n + 1) = (n 3 - n) + (3n 2 + 3n) = (n 3 - n) + 3(n 2 + n) = 6j + 3(2k) = 6(j + k).

5 Prove: 2 n > n 3 when n ≥10.

Inductive basis: For n = 10, 2 10 = 1024 > 1000 = 10 3.

Inductive hypothesis: Assume 2 n > n 3.

Now, 2 n+1 = 2(2 n) > 2n 3 = n 3 + n 3

> n 3 + 3n 2 + 3n + 1 since n ≥10 = (n + 1) 3.

6 Prove: n! > n 3 when n is large enough.

Inductive basis: For n = 6, 6! = 720 > 216 = 6 3.

Inductive hypothesis: Assume n! > n 3.

Now, (n + 1)! = (n + 1)n! > (n + 1)n 3 by hypothesis = n 4 + n 3

> n 3 + 3n 2 + 3n + 1 since n ≥ 6 = (n + 1) 3.

7a Prove: C(n, 0) + C(n, 1) + … + C(n, n) = 2 n.

Inductive basis: For n = 1, C(1, 0) + C(1, 1) = 1 + 1 = 2 = 2 1.

Inductive hypothesis: Assume C(n, 0) + C(n, 1) + … + C(n, n) = 2 n.

Now, C(n + 1, 0) + C(n + 1, 1) + … + C(n + 1, n + 1)= C(n, 0) + C(n, 0) + C(n, 1) + … + C(n, n) + C(n, n + 1)= [C(n, 0) + C(n, 1) + … + C(n, n)] + [C(n, 0) + C(n, 1) + … + C(n, n)]= 2 n + 2 n + 0 = 2(2 n) = 2 n+1.

7b Prove: ( )x y C n k x yn k n k

k

n

+ = −

=∑ ( , )

0

.

Inductive basis: For n = 1, (x + y) 1 = x + y = x 1 + y 1 = x 1y 0 + x 0y 1 = C k x yk k

k

(, )1 1

0

1−

=∑

Inductive hypothesis: Assume the identity holds for n.

Now, ( ) ( )( )x y x y x yn n+ = + ++1

Page 161: Excersize DataStructure

161

= +− −

==∑∑x C n k x y y C n k x yk n k k n k

k

n

k

n

( , ) ( , )00

= ++ − − +

==∑∑ C n k x y C n k x yk n k k n k

k

n

k

n

( , ) ( , )1 1

00

= ++ − − +

==

+

∑∑C n k x y C n k x yk n k k n k

k

n

k

n

( , ) ( , )1 1

00

1

= + + −

=

+

∑C n k x yk n k

k

n

( , )1 1

0

1

.

8 Prove that Rabbit(n) ≤an - 1 when n ≥ 1 and a = (1 + 5 )/2.

Inductive basis: Rabbit(1) = 1 ≤ 1 = [(1 + 5 )/2] 0 = [(1 + 5 )/2] 1 - 1 .

Inductive hypothesis: Assume Rabbit(n) ≤an - 1 .

Now, Rabbit(n + 1) = Rabbit(n) + Rabbit(n - 1) ≤ a n - 1 + a (n - 1) - 1

= a n - 1 + a n - 2

= a n - 2 (a + 1)

= a n - 2 ((1 + 5 )/2 + 1)

= a n - 2 ((3 + 5 )/2)

= a n - 2 ((6 + 25)/4)

= a n - 2 ((1 + 5 )/2) 2

= a n - 2 a2

= a n

= a (n + 1) - 1 .

9 For n = 0, R(n) = 2. Let R(n) = 2 n+1. Assume this is true for n.Then, R(n + 1) = 2 (n+1)+1 = 2(2 n+1) = 2R(n).