31
Solutions Manual to accompany Fundamentals of Data Structures in C++ Dinesh P. Mehta

Solutions Manual

Embed Size (px)

Citation preview

Page 1: Solutions Manual

Solutions Manual to accompany

Fundamentals of

Data Structures in C++

Dinesh P. Mehta

Page 2: Solutions Manual

Chapter 1

BASIC CONCEPTS

1.3.1

Predecessor(x):NaturalNumber ::= if (x == 0) then Predecessor = x

else Predecessor = x−1

IsGreater(x,y):Boolean ::= if (x > y) IsGreater:= true

else IsGreater = false

Multiply(x,y):NaturalNumber ::= if (x ∗ y ≤ MAXINT) then Multiply = x ∗ y

else Multiply = MAXINT

Divide(x,y):NaturalNumber ::= if (y == 0) then Divide = MAXINT

else Divide = x / y

1.3.3

ADT Bag is

objects: A collection of items where the items are in the subrange

of integers starting at 0 and ending at MAXINT on the computer.

functions:

for all i ∈ (0,MAXINT)

Create () ::= Declare an array A of dimension MAXINT starting at 0.

for (int i=0; i < MAXINT; i++) A[i] = 0

Insert(i) ::= if (A[i] ≤ MAXINT) A[i]++

Remove(i) ::= if (A[i] == 0) Remove = NULL

else Remove = i

IsIn(i) ::= if (A[i] == 0) IsIn = false

else IsIn = true

end Bag

1

Page 3: Solutions Manual

2 1 BASIC CONCEPTS

1.5.1

void horner (){

int ∗a, n, x, out;cout � "Input n, the coefficients, and x " � endl; // 1cin � n; // 1a = new int[n+1]; // 1for (int loop = 0; loop ≤ n; loop++) // n+2

cin � a[loop]; // n+1cin � x; // 1for (loop = n, out = 0; loop ≥ 0; loop−−) // n+2

out = out ∗ x + a[loop]; // n+1cout � out � endl; // 1

}

The comments at the end of each statement indicate how many times it was executed.

1.5.3

The trace for x = 13 is shown (the others are similar):Initially, i = 0 and j = 9.Iteration 1: k = 4. a[4] = 10, so condition of if statement evaluates to true and i becomes 5.i ≤ j, so repeat loop.Iteration 2: k = 7. a[7] = 16, so condition of if statement evaluates to false and j becomes6. i ≤ j, so repeat loop.Iteration 3: k = 5. a[5] = 12, so condition of if stmt evaluates to true and i becomes 6. i ≤ j,so repeat loop.Iteration 4: k = 6. a[6] = 14, so condition of if stmt evaluates to false and j becomes 5.i > j, so exit the program.

1.5.6

Recursive Versionint factorial (int n){

if (n ≤ 1) return 1;else return (n ∗ factorial(n−1));

}

Iterative Versionint factorial iter (int n){

int output = 1;

Page 4: Solutions Manual

1 BASIC CONCEPTS 3

for (int i = n; i > 1; i−−) output ∗= i;return output;

}

1.5.8

int Binomial Coeff (int n, int m){

if (m == 0 || m == n) return 1;else return (Binomial Coeff(n−1, m) + Binomial Coeff(n−1, m−1));

}

Time and Space RequirementsTime required = (2 * BinomialCoeff(n,m) - 1)* t where t is the time required for executing

the BinomialCoeff function once.Space required = c * (BinomialCoeff(n,m) -1) where c is the stack space required for

storing the context.

1.5.10

Recursive Functionint Ackermann (int m, int n){

if (m == 0) return n+1;if (n == 0) return Ackermann(m−1, 1);return Ackermann(m−1, Ackermann(m, n−1));

}

Nonrecursive Algorithmint Ackermann (int m, int n) // Pseudocode{// Assume that there are two stacks available to us. stack2 can be thought of as result// stack where results are pushed for future use. This program can be written with one// stack but we use two stacks for clarity.

Initialize stack1 and stack2;push m and n into stack1;

do {pop n and m from stack1;

if (n is a special symbol) n = pop from stack2;// This means that the result has been stored in the result stack.

Page 5: Solutions Manual

4 1 BASIC CONCEPTS

if (m=0) push (n+1) onto stack2;else if (n=0)

push m−1 and 1 onto stack1;else {

push m−1 and special symbol onto stack1;push m and n−1 onto stack1;

}} while (stack1 is not empty);result = pop from stack2;return result;

}

1.5.12

void perfect (int n){

int stop = n/2, sum = 0;for (int i = 1; i ≤ stop; i++)

if (n % i == 0) sum += i;if (sum == n) cout � n � " is the sum of its divisors" � endl;else cout � n � " is not the sum of its divisors" � endl;

}

1.5.14

Set power(Set S, int n) // pseudo-code// S[n] gives the nth element of the set S{

if (n == 0) then return EmptySet;else {

Set Result = power(S,n−1);Set Power = Result;while (NotEmpty(Result)) {

Set temp = make set(S[n],DeleteElement(Result));Power = Union(Power,temp);// The first parameter to make set is an element and// the second parameter is a set. DeleteElement// deletes and returns one element from Result.// Since Result is a power set, DeleteElement returns// a set. make set returns the set obtained by inserting// S[n] into the set returned by DeleteElement

}return Power;

Page 6: Solutions Manual

1 BASIC CONCEPTS 5

}

}

1.7.1

The function n2 is a polynomial function of degree 2 whereas 2n/4 is an exponentialfunction. n2 = 2n/4, when n = 8, and n2 < 2n/4, when n > 8.

1.7.3

(a)

line s/e frequency total steps1 1 n + 1 n + 12 1 Σi=n

i=1 (i + 1) (n2 + 3n)/2

3 1 Σi=ni=1Σj=i

j=1(j + 1) n ∗ (n + 1) ∗ (2n + 1)/12 + 3n(n + 1)/4

4 1 Σi=ni=1Σj=i

j=1j n ∗ (n + 1) ∗ (2n + 1)/12 + n(n + 1)/4

Total number of steps = n ∗ (n + 1) ∗ (2n + 1)/6 + n(n + 1) + (n2 + 3n)/2 + n + 1.

(b)

line s/e frequency total steps1 1 1 12 1 n + 1 n + 13 0 0 04 1 n n5 1 n n6 0 0 0

Total number of steps = 3n + 2.

1.7.5

(a)

void Transpose(int ∗∗a, int n)

{for (int i = 0; i < n−1; i++) {

count++; // count is globalfor (int j =i+1; j < n; j++) {

count++;

swap(a[i][j],a[j][i]);

Page 7: Solutions Manual

6 1 BASIC CONCEPTS

count++;}count++; // for last time of for j

}count++; // for last time of for i

}

(b)

void Transpose(int ∗∗a, int n){

for (int i = 0; i < n−1; i++) {count += 2; // count is globalfor (int j = i+1; j < n; j++)

count += 2;}count++;

}

(c) The exact value of the count is n2 + n − 1 as shown in (d).

(d)

line s/e frequency total steps1 0 0 02 0 0 03 1 n n4 1 Σi=n−2

i=0 (n − i) n(n + 1)/2 − 15 1 Σi=n−2

i=0 (n − i − 1) n(n − 1)/26 0 0 0

Total number of steps = n2 + n − 1.

1.7.7

(a)

void Multiply(int ∗∗a, int ∗∗b, int ∗∗c, int m, int n, int p){

for (int i = 0; i < m; i++) {count++; // count is globalfor (int j = 0; j < p; j++) {

count++;

Page 8: Solutions Manual

1 BASIC CONCEPTS 7

c[i][j] = 0;count++;for (int k = 0; k < n; k++) {

count++;c[i][j] += a[i][k] ∗ b[k][j];count++;

}count++; // for last time of for k

}count++; // for last time of for j

}count++; // for last time of for i

}

The following program is written by simplifying the program above by removing thestatements.

void Multiply(int ∗∗a, int ∗∗b, int ∗∗c, int m, int n, int p){

for (int i = 0; i < m; i++) {count += 2; // count is globalfor (int j = 0; j < p; j++) {

count += 3;for (int k = 0; k < n; k++)

count += 2;}

}count++; // for last time of for i

}

The following is the step count table.

line s/e frequency total steps1 0 0 02 0 0 03 1 m + 1 m + 14 1 m(p + 1) m(p + 1)5 0 0 06 1 mp mp7 1 mp(n + 1) mp(n + 1)8 1 mpn mpn9 0 0 010 0 0 0

Total number of steps = 2mpn + 3mp + 2m + 1.

Page 9: Solutions Manual

8 1 BASIC CONCEPTS

(b) It is profitable to interchange the two outermost for loops when p < m. In that case thetotal number of steps becomes 2mpn + 3mp + 2p + 1.

1.7.9

(a) If 10n2+9 = O(n) then 10n2+9 ≤ cn for some positive constant c and for all n, n ≥ n0 bydefinition. We can disprove this in the following way: 10n2+9 ≤ cn ⇒ 10n2 ≤ cn ⇒ 10n ≤ c.Choosing n > max{n0, c/10}, we have a contradiction.

(b) As in the previous problem, we have to get c1, c2, and n0 such that c1n2 ≤ n2logn ≤ c2n

2

for all n, n ≥ n0. n2logn ≤ c2n2 ⇒ c2 ≥ log2n. Choosing n > max{n0, 2

c2}, there is acontradiction.

(c) c1n2 ≤ n2/logn ≤ c2n

2 for all n, n ≥ n0 for some positive constants c1 and c2. c1n2 ≤

n2/logn ⇒ log2n ≤ 1/c1, which is a contradiction because the left hand side increases as nincreases whereas the right hand side is a constant.

(d) If this is true, n32n+6n23n ≤ cn32n for some positive constant c and for all n, n ≥ n0. Thismeans 6n23n ≤ cn32n ⇒ 3n ≤ cn2n. Since n ≤ (1.1)n, we have 3n ≤ c(2.2)n ⇒ (3/2.2)n ≤ c.The left hand side increases as n increases whereas the right hand side is a constant whichis a contradiction. Hence, the equality is incorrect.

1.7.11

There are two for loops, one at line 3 and the other at line 7. While i goes from 0 ton − 1, k goes from (i + 1) to n − 1, so line 8 gets executed n − 1 times , n − 2 times, andso on. The total number of times line 8 is executed is (n − 1) + (n − 2) + ... + 1 which isn(n − 1)/2. No other line is executed more times than line 8. Hence, the execution time ofthe program SelectionSort is O(n2).

1.7.15

This program makes use of the procedures add and mult. In every call of mult there aren3 multiplications and n3 additions. In add there are n2 additions and 0 multiplications.Procedure mult has to be called 4 times, meaning 4n3 multiplications and 4n3 additions.Procedure add has to be called 2 times (including subtractions) which means additions goup by 2n2. Hence, the number of additions (including subtractions) is 2n2 + 4n3, and thenumber of multiplications is 4n3.

Page 10: Solutions Manual

Chapter 2

ARRAYS

2.1.1

int Rectangle::operator<(const Rectangle& s) {if (h ∗ w < s.h ∗ s.w) return 1;return 0;

}

2.1.5

#include <iostream.h>#include <math.h>

class Polynomial{friend ostream& operator� (ostream& os, Polynomial& p);friend istream& operator� (istream& is, Polynomial& p);public:

Polynomial(int c0 = 0, int c1 = 0, int c2 = 0) : c(c0), b(c1), a(c2) { }Polynomial operator+(const Polynomial& s) {

Polynomial sum; sum.a = a + s.a; sum.b = b + s.b; sum.c = c + s.c;return sum;

}float eval(float x) { return a∗x∗x + b∗x + c; }void roots();

private:int a, b, c;

};

ostream& operator�(ostream& os, Polynomial& p) {

9

Page 11: Solutions Manual

10 2 ARRAYS

os � "Polynomial is: " � p.a � "x^2 + " � p.b � "x + " � p.c � endl;return os;

}

istream& operator�(istream& is, Polynomial& p) {cout � "Enter coefficients of polynomial (a, b, c in that order)" � endl;is � p.a � p.b � p.c;return is;

}

void Polynomial::roots() {if (b∗b − 4∗a∗c ≥ 0) {

float r1 = (−b + sqrt(b∗b − 4∗a∗c))/ (2 ∗ a);float r2 = (−b − sqrt(b∗b − 4∗a∗c))/ (2 ∗ a);cout � "Roots are " � r1 � " and " � r2 � endl;

}else {

// use functions defined in 2.1.2Complex c1( (−b)/(2∗a), sqrt(4∗a∗c − b∗b)/(2∗a));Complex c2( (−b)/(2∗a), −sqrt(4∗a∗c − b∗b)/(2∗a));cout � "Roots are " � c1 � " and " � c2 � endl;}

}

2.2.1

#include <iostream.h>const int defaultSize = 100;const float defaultValue = 0.0;

class CppArray {friend ostream& operator�(ostream& , CppArray&);friend istream& operator�(istream& , CppArray&);public:

CppArray(int, float);CppArray(const CppArray&);∼CppArray();CppArray& operator= (const CppArray&);float& operator[] (int i);int GetSize();

private:int n;

Page 12: Solutions Manual

2 ARRAYS 11

float ∗cpparr;};

CppArray::CppArray(int size = defaultSize, float initvalue = defaultValue): n(size) {

cpparr = new float[n];for (int i = 0; i < n; i++)cpparr[i] = initvalue;

}

CppArray::CppArray(const CppArray& cp2) {n = cp2.n;cpparr = new float[n];for (int i = 0; i < n; i++)

cpparr[i] = cp2.cpparr[i];}

CppArray::∼CppArray() {delete [] cpparr;

}

CppArray& CppArray::operator= (const CppArray& cp2) {if (this 6= &cp2) { // for a = a

delete [] cpparr;n = cp2.n;cpparr = new float[n];for (int i = 0; i < n; i++)cpparr[i] = cp2.cpparr[i];

}return (∗this);

}

float& CppArray::operator[] (int i) {if (i ≥ 0 && i < n) return cpparr[i];else cerr � "Error" � endl;

}

int CppArray::GetSize() {return n;}

ostream& operator� (ostream& os, CppArray& cp) {for (int i = 0; i < cp.n; i++)

os � cp.cpparr[i] � " ";os � endl;return os;

Page 13: Solutions Manual

12 2 ARRAYS

}

istream& operator� (istream& is, CppArray& cp) {cout � "Please input array size followed by elements" � endl;is � cp.n;for (int i = 0; i < cp.n; i++)

is � cp.cpparr[i];return is;

}

2.3.1

ADT OrderedList isobjects: A set of pairs < index, value > where for each value of index there is a value fromthe set item. index is a finite ordered set of one dimension.functions:

for all A ∈ Array, x ∈ item, i, j, n ∈ integerCreate(size, item) : Array ::= declare an array of size size

and the array elements are of type item;n = 0;Length(A) : integer ::= Length = nRead(A)::= for (int j = 1; j <= n; j + +) cin >> A[i]Retrieve(A, i) : item ::= Retrieve = A[i]Store(A, i, x) ::= A[i] = xInsert(A, i, x) ::= if (n < size) then

for (int j = n; j >= i; j −−) A[j + 1] = A[j];A[i] = x; n + +;else error;

Delete(A, i, x) ::= if (n == 0) then errorelse for (int j = i; j < n; j + +) A[j] = A[j + 1];n −−;

endOrderedList

2.3.4

ostream& operator�(ostream& os, Polynomial& p) {os � "\t" � "Coef" � "\t" � "Exp" � endl;for (int i = p.Start; i ≤ p.Finish; i++)

os � "\t" � p.termArray[i].coef � "\t" � p.termArray[i].exp � endl;return os;

}

istream& operator�(istream& is, Polynomial& p) {

Page 14: Solutions Manual

2 ARRAYS 13

int numTerms;cout � "Enter number of terms in polynomial followed by (coef, exp) pairs" �

endl;is � numTerms;if (p.free + numTerms > MaxTerms) cout � "error" � endl;else {

p.Start = p.free; p.Finish = p.Start + numTerms − 1;p.free = p.Finish + 1;for (int i = p.Start; i ≤ p.Finish; i++)is � p.termArray[i].coef � p.termArray[i].exp;

}return is;

}

2.3.6

float Polynomial::eval(float x){

float result = 0.0;int power = 0; float value = 1.0; // value = x∗∗power

for (int i = Finish; i ≥ Start; i−−) {for (int j = 1; j ≤ termArray[i].exp − power; j++) value ∗= x;power = termArray[i].exp;result += termArray[i].coef ∗ value;

}return result;

}

2.4.1

The elements are stored row by row, and every row is stored in increasing order of thecolumn indices. By doing this we have imposed an order. We can do a binary search on theelements stored using this order to locate an arbitary element. The time required for thissearch will be O(log2(terms)). Since changing a value takes a constant amount of time, thetotal time is O(log2(terms)).

2.4.3

Page 15: Solutions Manual

14 2 ARRAYS

We will assume that the matrix is input in increasing order of the rows and that withinevery row the elements are ordered by increasing order of their column indices. The outputhas the same format as the input. The number of nonzero entries and matrix dimensionsare initially specified.

ostream& operator�(ostream& os, SparseMatrix& p) {os � "The matrix has " � p.Rows � " rows and " � p.Cols� " columns and contains " � p.Terms � " terms:" � endl;for (int i = 0; i < p.Terms; i++) os � p.smArray[i].row � "\t"

� p.smArray[i].col � "\t" � p.smArray[i].value � endl;return os;

}

istream& operator�(istream& is, SparseMatrix& p) {cout � "Enter the number of rows followed by the number of columns" � endl;is � p.Rows � p.Cols;cout � "Enter the number of non-zero terms" � endl;is � p.Terms;if (p.Terms > MaxTerms) cout � "error" � endl;else

for (int i = 0; i < p.Terms; i++)is � p.smArray[i].row � p.smArray[i].col � p.smArray[i].value;

return is;}

The time complexity is O(number of nonzero entries) for each procedure.

2.4.5

Line 3 verifies that the matrices are compatible. Line 4 calls FastTranspose to producematrix bXpose. Matrix bXpose is the transpose of matrix b. Every row of a is multipliedwith every row of bXpose to produce the corresponding row of result. Note that a row ofbXpose corresponds to a column of b.

Now let us see how the while loops function to determine the correctness. There aretwo while loops, one starting at line 16 and the other at line 20. Each time the while loopat line 16 is iterated one row of d gets stored. We start with currRowIndex = 0 and weiterate until currRowIndex <=a.Terms. Every time we move to the next row in lines 53-54,where we increment currRowIndex, and in line 55, we assign currRowBegin to currRowIndex.currRowBegin keeps track of where the current row starts. This variable is used within thesecond while loop. The variable currRowA keeps track of row number we presently are usingto generate the matrix d. The value of currRowA is changed at lines 8 and 56 only, wherethey are initialized and updated properly. Hence, the row numbers of the elements we aregenerating are correct.

Page 16: Solutions Manual

2 ARRAYS 15

Having established that we are taking a single row and using that in each iteration ofthe while loop starting at line 16, let us see what happens within the while loop at line 20.The ideas used in the previous loop apply here too: We look at every row of matrix bXpose(which is equivalent of looking at every column of matrix b) and then generate items. Beforeentering the while loop of line 20, we initialize currColIndex to 0. Variable currColB pointsto the column (of b) we are looking at. If the term we are looking at has a row value that isgreater than the present value (of currRowA), then we have seen all the elements of the row.It does not matter whether we have seen the whole column; these items are going to be zero.Having done this in lines 22-25, we have to make the row pointer point to the beginning ofthe row which we do in line 26. Lines 28-29 make sure that the pointer currColIndex pointsto the next column and the present column value is stored in currColb.

Storesum stores the element that has a value equal to sum in d[LastInResult], whichhas a row value currRowA and a column value currColB only if sum is not equal to zero.LastInResult is incremented in the process. Note that sum is assigned the value zero.

We may run out of column values before we run out of row values, in which case we haveto make currRowIndex point to currRowbegin and we must change the column value. Thisis done in lines 37-38. Also, the sum is stored in the corresponding place by calling Storesumin line 34.

When we scan the row and column simultaneously, the value of sum is changed only ifthe column value of a and the row value of b (column value of bXpose) is the same. This ischecked in lines 44-45. If these values are the same, the sum is incremented and the pointerscurrRowIndex and currColIndex are incremented. If we are looking at a column value of athat is greater than the row value of b (column value of bXpose) we increment the pointercurrColIndex; otherwise we increment the pointer currRowIndex. These are done in lines 51and 43, respectively.

2.4.7

(a) To represent t nonzero terms we need t words. To store the two-dimensional array bitswe need dnm/we words. Total words needed = t + dnm/we.

(b) We assume that both matrices are compatible. Assume that each matrix has row, coldata members which contain the number of rows and columns, resp., of the matrix. bit[][] isthe bitmatrix and terms, the array of terms.

SparseMatrix operator+(const SparseMatrix& a, const SparseMatrix& b){

SparseMatrix c;c.row = a.row;c.col = a.col;int pta = 0, ptb = 0, ptc = 0;

for (int i = 0; i < c.row; i++)for (int j = 0; j < c.col; j++) {

Page 17: Solutions Manual

16 2 ARRAYS

c.bit[i][j] = a.bit[i][j] || b.bit[i][j];if (a.bit[i][j] && b.bit[i][j]) {

c.terms[ptc] = a.terms[pta]+b.terms[ptb];pta++; ptb++; ptc++;

}else if (a.bit[i][j]) {

c.terms[ptc] = a.terms[pta];pta++; ptc++;

}else if (b.bit[i][j]) {

c.terms[ptc] = b.terms[ptb];ptb++; ptc++;

}}

}Time complexity: There are two for loops and within the for loops a constant amount of

work is done. Hence, the time taken = O(mn), where mn = dimension of the matrices.

(c) We first consider the random access operation. Suppose we do not use a supplementaryarray: to access A[i][j], we first check bits[i][j] in O(1) time. If bits[i][j] is 0, then A[i][j] is0, and we are done. If not, we need to look up array v. To do this, we need to know theposition of v containing A[i][j]. This is obtained by counting the number of non-zero elementsthat precede A[i][j] in row-major order. This requires a scan of the bits array, which canconsume, in the worst case, O(mn) time. Suppose we use a supplementary array as specifiedin the problem statement: we immediately know the number of non-zero elements in rows0 through i − 1. It remains to find the number of non-zero elements in positions 0 throughj − 1 in row i. This requires a scan of row i of the bits array, requiring, in the worst case,O(n) time.

Addition takes O(mn) time, as described above. Multiplication takes O((mn + np)p)time using an additional O(n) space: suppose we need to get C = A.B, where A=m*n andB=n*p. The idea is to multiply the rows of A with the first column of B, using an additionalO(n) space to store the elements of the column. These elements are stored as the first row ofC. This is repeated with all columns of B. Finally, C is transposed to get the correct matrix.

The representation of Section 2.4 requires 3t words. It is better when the number ofnonzero elements in the matrix (t) is very small and the size of the matrix (mn) is large. Ift is large, the representation used in this exercise takes less space. Random access time isO(log t) with the representation of Section 2.4 (Exercise 2.4.1). Generally, when t is muchless than mn, the representation of Section 2.4 will outperform the representation in thisexercise. This can be intuitively understood from the fact that we do not have to look into alarge two-dimensional array for any of the operations. The exact analysis and the breakevenpoints cannot be determined unless we have the results of timing experiments.

2.5.2

Page 18: Solutions Manual

2 ARRAYS 17

In array a[0..n] we can store n+1 values. Array b[−1..n, 1..m] can hold m∗ (n+2) values,whereas array c[−n..0, 1..2] can hold 2n + 2 values.

2.5.3

The address of A[i1, i2, ..., in] is

α + Σj=nj=1 ij ∗ aj

where aj = Πk=nk=j+1(uj + 1) for 1 ≤ j < n and an = 1.

2.6.1

void String::Frequency()// Assume only characters a to z are allowed in the string{

int freq[26]; char temp = 'a';for (int i = 0; i < 26; i++) freq[i] = 0;for (i = 0; i < length; i++) freq[str[i]−'a']++;for (i = 0; i < 26; i++) {

cout � temp � ": " � freq[i];temp++;

}cout � endl;

}

2.6.3

String String::CharDelete(char c){

String delstring;int count = 0;for (int i = 0; i < length; i++)

if (str[i] == c) count++;delstring.length = length − count;delstring.str = new char[length−count];int j = 0;for (i = 0; i < length; i++)

if (str[i] 6= c) {delstring.str[j] = str[i];

j++;}

Page 19: Solutions Manual

18 2 ARRAYS

return delstring;}

2.6.5

int compare(const String& s, const String& t){

int m = s.Length(), n = t.Length(), min = n;if (m < n) min = m;

for (int i = 0; i < min; i++)if (s.str[i] > t.str[i]) return 1;else if (s.str[i] < t.str[i]) return −1;

if (m > n) return 1;else if (m < n) return −1;else return 0;

}

2.6.7

(a)

j 0 1 2 3 4pattern a a a a b

f −1 0 1 2 −1

(b)

j 0 1 2 3 4 5pattern a b a b a a

f −1 −1 0 1 2 0

(c)

j 0 1 2 3 4 5 6 7 8pattern a b a a b a a b b

f −1 −1 0 0 1 2 3 1 −1

2.6.9

Page 20: Solutions Manual

2 ARRAYS 19

(a)

j 0 1 2 3 4 5 6 7 8 9pat a b c a b c a c a bf −1 −1 −1 −1 −1 −1 3 −1 −1 1

(b)As before, if the character at the pattern matches the text, we increment PosP and

PosS (line 8). Consider the case when the pattern fails to match. Let PosP initially be iand let its new position be j. If pat.str[i] = pat.str[j], we are going to fail again becauses.str[PosS] 6= pat.str[i] and therefore s.str[PosS] 6= pat.str[j]. The strengthening conditionprevents failure in this case.(c)

void String::FailureFunction2(){

int LengthP = Length();int ∗temp = new int[LengthP];temp[0] = −1;for (int j = 1; j < LengthP; j++){

int i = temp[j−1];while((∗(str+j) 6= ∗(str+i+1)) && (i ≥ 0)) i = temp[i];if (∗(str+j) == ∗(str+i+1)) temp[j] = i + 1;else temp[j] = −1;

}

f[0] = −1;for (j = 1; j < LengthP; j++){int i = temp[j];while (i ≥ 0 && ∗(str+j+1) == ∗(str+i+1)) i = temp[i];if (∗(str+j+1) 6= ∗(str+i+1)) f[j] = i;else f[j] = −1;}delete [ ] temp;

}

It is easy to see from the bounds of the two for loops that the computing time remainsO(LengthP ).

(d) With the new definition of f, we have strengthened the failure function. Therefore, withthe new definition FastFind cannot take more time to run than it did with the old definition,it can take less time. For example take the pattern abcabcabcabcabc. Suppose part of the

Page 21: Solutions Manual

20 2 ARRAYS

text is abcabcabcabcabx. With the modified definition of f, when we fail to match x withc the failure function is −1, whereas with the old definition we have to match four timeswithin the pattern to arrive at the same result. Considering that the whole text contains thepiece of text shown above, the run time of the algorithm FastFind with the new definitionfor f is considerably faster than with the old definition.

2.8.1

void reverse(int ∗a; int n){

for (int i = 0; i < n/2; i++) {swap(a[i],a[n−i−1])

}}

2.8.2

class Matrix {private:

int m, n;int ∗∗a;

public:int saddle();

};

// Assume that there is a unique maximum in each column and a// unique minimum in each row.

int Matrix::Saddle(){

int ∗aux = new int[n]; // auxiliary array for storing the max element in each colfor (int j = 0; j < n; j++) { // find max element in column j

aux[j] = a[0][j]; // and store in aux[j]for (int i = 1; i < m; i++)if (aux[j] < a[i][j]) aux[j] = a[i][j];

}

for (int i = 0; i < m; i++) { // find min element in row i and store in minint min = a[i][0]; // minpos is the column number of the min elementint minpos = 0;for (j = 1; j < n; j++)if (min > a[i][j]) {

Page 22: Solutions Manual

2 ARRAYS 21

min = a[i][j];minpos = j;

}

// Check if min element in row i is max element of its column// If yes, then it is a saddle point.if (aux[minpos] == min) {cout � "Saddle point is " � i � " " � minpos � endl;delete [] aux;return 1;}

}delete [ ] aux;return 0;

}

The time complexity of the two nested for loops is O(mn).

2.8.4

The storage scheme is given in the hint. We will store the lower triangular matrix A asthe lower triangle of c, and the lower triangular matrix B is transposed (it then becomesupper triangular) and is stored as the upper triangular matrix of c.

The storage scheme then is

A[i][j] is stored in c[i][j], for i ≥ jB[i][j] is stored in c[j][i + 1], for i ≥ j

Algorithm retrieve(Matrix,i, j)if (Matrix == A) return c[i][j]else return c[j][i + 1]

2.8.6

(a) The main diagonal contains n elements. Let us count the number of elements in the lowerdiagonals(excluding the main diagonal). The first lower diagonal contains n − 1 elements,and the second lower diagonal contains n − 2 elements. Generalizing, we can say that the(a − 1)th diagonal contains n − (a − 1) elements, which is n − a + 1 elements. Hence, thetotal number of elements in the lower diagonals = (n − 1) + (n − 2) + . . . + (n − a + 1) =n(n−1)/2−(n−a)(n−a+1)/2. The total number of elements in the diagonals (excluding themain diagonal) is = 2[n(n−1)/2−(n−a)(n−a+1)/2], which is n(n−1)−(n−a)(n−a+1),which is simply (a− 1)(2n− a). Hence, the total number of elements is n + (a− 1)(2n− a).

Page 23: Solutions Manual

22 2 ARRAYS

Note that in the last term we are adding n elements from the main diagonal.

(b) If (i = j) then A[i][j] lies in the main diagonal.If (i > j and i − j = k), A[i][j] lies in the kth lower diagonal.If (i < j and j − i = k), A[i][j] lies in the kth upper diagonal.Thus the relationship between i and j can be summarized as |i − j| ≤ a − 1.

(c) There are three cases, as mentioned in (b). If (i = j), then all the lower diagonal elementsare stored first. The number of lower diagonal elements = (a−1)(2n−a)/2. Now, the addressof the element A[i][j] when (i = j) is i + [(a − 1)(2n − a)/2] − 1.

When (i > j) the element lies in one of the lower diagonals. If (i − j = k), for example,the element lies in the kth lower diagonal. The (a−1)th diagonal contains n−a+1 elements.All the elements in the diagonals (a − 1) through (k + 1) will be stored before the elementsin the kth lower diagonal are stored. In other words, (n− a + 1)+ . . . +(n− k− 1) elementsare stored earlier. That is, (a − 1 − k) ∗ (2n − a − k)/2 elements. Hence, the address of theelement A[i][j] is j + (a − 1 − k) ∗ (2n − a − k)/2 − 1.

Now we have to get the address of the elements when (i < j), that is, of the elementsthat reside in the upper diagonal. All the lower diagonal elements and the main diagonalelements will be stored before the upper diagonal elements are stored. That will be n +[(a − 1)(2n − a)]/2 elements. In the upper diagonal, the first upper diagonal contains n − 1elements, the second n− 2 elements, and so on. If the element is in the kth upper diagonal,then all elements from the first upper diagonal to the (k − 1)th upper diagonal are storedbefore the kth diagonal element. That is, (n − 1) + . . . + (n − k + 1) elements from theupper diagonal are stored before the kth upper diagonal elements. This is (k − 1)(2n− k)/2elements. Hence, the total number of elements stored before the kth upper diagonal elementsis n + (a − 1)(2n − a)/2 + (k − 1)(2n − k)/2. Also, the elements in the upper diagonal arestored in increasing order of their row number. Hence the address of A[i][j] is i + n + (a −1)(2n − a)/2 + (k − 1)(2n − k)/2 − 1.

We can combine these three cases and obtain the addressing formula for A[i][j] asAddress of A[i][j] = i + [(a − 1)(2n − a)/2] − 1, if i = j

= j + (a − 1 − k) ∗ (2n − a − k)/2 − 1, if i − j = k and k ≤ a − 1= i+n+(a−1)(2n−a)/2+(k−1)(2n−k)/2−1, if j− i = k and k ≤ a−1

Page 24: Solutions Manual

Chapter 3

STACKS AND QUEUES

3.3.1

template <class T>void Queue<T>::Push(const T& x){

if (front == rear && LastOp == "push") {// include code to double queue capacity here

}int rear = (rear + 1) % capacity;queue[rear] = x;LastOp = "push";

}

template <class T>void Queue<T>::Pop()// remove and return top element from queue{

if (front == rear && LastOp == "pop")throw "Queue is empty. Cannot delete";

front = (front + 1) % capacity;queue[front].∼T();LastOp = "pop";

}

3.3.6

We assume that we do not use the variable LastOp.

23

Page 25: Solutions Manual

24 3 STACKS AND QUEUES

(a) Number of elements = (rear − front) % capacity.

(b) The kth element of the list is the position (front + k)% capacity. Since the kth elementis deleted, all the elements residing in positions from (front+k+1)%capacity to rear shouldbe moved up by one position.

template <class T>void Queue<T>::DeleteK (int k)// Delete the kth element of the queue{

if ((rear−front) % capacity < k)throw "Less than k elements in queue";

x = queue[(front+k) % capacity];for (int i = k; (front+i) % capacity 6= rear; i++) // move elements one position

queue[(front+i)%capacity] = queue[(front+i+1) % capacity];rear = (rear−1) % capacity;

}(c)

The first k elements are shifted by one position, creating a space for the new element tobe inserted.

template <class T>void Queue<T>::AddK (const T& x, int k)// add x immediately after the kth element of the queue{

int newrear = (rear + 1) % capacity;if (front == newrear) {

// include code to double capacity here}if (k ≤ (rear−front) % capacity) {

front = (front−1) % capacity;for (int i = 1; i ≤ k; i++)

queue[(front+i)%capacity] = queue[(front+i+1)%capacity];queue[(front+k+1)%capacity] = x;

}else throw "Queue contains < k elements";

}The Time complexity for (b) and (c) is O(number of elements in the queue).

3.4.1

#include <iostream.h>int DefaultSize = 100;

template <class T>

Page 26: Solutions Manual

3 STACKS AND QUEUES 25

class Bag {friend ostream& operator�(ostream&, Bag<T>&);public:

Bag (int bagCapacity = DefaultSize); // constructorvirtual ∼Bag(); // destructor

virtual void Push(const T&);virtual void Pop();

virtual bool IsEmpty();

protected:T ∗array;int capacity; // size of arrayint top; // highest position in array that contains an element

};

template <class T>class Stack : public Bag<T> {public:

Stack (int stackCapacity = DefaultSize); // constructor∼Stack(); // destructorvoid Pop(); // delete element from bag

};

template <class Type>Bag<T>::Bag (int bagCapacity): capacity(bagCapacity) {

array = new T[MaxSize];top = −1;

}

template <class T>Bag<T>::∼Bag() {

delete [ ] array;}

template <class T>inline bool Bag<T>::IsEmpty() {

if (top == −1) return true;else return false;

}

template <class T>void Bag<T>::Push(const T& x) {

if (IsFull()) {

Page 27: Solutions Manual

26 3 STACKS AND QUEUES

// code to double capacity goes here}array[++top] = x;

}

template <class T>void Bag<T>::Delete() {

if (IsEmpty()) throw "stack is empty";int deletePos = top / 2;x = array[deletePos];for (int index = deletePos; index < top; index++)

array[index] = array[index + 1]; //compact upper half of arraytop−−;

}

template <class T>ostream& operator�(ostream& os, Bag<T>& b) {

for (int i = 0; i ≤ b.top; i++)os � b.array[i] � " ";

os � endl;return os;

}

template <class T>Stack<T>::Stack (int stackCapacity) : Bag<T>(stackCapacity) {}

template <class T>Stack<T>::∼Stack() {}

template <class T>

void Stack<T>::Pop() {if (IsEmpty()) throw "stack is empty";x = array[top−−];

}

3.4.4 (a) Yes. All rectangles are trapeziums. (b) No. (c) No. (d,e) Yes. Stacks and queuesare both ordered lists.

3.6.1

(a) AB ∗ C∗

Page 28: Solutions Manual

3 STACKS AND QUEUES 27

(b) AuB + C − D+, where u represents the unary minus

(c) ABu ∗ C+

(d) AB + D ∗ EFAD ∗ +/ + C+

(e) AB and C or EF > not or

(f) ABC < CD > or not and not CE < or

3.6.3

(a)

∗ ∗ ABC+ − +uABCD, where u represents the unary minus+ ∗ AuBC+ + ∗ + ABD/E + F ∗ ADCor or and ABC not > EFor not and A not or < BC > CD < CE

(b)

void eval(expression e)// Evaluate the prefix expression e. It is assumed that the first token// in e is ’#’. A procedure PrevToken is used to extract from e the next// token. We assume that we set the pointer to the last token in e initially.// A one-dimensional array stack is used as a stack{

Stack<token> stack; // initialize stackfor (token x = Lasttoken(e); x 6= '#'; x = PrevToken(e))

if (x is an operand) stack.Push(x) // add to stackelse { // operator

remove the correct operands for operator x from the stack;perform the operation x and store the result onto the stack;

}} // end of eval

(c) This is symmetric to the code of Program 3.19 in the text. The main difference is that wescan the infix expression from right to left. We define isp[’)’]= 8, icp[’)’]=0, and isp[’#’]=8.Also, since we cannot print from right to left, we use a stack outstack to reverse the output.

void InfixToPrefix(Expression e){

Page 29: Solutions Manual

28 3 STACKS AND QUEUES

Stack<Token> stack, outStack;Token y;stack.Push('#');for (Token x = LastToken(e); x 6= '#'; x = PrevToken(e)){

if (x is an operand) outStack.Push(x)else if (x=='(') // unstack until ’)’

for (; stack.Top() 6= ')'; stack.Pop()) outStack.Push(stack.Top());else { // x is an operator

for (; isp(stack.Top()) ≤ icp(x); stack.Pop())outStack.Push(stack.Top());

stack.Push(x);}

for(;!stack.IsEmpty();stack.Pop()) outStack.Push(stack.Top());for(;!outStack.IsEmpty()); cout � outStack.Top(), outStack.Pop());

} // end of InfixToPrefix

(b) and (c) have O(n) time complexity and O(n) space complexity.

3.6.5

We will assume that the postfix expression ends with a #. We use two stacks, S1 andS2, and a special flag that does not appear in the expression. The flag marks the end of anoperand. When we pop an operand from stack S1, we will need this flag to to tell us thatwe have reached the end of the operand. This is necessary because an operand could itselfbe an expression consisting of several characters. For simplicity, we assume that only binaryoperators are used.

void PostfixToPrefix(expression e){

Stack<token> S1, S2;token y;

for (token x = FirstToken(e); x 6= '#'; x := NextToken(e))if (x is an operand) {

S1.Push(flag); S1.Push(x);// flag marks the end of an operand

}else if (x is an operator)

// pop 2 opds from S1, put them on S2for (int i = 1; i ≤ 2; i++)

for (;S1.Top() 6= flag; S1.Pop())S2.Push(S1.Top());

Page 30: Solutions Manual

3 STACKS AND QUEUES 29

// The idea is to pop from the main stack and push into// the temporary stack until two flags are encountered.S1.Push(flag); // put flag back onto S1S1.Push(x); // put operator on S1

// put the two operands unstacked back onto S1while (!S2.IsEmpty())S1.Push(S2.Top());

S2.Pop();}

// The output is in reverse order. Use the other stack to invert itwhile (!S1.IsEmpty()) {

if (S1.Top() is not a flag) S2.Push(S1.Top());S1.Pop();

}

// Output in stack S2 in right order.while (!S2.IsEmpty()) {

cout � S2.Top();S2.Pop();

}

} // end of PostfixToPrefix

This algorithm takes time O(n2). The space taken is O(n). By making use of the listrepresentation, discussed in Chapter 4, we could make the run time O(n).

3.6.7

We will use two stacks S1 and S2. We will scan e from right to left. Assume that theleftmost token is ’#’. The idea used in 3.6.5 also applies to this algorithm. Assume binaryoperators.

Pre2fpIn(expression e){

Stack<token> S1, S2;token y;

for (token x = LastToken(e); x 6= '#'; x = PrevToken(e))if (x is an operand) {

S1.Push(flag);S1.Push(x);

Page 31: Solutions Manual

30 3 STACKS AND QUEUES

// flag marks the end of an operand}else if (x is an operator) {

S2.Push('(');// transfer first operand from S1 to S2for (; S1.Top() 6= flag; S1.Pop())

S2.Add(S1.Top());S2.Push(x); // place the operator in S2// transfer second operand from S1 to S2for (; S1.Top() 6= flag; S1.Pop())

S2.Push(S1.Top());S2.Push(')');

S1.Push(flag);// transfer entire expression from S2 to S1while (!S2.isEmpty())

S1.Push(S2.Top());S2.Pop();

}

// print fully parenthesized expressionwhile (S1.isEmpty()) {

if (S1.Top() 6= flag) cout � S1.Top();S1.Pop();

}} // end of Pre2fpIn