Professional Documents
Culture Documents
Standish Sol Manual Ece223
Standish Sol Manual Ece223
Standish Sol Manual Ece223
7.5
7.6
7.7
7.8
7.9
p.
p.
p.
p.
p.
50
53
56
56
59
i
iii
7.
2. It prints
5.
4.
Airport
N
Airport
Link
ORD
Link
GCM
Airport
Link
MIA
NULL
Airport
Link
MEX
5. strcpy(L>Link>Airport, "JFK");
6. N>Link = L>Link>Link; free(L>Link); L>Link = N;
2.
void DeleteFirst(NodeType **L)
{
NodeType *N;
if (*L != NULL) {
N = *L;
*L = (*L)>Link;
free(N);
}
}
3.
void InsertBefore(NodeType *N, NodeType *M)
{
AirportCode A;
/* insert node M after node N on list L */
M>Link = N>Link;
N>Link = M;
/* swap airport codes in N and M */
strcpy(A, N>Airport);
strcpy(N>Airport, M>Airport);
strcpy(M>Airport, A);
}
4.
NodeType *Copy(NodeType *L)
{
NodeType *N, *M, *L2;
if (L == NULL) {
return NULL;
} else {
/* initialization and copying of first node */
M = (NodeType *) malloc(sizeof(NodeType));
L2 = M;
N = L;
strcpy(M>Airport, N>Airport);
/* L2 points to the copy of the list L being constructed */
/* N is a pointer that steps along the nodes of L to copy */
/* M is a pointer that steps along the nodes of L2 that are copies */
5.
void Reverse(NodeType **L)
{
NodeType *R, *N;
R = NULL;
while (*L != NULL) {
N = *L;
*L = (*L)>Link;
N>Link = R;
R = N;
}
*L = R;
Airport
Right
Link
Left
Link
BRU
Airport
Right
Link
Left
Link
x2
ORD
Airport
SAN
Right
Link
k!(nk)!
6. Decompose a non-empty list into its Head (which is its first node)
and its Tail (consisting of the rest of the nodes on the list after
the first one).
2.
double Power(double x, int n)
{
double p;
if (n == 0) {
return 1.0;
}
}
3.
int Mult(int m, int n)
{
if (m == 1) {
return n;
} else {
return n + Mult(m 1, n);
}
}
P = (char *) malloc((1+strlen(S)+strlen(T))*sizeof(char));
temp = P;
while ((*P++ = *S++) != '\0')
;
P--;
while ((*P++ = *T++) != '\0')
;
return temp;
}
/* -------------------------------------------------------------- */
char *Reverse(char *S)
{
char *temp;
/* to Reverse a String S */
if (Empty(S)) {
/* the empty string is returned */
return EmptyString;
/* for the base case */
} else {
return Concat(Reverse(Tail(S)), Head(S));
}
}
/* ------------------------------------------------------------------------------ */
int main(void)
{
char *S = "abcdefg", *S1;
10.
int Min2(int A[ ], int m, int n)
{
int MinOfRest;
if (m == n) {
return A[m];
} else {
MinOfRest = Min2(A,m+1,n);
if (A[m] < MinOfRest) {
return A[m];
} else {
return MinOfRest;
}
}
}
int Min(int A[ ])
/* to find the smallest integer in an integer array A[0:n1] */
{
return Min2(A,0,n1);
}
11.
integer n in reverse
16.
int C(int n, int k)
/* where n and k are non-negative integers */
{
if ((k == 0) | | (n == k)) {
return 1;
}else {
return C(n1,k) + C(n1,k1);
}
}
3.1536*107.
85
90
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10
15
20
25
30
35
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10
15
20
|
|
|
|
|
|
|
|
|
#include <stdio.h>
#include <stdlib.h>
/* type definition section */
typedef struct RowTag{
int Amount;
int Repetitions;
15
20
25
30
35
40
45
50
55
60
65
70
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct RowTag*Link;
} RowStruct;
typedef RowStruct *RowStructPointer;
typedef int InputArray[6];
/* declarations of variables */
RowStructPointer Table = NULL;
InputArray A;
/* Program 5.5 */
void GetSixInputs(InputArray A)
{
int i;
}
}
/* Refinement of Program Strategy 5.7 */
void InsertAmount(int AmountToinsert)
{
RowStructPointer RowPointer;
int UpdateCompleted;
RowPointer = Table;
UpdateCompleted = 0;
75
80
85
90
95
100
105
110
115
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int i;
for (i = 0; i < 6; ++i) {
InsertAmount(A[i]);
}
}
/* Refinement of Program Strategy 5.8 */
void FindAndPrintWinner(void)
{
int AmountWon;
RowStructPointer RowPointer;
AmountWon = 0;
RowPointer = Table;
while (RowPointer != NULL) {
if ((RowPointer >Repetitions >= 3) &&
(RowPointer >Amount > AmountWon)) {
AmountWon = RowPointer >Amount;
} else {
RowPointer = RowPointer >Link;
}
}
printf("You Won $% d\n",AmountWon);
}
/* Refinement of Program Strategy 5.4 */
void FindWinningAmount(void)
{
GetSixInputs(A);
MakeTable(A);
FindAndPrintWinner();
}
int main(void)
{
FindWinningAmount( );
}
/* end of main */
10
15
20
25
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
* Priority Queue Lottery Solution to Exercise 5.2.3
*/
#include <stdio.h>
#include <stdlib.h>
#include "PQInterface.h"
/* type definitions */
typedef PQItem InputArray[6];
/* declarations of variables */
InputArray A;
PriorityQueue PQ;
/* Program 5.5 */
void GetSixInputs(InputArray A)
{
int i;
printf("Give six dollar amounts separated by spaces: ");
35
40
45
50
55
60
65
70
75
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
}
/* Exercise 5.2.2, pp. 153154 van Snipe's Short Lottery Solution */
/* assume the global InputAray A has been declared */
/* and is used in these routines */
int ThreeOrMore(int Amt)
{
int j;
int k = 0;
for (j = 0; j < 6; ++j) if (A[j] == Amt) k++;
return( k >= 3 );
}
GetSixInputs(A);
for (i=0; i<6; ++i) {
if ( ThreeOrMore(A[i]) ) Insert(A[i], &PQ);
}
AmountWon = ( Empty(&PQ) ? 0 : Remove(&PQ));
printf("You win $ %d\n",AmountWon);
}
/* main program to test results */
int main(void)
{
/* test priority queue lottery solution */
PQLotterySolution( );
}
/* end of main */
K [ n0 [~~((K > 0 ) (n0 > 0 )) n [~(n > n 0 ) (|g (n )| < K |f(n )|)] ] ]
Translating the later into English yields, For any K >0 and any n 0 >0
there exists an integer n greater than n 0 such that |g ( n )| K | f ( n )|. In
essence, this says that if f ( n ) and g ( n ) are positive functions, then
g ( n ) grows so fast as n increases that it is never bounded above by
some constant multiple of f ( n ) for sufficiently large n . This would
be a true statement, for instance, if g ( n ) = n 2 and f ( n ) = n . For
example, for any K > 0 and any n0 > 0, choose n > max (K , n0). Then n >
n 0 and n >K , and multiplying both sides of n > K by n , we get n 2 > K n
which is the same as |g ( n )| > K |f ( n )|, from which it follows that |g ( n )|
K|f(n)|.
6. Loop invariant :
[((0 i ) (i < n )) ( S == (0
j i)
A [ j] ) ]
Precondition : i == 0, S == 0.
Postcondition : the value returned by the function S um == (0 i n
1) A[i ]
The following version of the original program is annotated with
assertions:
10
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* assume n > 0 */
/* precondition */
/* loop invariant */
/* postcondition */
Base Case : Before entering the while-loop for the first time, S
== 0 and i == 0. In particular, S == (0 j < i ) A [ j ] == (0 j < 0) A [ j ]
= 0, because there are no integers j in the range 0 j < 0. Hence,
the assertion on line 7 is true on the first trip through the whileloop. Then on line 8, the statement S += A[i] is executed, with the
previous values S == 0 and i == 0. So A[ 0 ] is added to S and S ==
A [ 0 ] == (0 j i) A [ j ] . From this, the truth of the loop invariant on
line 9 follows on the first trip through the loop.
Induction Step : Assume that the invariant holds when we are in
the i th iteration of the loop. Then the invariant on line 9 holds,
namely:
{ ( 0 i < n ) ( S == (0 j i) A[j] ) }
is correctly
|
|
|
|
|
|
|
|
|
while (m < n) {
/* while the center has characters to reverse */
c = S[m]; S[m] = S[n]; S[n] = c;
/* swap the edges, then move */
m++; n ;
/* the edge indices toward the center */
}
}
CalculatorProgramShell:
CalculatorProgramShell
S2
CalculatorModule:
InitializeAndDisplayCalculator
GetAndProcessOneEvent
UserSubmittedAnExpression
Display
UserWantsToQuit
Shutdown
S1
YourCalculationModule:
Evaluate
S1
+ functions of YourCalculatorUnit
2.
PriorityQueueSorting program:
PriorityQueueSort
S2
PQImplementation.c:
Initialize
Full
Empty
Insert
Remove
S1
PQTypes.h:
PQItem
PQListNode
PriorityQueue
S1
$1,061,093.
|
|
|
|
|
}
}
10
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3. Use the input sequence: 0.3, 0.4, 1.1, 2.3, 99999, 99999. This sequence
forces the program to add 99999 to the sum giving a wrong answer,
25000.20.
4. Use a transformation that eliminates the duplicated assignment
statement,
|
PlayersMove = GetMoveFromUser( );
|
|
|
|
|
|
|
|
while (1) {
PlayersMove = GetMoveFromUser( );
if (PlayerMove == QuitSignal) {
break;
}
DisplayPlayersMoveOnTheBoard( );
MakeMachineMove( );
}
O(1)
O(log n)
O(n)
n log n
O(n log n)
Quadratic
O(n2)
Cubic
O(n3)
where c > 0 is a finite constant.
Exponential
O(cn)
2. No, the complexity class tends to give useful comparative
information only when the input size of the algorithm is
comparatively large.
3. If we are using small data sets (in which the input size is small)
then the complexity class of the algorithm does not matter very
much. For small n , an O(n 2 ) and an O(n log n ) algorithm have almost
the same running time. On the other hand, for large sorting
problems, an O( n log n ) sorting algorithm may have dramatic
advantages in running time over an O( n 2 ) sorting algorithm (as
illustrated by the answer to Ex. 6.3.2 below). HeapSort , MergeSort , and
QuickSort are O( n log n ) algorithms. SelectionSort and InsertionSort a r e
O( n 2 ) sorting algorithms.
4. Using algorithms that take exponential space or exponential
running time is usually impractical for all but small input values.
However, for small inputs occasionally it makes sense to use an
exponential algorithm. For example, the input sizes for which an
n < 77.0613459
2. S e l e c t i o n S o r t will take (262144*262144)/(10 6 *60) = 1145.3246
minutes (or a little over 19 hours) and Q u i c k S o r t will take
262144*log 2 (262244)/(10 6 *60) = 0.0786432 minutes. Applying a
cost of $100 per minute, SelectionSort costs $114,532.46 and QuickSort
costs $7.86. QuickSort seems a tad cheaper under these particular
economic circumstances.
3. Many practical parsing algorithms used in contemporary compilers
run in time O(n ), even though theoretically it is not known how to
perform completely general parsing in time less than O( n 2.8 ).
4. There are substring searching algorithms that run O( n ) time. There
are even some that run in sublinear time, meaning that they run in
fewer than n steps for a text being searched that is n characters
long. There are also obvious, but inefficient, text searching
algorithms that run in time proportional to m * n , where m is the
length of the search pattern and n is the length of the text being
searched.
3 n 2 3n 3 ,
4 n 4n 3 ,
5 n 3 5n 3 .
8n 3 ,
and
5n3+3n2+4n+8 20 n3.
Binary Search
Sequential Searching
MergeSort
O(n2)
SelectionSort
O(2n)
d 1 b (n 1) + d 1 c + d2T(n 2) .
Then, unrolling some more, we get:
= d 0 b (n ) + d 0c +
d 1 b (n 1) + d 1 c +
d 2 b (n 2) + d 2 c +
:
:
d i1 b ( n (i 1)) + d i1 c
+
d i T( n i)
:
:
So letting i = n 1, the unrolling stops on the line reaching
the base case:
dn2b(n (n 2)) + dn2c + dn1 T(n (n 1)) .
But, T(n (n 1)) = T(1) = a . So the last line can be rewritten
as:
dn2b(n (n 2)) + dn2c + adn1 .
Then, summing all the columns in the unrolled equation gives:
n2
T(n) = b
d i( n i) + c
i= 0
n2
di
+ adn1 .
i= 0
T(n) =
adn1 + (bn + c)
di
n2
i= 0
i di .
i= 0
(A)
[ Note : We can also solve recurrence relations 6.6 using the method
of summing factors. ] Each of the following lines is multiplied by
progressively higher powers of d . That is, when we see the
notation: d i *{T(n i ) d T(n i 1) = b ( n i ) + c }, it signifies
multiplying all terms on both sides of the equation by d i:
T(n) dT(n1)
d *{T(n 1) d T(n 2)
d2*{T(n2) dT(n3)
:
:
:
:
d n 2*{T(2) d T(1)
=b n
+c
= b (n 1)+ c }
= b (n 2)+ c }
:
:
= b (2)
+c }
T(n) dn1T(1) = b
n2
d i .
d i( n i) + c
i= 0
i= 0
T(n) =
adn1 + (bn + c)
n2
di b
i= 0
i di .
i= 0
(A)
T(n) = a +
(b n + c )
n2
i= 0
which
i= 0
(bn + c )( n 1)
( n 2 )( n 1 )
2
A fter more simplification, the last line yields the final form given
in Table 6.18:
T( n ) = (b /2 ) n 2 + (b /2 + c ) n + (a b c ),
provided d = 1.
i= 0
dn1 1
d 1
.
Also, one of the terms in Equation A is of the form ( 1 i n ) i * d i .
Using the hint that ( 1 i n ) i * d i = [ d /( d 1) 2 ] * [ ( n d n 1) d n + 1 ] , and
taking this sum with an upper limit of (n 2 ) instead of n , yields:
n2
id i
= b * [ d /( d 1) 2 ] * [ (( n 2) d ( n 2)1) d n 2 +1 ] .
i= 0
dn1 1
b * [ d /( d 1) 2 ] * [ (( n 2) d ( n 2 )
d 1
1)dn2+1 ] .
The last equation is in closed form. After (lots of) simplification,
this equation can be rearranged to take the final form in Table
6.18:
T( n ) = \B
b
n +
1
, for d 1.
2
(
d
1
)
|
|
|
|
|
|
|
|
T( n ) = 2 n 2 + 2 + c n + (a b c).
Thus, the running time for recursive SelectionSort is O(n 2 ).
d 0 b n /p 0 + d 0 c +
+ d1 c +
+ d2 c +
+ d3 c +
d 1 b n /p 1
d 2 b n /p 2
d 3 b n /p 3
...
d ( k 1) b n / p ( k
1)
+ d (k
k1
T(n) =
bn ( d j/ p j )
1)
c + d k T( n / p k )
k1
j= 0
d j + d k a
(B)
j= 0
First Case:
Assume d = p . Then d k = p k = n , k = logp n , and (d j/ p j) = 1. So,
Equation B simplifies to:
T( n ) =
d k 1
bnk + c
d 1
+ adk .
c
c
bn logp n + a +
n
d 1
d 1
Second Case: d = 1
Assume d = 1. Then d k = 1, p k = n , k = logp n , and (d j/ p j) = (1/p j) .
So, Equation B simplifies to:
T( n ) =
1 / p k 1
bn
1/p 1
1/n 1
bn
1 / p 1
(n 1)/n
bn
( p 1 ) / p
+ ck + a
+ c logp n + a
+ c logp n + a
bp
(n 1) + c logp n + a
(p 1 )
which simplifies to the final form:
=
T( n ) =
bp
bp
+ c logp n + a
p
.
1
Third Case: d = 1, b = 0
Assume d = 1 and b = 0. Then d k = 1, p k = n , and k = logp n . So,
Equation B simplifies to:
T( n ) = ck + a
and substituting logp n for k yields the final form:
T( n ) = c logp n + a .
Fourth Case: d 1, d p
Assume d 1 and d p . Then p k = n and k = logp n . So, Equation B
simplifies to:
T( n ) =
d k / p k 1
bn
d
/
p
( d k n )/ n
bn
(
d
p
)/
p
d k 1
+ c
dk
+ c
bp
c
+
+ a d k
p
d 1
+ adk
c
1
+ adk
bp
n c
d 1
p
d
\B(a +
\ F ( b p , d p ) + \F(c , d 1 )) n l o g p d
b p
.
n
p
d 1
5. (a)
O( n log n )
(b)
O(n)
(c)
O(log n )
(d)
6. Equations 6.7 on page 237 match the conditions for the first line of
Table 6.21 on page 241, if we set d = p = 2. The solution resulting
from substituting 2 for both d and p in the first line of Table 6.2.1
is:
T( n ) = b n log2 n + (a + c ) n c
This equation gives the running time of MergeSort and is identical
Equation 6.8 on page 239.
7. The proof that log 2 ( n + 1) < log2 ( n ) + 1, for all n > 1, is given on
pages 709 to 710 of the Math Reference Appendix . (A brief
summary of the steps in this proof is: (n > 1) (1 < n ) ( n + 1) <
2 n lg(n + 1) < lg(2 n ) lg(n +1) < lg 2 + lg n lg( n +1) < lg n + 1).
Now lets take the running time equation for binary search given
by Equation 6.14 on page 245:
C( n ) =
2 log2 (n + 1) 3 +
2 log2 (n + 1)/n
45
50
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( d == '('
| | d == '[' | | d == '{' ) {
if ( Full(&ParenStack) ) {
printf("Results inconclusive. Stack overflow during processing.\n");
return;
} else {
Push(d, &ParenStack);
}
} else if ( d == ')' | |
d == ']' | | d == '}' ) {
3. This method will not work because it will accept as valid the
improperly nested sequence of parentheses given in the following
counterexample: } ( ) {. For this sequence, BraceCount will go to 1
when the first brace is encountered and will later return to 0 when
the last brace is encountered. This leaves BraceCount at 0, but the
parentheses are not matched. Another counterexample is
( [ { ) ] } which will leave all counts zero at the end, but which
is not well-formed
(((6*7)2)/5)^(1/3) =
2
1/3 =
^(1/3) = 8
5
8 = 2
/* contains atof */
/* contains log and exp */
/* contains isdigit(d) */
/* Assume that the types and operations defining a stack ADT are defined */
/* in "StackInterface.h". The source file "StackImplementation.c" */
/* should be compiled independently and then linked with this program */
Stack EvalStack;
char *PostfixString;
void InterpretPostfix(void)
{
float LeftOperand, RightOperand, Result;
int i;
char c;
char *s = "x";
InitializeStack(&EvalStack);
for (i = 0; i < strlen(PostfixString); ++i) {
s[0] = c = PostfixString[i];
if (isdigit(c)) {
if ( Full(&EvalStack) ) {
printf("Stack full. Postfix Evaluation could not be completed.\n");
if ( Empty(&EvalStack) ) {
printf("Value of postfix expression = %f\n", Result);
} else {
printf("Malformed postfix string.\n");
printf("Too many operands and not enough operators.\n");
}
}
int main(void)
/* and print it */
/* Assume that the types and operations defining a stack ADT are defined */
char c;
int i,L;
Stack S;
Boolean Match;
L = strlen(A);
/* check first to see that the string A is spelled only with the allowable */
/* letters 'a', 'b', 'c', and 'm' and that its length is at least 3 */
Match = true;
for (i = 0; i < L; ++i) {
if (! (A[i] == 'a' | | A[i] == 'b' | | A[i] == 'c' | | A[i] == 'm') ) {
Match = false;
}
}
if (L < 3) Match = false;
if ( Match ) {
c = A[0]; i = 0;
InitializeStack(&S);
while ( (c != 'm') && (i < L) ) {
Push(c,&S);
i++;
if (i < L) c = A[i];
}
if (c != 'm') {
Match = false;
} else {
while ( (i < L1 /* not at end of string A */) && (Match /* == true */) ) {
if ( Empty(&S) ) {
Match = false;
} else {
Pop(&S,&c);
i++;
if (c != A[i]) {
/* match the remaining */
Match = false; /* characters with those from the stack */
}
}
}
if (Match && ! Empty(&S)) Match = false;
}
/* end if (c != M) */
}
/* end if (Match) */
return (Match);
}
/* end Recognize */
55
|
|
|
|
|
|
|
|
|
|
|
if (Q>Front == Q>Rear) {
SystemError("attempt to remove item from empty Queue");
Then delete the Count field from the declaration of the Queue record
on line 8 and remove all operations on the Count field in the queue
functions. The definitions of E m p t y ( & Q ) and F u l l ( & Q ) have to be
modified in a fashion similar to that given immediately above for
lines 52:53 and 65:66.
3. Just remove the items from the front of the queue one-by-one and
push them onto the stack until the queue becomes empty. Then
pop the items off the stack one-by-one and insert them into the
queue until the stack becomes empty, as follows:
10
15
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10
15
20
25
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( Prev == NULL ) {
/* if the Queue is empty, report error */
SystemError("attempt to remove item from empty queue");
} else if (Prev>Link == Prev) {
/* if there is only one node in Q */
/* free it and set Q>Rear to NULL */
*F = Prev>Item;
Q>Rear = NULL;
free(Prev);
} else {
/* otherwise */
while (Prev>Link != Q> Rear) {
/* find the predecessor */
Prev = Prev>Link;
/* of Q>Rear */
}
*F = Q>Rear> Item;
Prev>Link = Q> Rear>Link;
/* link Prev to front of queue */
free(Q>Rear);
/* free old Q>Rear */
Q>Rear = Prev;
/* and set new Q>Rear to Prev */
}
}
= ( 1 i n ) (n i )
= ( 1 i n ) n ( 1 i n ) i
= n 2 n( n +1)/2
= n ( n 1)/2
Now, to average over all n items of the array, we divide the latter
total by n , getting:
(1/ n )* n ( n 1)/2 = (n 1)/2
Therefore, the average time for deletion in such an array is O(n ).
2. By an analysis similar to that for Exercise 1, the average time
required for insertion is O(n ). The analysis goes as follows: If we
insert a new item after the last, or n th , item, we have to shift 0
items to the right. If we insert a new item after the (n 1)st item,
we have to shift 1 item to the right. In general, if we have to insert
a new item after the i th item, we have to shift (n i ) items to the
right. Finally, if we have to insert a new item before the first item,
we have to shift n items to the right. The total time to shift items
for insertions in all (n + 1) possible positions (from before the
first to after the last) is a sum of the form 0 + 1 + 2 + ... + n =
n ( n +1)/2. Dividing by n + 1 yields n /2 shifts on the average. Hence,
the average number of shifts is O( n ). Since the shifting time
dominates the time required to do insertion, the average insertion
operation takes time O(n ).
3. Some arguments supporting the results in Table 8.5 are as follows:
(a) Finding the length of L
#include <stdio.h>
#include <stdlib.h>
typedef int ItemType;
typedef struct NodeTag {
ItemType
struct NodeTag
} ListNode;
void Initialize (ListNode **L)
{
*L = NULL;
}
Item;
*Link;
}
}
ListNode *Select(int i,ListNode *L)
{
int j;
ListNode *Temp;
if (L == NULL) {
return NULL;
} else {
j = 1;
Temp = L;
while ((i != j) && (Temp>Link != L)) {
/* find node */
Temp = Temp>Link;
/* you are looking for */
j++;
/* by advancing i nodes in the list */
}
if (i == j) {
return Temp;
} else {
return NULL;
}
}
}
void Replace (int i, ItemType Y, ListNode *L)
{
ListNode *Temp;
Temp = Select(i,L);
if (Temp != NULL) Temp>Item = Y;
}
void DeleteFirst (ListNode **L)
{
ListNode *First, *Last;
First = *L;
if (First != NULL) {
/* if list is nonempty */
if (First>Link == First) {
/* if list has only one node */
free(First);
/* recycle storage for the node */
*L = NULL;
/* and set the list pointer in L to NULL */
} else {
/* list had more than one node */
Last = First;
while (Last>Link != First) {
/* locate last node */
Last = Last>Link;
}
*L = Last>Link = First>Link; /* link around first and reset *L */
free(First);
/* recycle storage for deleted node */
}
}
|
|
|
|
|
|
ListNode *P;
N>Item = N>Link>Item;
P = N>Link;
N>Link = P>Link;
free(P);
TRUE 1
FALSE 0
typedef
int ItemType;
typedef
struct GenListTag {
struct GenListTag *Link;
short Atom;
union SubNodeTag {
ItemType
Item;
struct GenListTag *SubList;
10
|
|
|
|
|
|
|
|
|
|
|
|
|
int strlen(char S[ ])
{
int i;
i = 0;
while (S[i] != '\0' ) {
++i;
}
return i;
}
10
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20
25
|
|
|
|
|
|
|
|
|
|
|
|
if (*p == '\0') {
return q;
} else if (*r == '\0') {
return NULL;
} else {
p = S;
r++;
}
}
}
10
15
20
25
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return i;
}
(0 l n )
2l = 20 + 21 + 22 +...+ 2n = 2n +1 1 .
struct {
int
HeapItemType
} Heap;
/* for now */
Count;
ItemArray[MAXCOUNT+1];
/* ---------------------------------------------------------------------- */
void BuildInitialNonHeap(Heap *H)
{
int i;
HeapItemType InitializerArray[ ] = {0,2,4,5,7,3,10,8,1,9,6};
H>Count = MAXCOUNT;
for (i=1; i<=MAXCOUNT; i++) H>ItemArray[i] = InitializerArray[i];
}
/* ---------------------------------------------------------------------- */
void Reheapify(Heap *H, HeapNodeType N)
{
HeapNodeType M;
HeapItemType V1,V2, temp;
Boolean Finished;
/* Let V1 refer to N's value */
V1 = H>ItemArray[N];
Finished = (2*N > MAXCOUNT);
while (!Finished) {
/* let M be the child of node N having the larger value V2 */
M = 2*N;
/* let M be the left child of N */
if (M < MAXCOUNT) {
/* if a right child of node N exists, then */
if (H>ItemArray[M+1] > H>ItemArray[M]) M++;
/* if the */
}
/* right childs value is larger than the left child's value */
V2 = H>ItemArray[M];
/* then let M be the right child of N */
if (V1 >= V2) {
Finished = true;
} else {
/* exchange the values in nodes N and M */
temp = H>ItemArray[N];
H>ItemArray[N] = H>ItemArray[M];
H>ItemArray[M]=temp;
/* Let N refer to node M and let V1 refer to N's value */
N = M;
V1 = H>ItemArray[N];
Finished = (2*N > MAXCOUNT);
/* true iff node */
/* N has no children */
}
/* ---------------------------------------------------------------------- */
void PrintHeap(Heap *H)
{
int i;
for (i=1; i<=H>Count; ++i) {
printf("%2d%2d; ",i,H>ItemArray[i]);
}
printf("\n");
}
/* ---------------------------------------------------------------------- */
int main(void)
{
Heap H;
BuildInitialNonHeap(&H);
PrintHeap(&H);
Heapify(&H);
PrintHeap(&H);
}
/* main program */
recursively as follows:
:RSXYZTUVW
:XSYZ RUTWV
PostOrder Traversal
:XZYSUWVTR
LevelOrder Traversal
:RSTXYUVZW
^
b
*
2
3. The solutions to Ex. 9.6.3 and Ex. 9.6.4 are given in the following
program:
|
|
/*
*
10
15
20
25
30
35
40
45
50
55
60
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct NodeTag {
char
struct NodeTag
struct NodeTag
} Node;
Symbol;
*LLink;
*RLink;
| {
|
if (T != NULL) {
|
if (IsOperator(T>Symbol) ) {
|
putchar('(');
|
PrintTree1(T>LLink);
70
|
printf(" %c ",T>Symbol);
|
PrintTree1(T>RLink);
|
putchar(')');
|
} else {
|
putchar(T>Symbol);
75
|
}
|
}
| }
|
| /* ---------------------------------------------------------------------- */
80
|
| void PrintTree(Node *T)
| {
|
PrintTree1(T);
|
putchar('\n');
85
| }
|
| /* ---------------------------------------------------------------------- */
|
| int precedence(char c)
/* define precedence of operators & atoms */
90
| {
|
switch (c) {
|
case '^':
|
return 3;
|
case '*':
95
|
case '/':
|
return 2;
|
case '+':
|
case '':
|
return 1;
100
|
default :
|
return 4;
|
}
| }
|
105
| /* ---------------------------------------------------------------------- */
|
| void WriteP(char c)
/* write spaces around '+' and '' */
| {
/* but don't write spaces around other operators */
|
if (precedence(c) == 1) {
110
|
printf(" %c ",c);
|
} else {
|
putchar(c);
|
}
| }
115
|
| /* ---------------------------------------------------------------------- */
|
| void PrintParens1(Node *T, char op)
/* op is the operator above and */
| {
/* to the right of subtree T, where T is not atomic */
120
|
if (T == NULL) {
|
;
/* print nothing */
|
} else if ( !IsOperator(T>Symbol) ) {
|
putchar(T>Symbol);
|
} else if (precedence(T>Symbol) < precedence(op) ) {
125
|
putchar('(');
130
135
140
145
150
155
160
165
170
175
180
185
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PrintParens1(T>LLink,T>Symbol);
WriteP(T>Symbol);
PrintParens2(T>RLink,T>Symbol);
putchar(')');
} else {
PrintParens1(T>LLink,T>Symbol);
WriteP(T>Symbol);
PrintParens2(T>RLink,T>Symbol);
}
}
/* ---------------------------------------------------------------------- */
void PrintParens2(Node *T, char op)
{
/* op is the operator above and to the left of subtree T, */
/* where T is not atomic */
if (T == NULL) {
;
/* print nothing */
} else if ( !IsOperator(T>Symbol) ) {
putchar(T>Symbol);
} else if ( (precedence(T>Symbol) < precedence(op)) | |
( (precedence(T>Symbol) == precedence(op)) &&
( !((T>Symbol == op) && ((op == '+') | | (op == '*')) )) )) {
putchar('(');
PrintParens1(T>LLink,T>Symbol);
WriteP(T>Symbol);
PrintParens2(T>RLink,T>Symbol);
putchar(')');
} else {
PrintParens1(T>LLink,T>Symbol);
WriteP(T>Symbol);
PrintParens2(T>RLink,T>Symbol);
}
}
/* ---------------------------------------------------------------------- */
void PrintParens3(Node *T)
{
if (T != NULL) {
if ( IsOperator(T>Symbol) ) {
PrintParens1(T>LLink,T>Symbol);
WriteP(T>Symbol);
PrintParens2(T>RLink,T>Symbol);
} else {
putchar(T>Symbol);
}
}
/* ---------------------------------------------------------------------- */
void PrintParens(Node *T)
{
PrintParens3(T);
putchar('\n');
}
/* ---------------------------------------------------------------------- */
190
195
200
205
210
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(void)
{
char *S = ".....................",
*S1 = "/^b2**4ac*2a",
*S2 = "**+ag+bc*++cd+de++efg",
*S3 = "/^2+a*bcefg",
*S4 = "/^2*a^bcehg",
*S5 = "/^2*a^bc//xy/hg";
/* empty string */
/* first test case */
/* second test case */
/* third test case */
/* fourth test case */
/* fifth test case */
Node *T;
int i;
strcpy(S,S1);
/* substitute Si for S1 for other test cases */
printf("translating %s:\n",S);
T = PrefixStringToTree(&S);
PrintTree(T);
PrintParens(T);
}
/* main program */
O(log n )
O(n)
O(log n )
10
15
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
key A in a
10
15
20
25
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10
15
20
25
30
35
40
45
50
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------- */
void AuxTreePrint(TreeNode *T)
{
if (T != NULL) {
putchar('(');
AuxTreePrint(T->LeftLink);
printf(" %s ",T->Airport);
AuxTreePrint(T->RightLink);
putchar(')');
}
}
/* -------------------------------------------------------------- */
void TreePrint(TreeNode *T)
{
if (T == NULL) {
printf("( )\n");
} else {
AuxTreePrint(T);
putchar('\n');
}
}
/* -------------------------------------------------------------- */
int main(void)
{
TreeNode *T;
/* First insert the airport codes from Table 9.3.2 in the order given */
T = NULL;
T = TreeInsert("ORY",T);
T = TreeInsert("JFK",T);
T = TreeInsert("BRU",T);
T = TreeInsert("DUS",T);
T = TreeInsert("ZRH",T);
T = TreeInsert("MEX",T);
T = TreeInsert("ORD",T);
T = TreeInsert("NRT",T);
T = TreeInsert("ARN",T);
T = TreeInsert("GLA",T);
T = TreeInsert("GCM",T);
/* Then print the tree T as a parenthesized expression */
TreePrint(T);
}
/* end main */
Ln =
i = 1
2
[(n +1) r 2(2r1) ] + 1
n
2
[(n +1) r 2 n ] + 1
n
2r+2r/n4+1
( 2r 3 ) +
10
15
20
25
30
35
40
45
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 r
.
n
#include <math.h>
/* -------------------------------------------------------------- */
double Hn(int n)
{
double Temp; int i;
Temp = 0.0;
for (i = 1; i <= n; ++i) Temp += 1.0/i;
return Temp;
}
/* -------------------------------------------------------------- */
double Lg(int n) /* Base 2 Logarithm */
{
return log(n)/log(2);
/* log(n) is C's natural log function */
}
/* -------------------------------------------------------------- */
double Power(int n, int m)
{
return exp(m*log(n));
}
/* n^m */
/* -------------------------------------------------------------- */
double L(int n)
{
int q;
/* L = (1in) Floor(lg(i)) */
q = (int) floor(Lg(n+1));
return (n + 1)*q Power(2,(q+1)) + 2;
}
/* -------------------------------------------------------------- */
double ExactCn(int n)
{
return 4*(1 + 1.0/n)*Hn(n) 7;
}
/* -------------------------------------------------------------- */
double ApproxCn(int n)
50
55
60
65
70
75
80
85
90
95
100
105
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
return 2.77*Lg(n) 4.7;
}
/* -------------------------------------------------------------- */
int TestFormulas(void)
{
int n;
double X, Y, Cn;
/* Exercise 9.7.7 -- Compare Exact and Approximate Average */
/* Case Formulas */
printf("Exercise 9.7.7\n");
n = 510;
printf("Exact Average Cn for n = %d: Cn = %3.7f\n", n, ExactCn(n));
printf("Apprx Average Cn for n = %d: Cn = %3.7f\n", n, ApproxCn(n));
n = 511;
printf("Exact Average Cn for n = %d: Cn = %3.7f\n", n, ExactCn(n));
printf("Apprx Average Cn for n = %d: Cn = %3.7f\n", n, ApproxCn(n));
n = 1023;
printf("Exact Average Cn for n = %d: Cn = %3.7f\n", n, ExactCn(n));
printf("Apprx Average Cn for n = %d: Cn = %3.7f\n", n, ApproxCn(n));
putchar('\n');
n = 1;
while (fabs(ExactCn(n) ApproxCn(n))/ExactCn(n) > 0.02) {
n++;
}
printf("The n for which ApproxAverageCn and ");
printf("ExactAverageCn differ by 2%% = %d\n",n);
putchar('\n');
printf("Exact Cn for n = 90:
printf("Apprx Cn for n = 90:
printf("Exact Cn for n = 91:
printf("Apprx Cn for n = 91:
Cn = %3.7f\n", ExactCn(90));
Cn = %3.7f\n", ApproxCn(90));
Cn = %3.7f\n", ExactCn(91));
Cn = %3.7f\n", ApproxCn(91));
printf("\n\n");
/* Exercise 9.7.8 -- Compare Exact and Approximate Best Case Formulas */
printf("Exercise 9.7.8\n");
n = 0;
do {
n++;
X = ((2*L(n) + n)/n);
Y = (2*Lg(n) 3);
} while ( (fabs(X Y)/X) > 0.02 );
115
|
|
|
|
|
|
|
|
|
|
|
n = 115;
printf("Exact Best Cn for n = %d: Cn = %3.7f\n", n, ((2*L(n) + n)/n));
printf("Apprx Best Cn for n = %d: Cn = %3.7f\n", n, (2*Lg(n) 3));
n = 116;
printf("Exact Best Cn for n = %d: Cn = %3.7f\n", n, ((2*L(n) + n)/n));
printf("Apprx Best Cn for n = %d: Cn = %3.7f\n", n, (2*Lg(n) 3));
}
/* end TestFormulas */
20.312
20.319
23.062
20.222
20.230
22.996
8. See the program above in the solution to Ex. 9.7.7. When this
program is executed, it determines that the least n for which the
Approximate Best C n and the Exact Best Cn differ by 2% is n =
116. Hence, it is verified that these values also differ by less than
2% for any n 197.
node with airport code A , call the function
in what follows, where T contains a pointer to the
root of the binary search tree:
9. To
delete
DeleteNode(A,&T)
10
15
20
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
*
*/
/* -------------------------------------------------------------- */
void DeleteSmallest(AirportCode *A, TreeNode **T)
{
TreeNode *N;
if ( (*T)>LeftLink == NULL ) {
strcpy(*A,(*T)>Airport);
N = (*T)>RightLink;
free(*T);
*T = N;
} else {
DeleteSmallest(A,&(*T)>LeftLink);
}
}
25
30
35
40
45
50
55
60
65
70
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------- */
void DeleteLargest(AirportCode *A, TreeNode **T)
{
TreeNode *N;
if ( (*T)>RightLink == NULL ) {
strcpy(*A,(*T)>Airport);
N = (*T)>LeftLink;
free(*T);
*T = N;
} else {
DeleteLargest(A,&(*T)>RightLink);
}
}
/* -------------------------------------------------------------- */
void DeleteRoot(TreeNode **T)
{
AirportCode temp;
if ( (*T)>LeftLink == NULL ) {
if ( (*T)>RightLink == NULL ) {
free(*T);
*T = NULL;
} else {
DeleteSmallest(&temp, &(*T)>RightLink);
strcpy( (*T)>Airport, temp);
}
} else {
DeleteLargest(&temp, &(*T)>LeftLink);
strcpy( (*T)>Airport, temp);
}
}
/* -------------------------------------------------------------- */
void DeleteNode(AirportCode A, TreeNode **T)
{
int result;
if ( (*T) == NULL ) {
; /* the tree is empty and does not contain the airport code A */
} else if ( ( result = strcmp(A, (*T)>Airport)) == 0 ) {
DeleteRoot(T);
} else if (result < 0) {
DeleteNode(A, &(*T)>LeftLink);
} else {
DeleteNode(A, &(*T)>RightLink);
}
}
/* -------------------------------------------------------------- */
|
|
|
|
|
|
|
|
2. Yes, the InOrder traversal of a binary search tree reads the keys
in the nodes in increasing order of the keys. It helps to use an AVL
tree to keep the total insertion time bounded by O(n log n ) where
the sum of the O(log i ) insertion times for the n keys Ki, (1 i n ),
starting with an empty tree, is O(n log n ).
3. The solutions to Exs. 9.8.3 and 9.8.4 are given in the following
program which provides a complete set of AVL-tree algorithms
10
15
20
25
30
35
40
45
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
* Complete AVL-tree programs including solutions to Exs. 9.8.3 and 9.8.4
*/
#include <stdio.h>
#include <string.h>
typedef char AirportCode[4];
typedef enum {LeftHeavy, Balanced, RightHeavy} BalanceCode;
typedef struct TreeNodeTag {
BalanceCode
AirportCode
struct TreeNodeTag
struct TreeNodeTag
} TreeNode;
BalanceFactor;
Airport;
*LeftLink;
*RightLink;
/* some variables */
TreeNode *T, *N;
Boolean Heavier, Lighter;
/* -------------------------------------------------------------- */
TreeNode *CreateNode(AirportCode A)
{
TreeNode *N;
N = (TreeNode *)malloc(sizeof(TreeNode)); /* create a new blank */
/* tree node which N references */
N>LeftLink = NULL;
/* set its left and right links to be NULL */
N>RightLink = NULL;
strcpy(N>Airport,A);
/* let its airport code be A */
N>BalanceFactor = Balanced;
return N;
/* and let N be the value of the function */
}
/* -------------------------------------------------------------- */
void RotateLeft(TreeNode **T)
/* Assume *T points to a non-empty */
{
/* tree having a non-empty right subtree */
TreeNode *N;
/* let N be a tree node pointer */
N = (*T)>RightLink;
50
55
60
65
70
75
80
85
90
95
100
105
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(*T)>RightLink = N>LeftLink;
N>LeftLink = (*T);
(*T) = N;
}
/* -------------------------------------------------------------- */
void RotateRight(TreeNode **T)
/* Assume *T points to a non-empty */
{
/* tree having a non-empty left subtree */
TreeNode *N;
/* let N be a tree node pointer */
N = (*T)>LeftLink;
(*T)>LeftLink = N>RightLink;
N>RightLink = (*T);
(*T) = N;
}
/* -------------------------------------------------------------- */
void RightRebalance(TreeNode **T, Boolean *Heavier)
{
TreeNode *N, *P;
N = (*T)>RightLink;
switch (N>BalanceFactor) {
case LeftHeavy:
P = N>LeftLink;
switch (P>BalanceFactor) {
case LeftHeavy:
(*T)>BalanceFactor = Balanced;
N>BalanceFactor = RightHeavy;
break;
case Balanced:
(*T)>BalanceFactor = Balanced;
N>BalanceFactor = Balanced;
break;
case RightHeavy:
(*T)>BalanceFactor = LeftHeavy;
N>BalanceFactor = Balanced;
break;
}
P>BalanceFactor = Balanced;
RotateRight(&N);
(*T)>RightLink = N;
RotateLeft(T);
*Heavier = false;
break;
case Balanced:
/* do nothing -- this case cannot occur */
break;
case RightHeavy:
(*T)>BalanceFactor = Balanced;
N>BalanceFactor = Balanced;
RotateLeft(T);
*Heavier = false;
break;
115
120
125
130
135
140
145
150
155
160
165
170
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
}
/* -------------------------------------------------------------- */
void LeftRebalance(TreeNode **T, Boolean *Heavier)
{
TreeNode *N, *P;
N = (*T)>LeftLink;
switch (N>BalanceFactor) {
case LeftHeavy:
/* perform a single right rotation */
(*T)>BalanceFactor = Balanced;
N>BalanceFactor = Balanced;
RotateRight(T);
*Heavier = false;
break;
case Balanced:
/* do nothing -- this case cannot occur */
break;
case RightHeavy:
P = N>RightLink;
switch (P>BalanceFactor) {
case LeftHeavy:
(*T)>BalanceFactor = RightHeavy;
N>BalanceFactor = Balanced;
break;
case Balanced:
(*T)>BalanceFactor = Balanced;
N>BalanceFactor = Balanced;
break;
case RightHeavy:
(*T)>BalanceFactor = Balanced;
N>BalanceFactor = LeftHeavy;
break;
}
P>BalanceFactor = Balanced;
RotateLeft(&N);
(*T)>LeftLink = N;
RotateRight(T);
*Heavier = false;
break;
}
}
/* -------------------------------------------------------------- */
void InsertNode(AirportCode A, TreeNode **T, Boolean *Heavier)
{
TreeNode *P, *N;
Boolean HeavierSubtree;
175
180
185
190
195
200
205
210
215
220
225
230
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
240
245
250
255
260
265
270
275
280
285
290
300
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
305
310
315
320
325
330
335
340
345
350
355
360
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} /* end switch */
break;
} /* end switch */
} /* RebalanceToLeft */
/* -------------------------------------------------------------- */
void RebalanceToRight(TreeNode **T, Boolean *Lighter)
{
/* Rebalance after T's right subtree became lighter */
TreeNode *N, *P;
switch ((*T)>BalanceFactor) {
case LeftHeavy:
N = (*T)>LeftLink;
switch (N>BalanceFactor) {
case LeftHeavy:
(*T)>BalanceFactor = Balanced;
N>BalanceFactor = Balanced;
RotateRight(T);
*Lighter = true;
break;
case Balanced:
(*T)>BalanceFactor = LeftHeavy;
N>BalanceFactor = RightHeavy;
RotateRight(T);
*Lighter = false;
break;
case RightHeavy:
P = N>RightLink;
switch (P>BalanceFactor) {
case LeftHeavy:
(*T)>BalanceFactor = RightHeavy;
N>BalanceFactor = Balanced;
break;
case Balanced:
(*T)>BalanceFactor = Balanced;
N>BalanceFactor = Balanced;
break;
case RightHeavy:
(*T)>BalanceFactor = Balanced;
N>BalanceFactor = LeftHeavy;
break;
}
RotateLeft(&N); /* double right rotation rooted at T */
(*T)>LeftLink = N;
RotateRight(T);
*Lighter = true;
365
370
375
380
385
390
395
400
405
410
415
420
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
} /* end switch */
break;
case Balanced:
(*T)>BalanceFactor = LeftHeavy;
*Lighter = false;
break;
case RightHeavy:
(*T)>BalanceFactor = Balanced;
*Lighter = true;
break;
} /* end switch */
} /* RebalanceToRight */
/* -------------------------------------------------------------- */
void DeleteSmallest(AirportCode *A,TreeNode **T, Boolean *Lighter)
{
TreeNode *temp;
Boolean SubtreeLighter;
if ( (*T)>LeftLink == NULL) {
if ( (*T)>RightLink == NULL) {
strcpy(*A,(*T)>Airport);
free(*T);
(*T) = NULL;
*Lighter = true;
} else {
strcpy(*A,(*T)>Airport);
temp = (*T);
(*T) = (*T)>RightLink;
free(temp);
*Lighter = true;
}
} else {
/* neither (*T)>LeftLink nor (*T)>RightLink is NULL */
DeleteSmallest(A,&(*T)>LeftLink,&SubtreeLighter);
if (SubtreeLighter) RebalanceToLeft(T,Lighter);
}
}
/* -------------------------------------------------------------- */
void DeleteLargest(AirportCode *A, TreeNode **T, Boolean *Lighter)
{
TreeNode *temp;
Boolean SubtreeLighter;
if ( (*T)>RightLink == NULL ) {
if ( (*T)>LeftLink == NULL ) {
strcpy(*A,(*T)>Airport);
free(*T);
(*T) = NULL;
*Lighter = true;
} else {
strcpy(*A,(*T)>Airport);
temp = (*T);
(*T) = (*T)>LeftLink;
430
435
440
445
450
455
460
465
470
475
480
485
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
free(temp);
*Lighter = true;
}
} else {
/* neither (*T)>LeftLink nor (*T)>RightLink is NULL */
DeleteLargest(A,&(*T)>RightLink,&SubtreeLighter);
if (SubtreeLighter) RebalanceToRight(T,Lighter);
}
}
/* -------------------------------------------------------------- */
void DeleteRoot(TreeNode **T, Boolean *Lighter)
{
AirportCode A;
Boolean SubtreeLighter;
if ( ((*T)>RightLink == NULL) && ((*T)>LeftLink == NULL) ) {
free(*T);
(*T) = NULL;
*Lighter = true;
} else {
switch ((*T)>BalanceFactor) {
case LeftHeavy:
DeleteLargest(&A,&(*T)>LeftLink,&SubtreeLighter);
strcpy((*T)>Airport,A);
if (SubtreeLighter) {
(*T)>BalanceFactor = Balanced;
*Lighter = true;
} else {
*Lighter = false;
}
break;
case Balanced:
DeleteSmallest(&A,&(*T)>RightLink,&SubtreeLighter);
strcpy((*T)>Airport,A);
if (SubtreeLighter) (*T)>BalanceFactor = LeftHeavy;
*Lighter = false;
break;
case RightHeavy:
DeleteSmallest(&A,&(*T)>RightLink,&SubtreeLighter);
strcpy((*T)>Airport,A);
if (SubtreeLighter) {
(*T)>BalanceFactor = Balanced;
*Lighter = true;
} else {
*Lighter = false;
}
break;
} /* end switch */
} /* end if */
} /* DeleteRoot */
/* -------------------------------------------------------------- */
490
495
500
505
510
515
520
525
530
535
540
545
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
555
560
565
570
575
580
585
590
595
600
605
610
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
if (T != NULL) {
switch (T>BalanceFactor) {
case LeftHeavy:
putchar('');break;
case RightHeavy:
putchar('+');break;
case Balanced:
putchar('=');break;
}
}
}
/* -------------------------------------------------------------- */
void PrintTree(TreeNode *T)
{
if (T != NULL) {
if (T>LeftLink != NULL) {
putchar('(');
PrintTree(T>LeftLink);
putchar(')');
}
printf(" %s",T>Airport);
PrintBalanceFactor(T);
putchar(' ');
if (T>RightLink != NULL) {
putchar('(');
PrintTree(T>RightLink);
putchar(')');
}
} else {
printf("( )");
}
}
/* -------------------------------------------------------------- */
void Delete(AirportCode A)
{
printf("\nAbout to delete %s: ",A);
DeleteNode(A,&T,&Lighter);
PrintTree(T);
putchar('\n');
}
/* -------------------------------------------------------------- */
int main(void)
{
/* Construct the AVL tree of Fig. 9.46 on p. 382 */
T = NULL;
InsertNode("ORY",&T,&Heavier);
615
620
625
630
635
640
645
650
655
660
665
670
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
InsertNode("JFK",&T,&Heavier);
InsertNode("BRU",&T,&Heavier);
/* Print the Tree */
PrintTree(T);
putchar('\n');
InsertNode("DUS",&T,&Heavier);
InsertNode("ZRH",&T,&Heavier);
InsertNode("MEX",&T,&Heavier);
InsertNode("ORD",&T,&Heavier);
InsertNode("NRT",&T,&Heavier);
/* Print the Tree */
PrintTree(T);
putchar('\n');
InsertNode("ARN",&T,&Heavier);
InsertNode("GLA",&T,&Heavier);
InsertNode("GCM",&T,&Heavier);
/* Print the Tree */
PrintTree(T);
putchar('\n');
/* Create a Binary Search Tree T pointing to 15 airports */
/*
T = NULL;
InsertNode("MEX",&T,&Heavier);
InsertNode("GCM",&T,&Heavier);
InsertNode("ORY",&T,&Heavier);
InsertNode("BRU",&T,&Heavier);
InsertNode("HKG",&T,&Heavier);
InsertNode("NRT",&T,&Heavier);
InsertNode("YYZ",&T,&Heavier);
*/
/*
InsertNode("ARN",&T,&Heavier);
InsertNode("DUS",&T,&Heavier);
InsertNode("GLA",&T,&Heavier);
InsertNode("JFK",&T,&Heavier);
InsertNode("MIA",&T,&Heavier);
InsertNode("ORD",&T,&Heavier);
InsertNode("SAN",&T,&Heavier);
InsertNode("ZRH",&T,&Heavier);
*/
/* Print the Tree */
/*
PrintTree(T);
putchar('\n');
Delete("NRT"); /* does DeleteNode("NRT",&T,&Lighter); and prints tree */
Delete("ORY"); /* does DeleteNode("ORY",&T,&Lighter); and prints tree */
Delete("YYZ"); /* does DeleteNode("YYZ",&T,&Lighter); and prints tree */
Delete("GCM");/* does DeleteNode("GCM",&T,&Lighter); and prints tree */
Delete("HKG"); /* does DeleteNode("HKG",&T,&Lighter); and prints tree */
Delete("MEX"); /* does DeleteNode("MEX",&T,&Lighter); and prints tree */
Delete("BRU"); /* does DeleteNode("BRU",&T,&Lighter); and prints tree */
putchar('\n');
*/
675
680
685
690
695
700
705
710
715
720
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
P
J
n + 1 2m /2k1.
Solving for k yields,
k
n+1
1 + log m /2
.
2
So,
n+1
k = 1 + log m /2
.
2
/*
10
15
20
25
30
35
40
45
50
55
60
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Letter;
Frequency;
*Code;
*LLink;
*RLink;
ItemStruct *ItemArray[MaxCount];
/* ---------------------------------------------------------------------- */
void InitItemArray(void)
{
int i;
char *Letters = "ETAONISRHLDCUPFMWYBGVKQXJZ";
ItemStruct *N;
for (i = 0; i< MaxCount; ++i) {
N = (ItemStruct *) malloc(sizeof(ItemStruct));
N>Letter = Letters[i];
N>LLink = NULL;
N>RLink = NULL;
ItemArray[i] = N;
}
/* input letter frequencies from Table 9.52, followed by */
/* Letter Huffman Code assigned by the algorithm given below */
ItemArray[ 0]>Frequency = 1231;
ItemArray[ 1]>Frequency = 959;
ItemArray[ 2]>Frequency = 805;
ItemArray[ 3]>Frequency = 794;
ItemArray[ 4]>Frequency = 719;
ItemArray[ 5]>Frequency = 718;
ItemArray[ 6]>Frequency = 659;
ItemArray[ 7]>Frequency = 603;
ItemArray[ 8]>Frequency = 514;
ItemArray[ 9]>Frequency = 403;
ItemArray[10]>Frequency = 365;
ItemArray[11]>Frequency = 320;
ItemArray[12]>Frequency = 310;
ItemArray[13]>Frequency = 229;
ItemArray[14]>Frequency = 228;
ItemArray[15]>Frequency = 225;
ItemArray[16]>Frequency = 203;
ItemArray[17]>Frequency = 188;
ItemArray[18]>Frequency = 162;
ItemArray[19]>Frequency = 161;
ItemArray[20]>Frequency = 93;
ItemArray[21]>Frequency = 52;
/* E - 100 */
/* T - 110 */
/* A - 0000 */
/* O - 0001 */
/* N - 0011 */
/* I - 0100 */
/* S - 0110 */
/* R - 1010 */
/* H - 1011 */
/* L - 00100 */
/* D - 01010 */
/* C - 01110 */
/* U - 01111 */
/* P - 11100 */
/* F - 11101 */
/* M - 11110 */
/* W - 001010 */
/* Y - 001011 */
/* B - 010110 */
/* G - 010111 */
/* V - 111111 */
/* K - 1111101 */
70
75
80
85
90
95
100
105
110
115
120
125
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ItemArray[22]>Frequency = 20;
ItemArray[23]>Frequency = 20;
ItemArray[24]>Frequency = 10;
ItemArray[25]>Frequency = 9;
/* Q - 11111001 */
/* X - 111110000 */
/* J - 1111100010 */
/* Z - 1111100011 */
} /* end for */
} /* ConstructHuffmanTree */
/* ---------------------------------------------------------------------- */
char *Concat(char *S, char c)
{
char *T,*temp;
T = (char *)malloc(2+strlen(S));
temp = T;
130
135
140
145
150
155
160
165
170
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*(++T) = '\0';
return temp;
}
/* ---------------------------------------------------------------------- */
void AssignHuffmanCodes(ItemStruct *N, char *CodeToAssign)
{
ItemStruct *L, *R;
/* Assume N is non-null */
N>Code = CodeToAssign;
L = N>LLink;
R = N>RLink;
if (L != NULL) AssignHuffmanCodes(L,Concat(CodeToAssign,'0'));
if (R != NULL) AssignHuffmanCodes(R,Concat(CodeToAssign,'1'));
} /* AssignHuffmanCodes */
/* ---------------------------------------------------------------------- */
void PrintHuffmanCodes(ItemStruct *N)
{
if (N != NULL) {
if ((N>RLink == NULL) && (N>LLink == NULL)) {
printf("%c %s\n", N>Letter, N>Code);
}
PrintHuffmanCodes(N>LLink);
PrintHuffmanCodes(N>RLink);
}
} /* PrintHuffmanCodes */
/* ---------------------------------------------------------------------- */
int main(void)
{
char *Test = "", *V;
InitItemArray();
ConstructHuffmanTree();
AssignHuffmanCodes(ItemArray[0],"");
PrintHuffmanCodes(ItemArray[0]);
}
/* main program */
is
in
V
x
is
V 5 = {4, 6}
V 2 = {1, 3, 4}
V 6 = {4, 5, 7, 8}
V 3 = {1, 2}
V 7 = {4, 6}
V 4 = {2, 5, 6, 7}
V 8 = {6}
|
|
|
|
|
|
|
10
15
20
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
*
* Solution to Ex. 10.3.2 -- converting a Graph representation from
*
-- array of linked lists of successor vertices to an
*
-- array of bit vectors representing adjacency sets
*
*/
#include <stdio.h>
#include<stdlib.h>
#define NumberOfVertices 5
#define ByteSize 8
#define ByteLength (NumberOfVertices/ByteSize +
(((NumberOfVertices % ByteSize) != 0)?1:0))
typedef struct NodeTag {
int
Item;
struct NodeTag *Link;
} NodeType;
typedef NodeType *ArrayOfLinkedLists[NumberOfVertices];
25
30
35
40
45
50
55
60
65
70
75
80
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PrintLinkedListGraph(ArrayOfLinkedLists F)
{
int i;
for (i=0; i<NumberOfVertices; ++i){
printf("%2d ",(i+1));
PrintList(F[i]);
}
}
int Member(int i, Set S)
{
i ;
/* membership is shifted from 1:n ==> 0:n1 */
return( ( S[i/ByteSize ] >> (i % ByteSize) ) & 1);
}
void InitializeSet(Set S)
{
int i;
for (i=0; i<ByteLength; ++i) S[i]='\0';
}
void InsertIntoSet(int i, Set S)
{
i;
/* insertion is shifted from the number range 1:n ==> 0:n1 */
90
95
100
105
110
115
120
125
130
135
140
145
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150
155
160
165
170
175
180
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Insert(3, 1, F);
Insert(2, 1, F);
Insert(5, 2, F);
Insert(4, 2, F);
Insert(3, 2, F);
Insert(4, 3, F);
Insert(1, 5, F);
*/
(2, 3, 4)
(3, 4, 5, 6)
1, 2
(4, 5, 6)
1, 2, 3
(5, 6, 7, 8)
1, 2, 3, 4
(6, 7, 8)
1, 2, 3, 4, 5
(7, 8)
1, 2, 3, 4, 5, 6
(8)
1, 2, 3, 4, 5, 6, 7
( )
1, 2, 3, 4, 5, 6, 7, 8
2. For the solutions to Exs. 10.4.2 and 10.4.3, see the program that
follows:
10
15
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
* Solutions to Exs. 10.4.2 and 10.4.3:
*
* Ex. 10.4.2 -- Refinement of Program Strategy 10.7 for Graph Searching
* Ex. 10.4.3 -- Recursive version of Program Strategy 10.7
*/
#include <stdio.h>
#include<stdlib.h>
#include "QueueInterface.h"
#define MaxVertexNumber 9
25
30
35
40
45
50
55
60
65
70
75
80
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
VertexNumber;
struct NodeTag *Link;
}Node;
typedef struct {
Boolean
Node
}Vertex;
Visited;
*AdjacencyList;
/* insert A into */
/* adjacency list */
/* of vertex B */
/* in Graph F */
85
90
100
105
110
115
120
125
130
135
140
145
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* G[8] = [6]; */
ListInsert(6,8,G);
}
/* ------------------------------------------------------------------ */
void Visit(int x)
{
printf("Visit Vertex Number: %2d.\n",x);
}
/* ------------------------------------------------------------------ */
void GraphSearch(ArrayOfVertices G, int v)
/* Ex. 10.4.2 -- */
{
/* refinement of Program Strategy 10.7, p. 416 */
int i,x;
Queue C;
Node *L;
/* Mark each vertex as being unvisited */
for (i = 1; i<MaxVertexNumber; ++i) {
G[i].Visited = false;
}
InitializeQueue(&C);
Insert(v,&C);
/* initialize C to be empty */
/* let the search begin at vertex v */
while (!Empty(&C)) {
Remove(&C,&x); /* remove a vertex from the container C */
if (! G[x].Visited) {
Visit(x);
/* mark x as having been visited */
G[x].Visited = true;
/* Enter all unvisited vertices of Vx into C */
L = G[x].AdjacencyList;
while (L != NULL) {
if (! G[L>VertexNumber].Visited) {
Insert(L>VertexNumber, &C);
}
L = L>Link;
}
}
}
}
/* ------------------------------------------------------------------ */
/* the following recursive procedure is the solution to Ex. 10.4.3 */
void RecursiveGraphSearch(ArrayOfVertices A, int v)
{
Node *L;
/* for the recursive function, assume each vertex of */
/* the graph has already been marked unvisited */
if (!A[v].Visited) {
Visit(v);
A[v].Visited = true;
L = A[v].AdjacencyList;
150
155
160
165
170
175
180
185
190
195
200
205
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (L != NULL) {
if (! A[L>VertexNumber].Visited) {
RecursiveGraphSearch(A, L>VertexNumber);
}
L = L>Link;
}
}
}
/* ------------------------------------------------------------------ */
void PrintLinkedListGraph(ArrayOfVertices A)
{
int i,j;
Node *L;
for (i = 1; i<MaxVertexNumber; ++i) {
L = A[i].AdjacencyList;
printf("G[%2d] = [",i);
while (L != NULL) {
printf("%2d ",L>VertexNumber);
L = L>Link;
}
printf("]\n");
}
putchar('\n');
}
/* ------------------------------------------------------------------ */
int main(void)
{
int i;
ArrayOfVertices G;
/* G is an array of vertices */
/* each vertex of which has */
/* a linked adjacency list */
InitGraph(G);
printf("print the graph of Figure 10.9 on p. 417:\n");
PrintLinkedListGraph(G);
printf("Search graph and print list of vertices visited.\n");
GraphSearch(G,1);
/* GraphSearch uses queue containers */
/* to test breadth-first search */
/* comment GraphSearch(G,1) above, and then uncomment */
/* RecursiveGraphSearch(G,1) below */
/* to test RecursiveGraphSearch */
/* RecursiveGraphSearch(G,1); */
}
/* end main */
/* The following is the printout from the program above:
print the graph of Figure 10.9 on p. 417:
G[ 1] = [ 2 3 4 ]
G[ 2] = [ 5 6 ]
G[ 3] = [ ]
G[ 4] = [ 7 8 ]
215
220
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
G[ 5] = [ ]
G[ 6] = [ 5 ]
G[ 7] = [ 1 3 6 ]
G[ 8] = [ 6 ]
Search graph and print list of vertices visited.
Visit Vertex Number: 1.
Visit Vertex Number: 2.
Visit Vertex Number: 5.
Visit Vertex Number: 6.
Visit Vertex Number: 3.
Visit Vertex Number: 4.
Visit Vertex Number: 7.
Visit Vertex Number: 8.
*/
3. See lines 133:154 of the program given above in Ex. 10.4.2 for the
solution to Ex. 10.4.3.
4. All you have to do is to remove the initialization code (on lines
8:10) from Program Strategy 10.7 and make the removed lines into
a separate procedure, called, say, MarkVerticesUnvisited(G) , following
which, you insert a call on MarkVerticesUnvisited(G) on line 4 of Program
Strategy 10.10, and then change line 6 of Program Strategy 10.10
to be: if (! v.Visited) GraphSearch(G,v);
10
15
20
25
30
35
40
45
50
55
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
* Solution to Exs. 10.5.1 and 10.5.3
*
* Ex. 10.5.1 -- Implement Program Strategy 10.12 for TopologicalOrder
* Ex. 10.5.3 -- Recursive version of Topological Order
*/
#include <stdio.h>
#include<stdlib.h>
#include "QueueInterface.h"
#define MaxVertexNumber 6
/* actually one greater than max vertex */
/* number because we use vertices in 1:n instead of 0:n-1 */
typedef struct NodeTag {
int
struct NodeTag
}Node;
typedef struct {
int
Node
}Vertex;
VertexNumber;
*Link;
InDegree;
*AdjacencyList;
/* ------------------------------------------------------------------ */
void InsertNewFirstNode (int A, Node **L)
{
Node *N;
N = (Node *)malloc(sizeof(Node));
N>VertexNumber = A;
N>Link = *L;
*L = N;
}
/* ------------------------------------------------------------------ */
void ListInsert(int A, int B, ArrayOfVertices F)
/* insert A into */
{
/* adjacency list of vertex B */
InsertNewFirstNode(A,&F[B].AdjacencyList);
/* in Graph F */
}
/* ------------------------------------------------------------------ */
void InitGraph(ArrayOfVertices G)
{
int i;
/* init G to the graph of Figure 10.11 on p. 420 */
65
70
75
80
85
90
95
100
105
110
115
120
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125
130
135
140
145
150
155
160
165
170
175
180
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Insert(x,TopoOrderList);
185
190
195
200
205
210
215
220
225
230
235
240
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
void PrintLinkedListGraph(ArrayOfVertices A)
{
int i,j;
Node *L;
for (i = 1; i<MaxVertexNumber; ++i) {
L = A[i].AdjacencyList;
printf("G[%2d] = [",i);
while (L != NULL) {
printf("%2d ",L>VertexNumber);
L = L>Link;
}
printf("]\n");
}
putchar('\n');
}
/* ------------------------------------------------------------------ */
void PrintQueue(Queue *Q)
{
ItemType x;
putchar('(');
while (!Empty(Q)) {
Remove(Q,&x);
printf("%2d ",x);
}
printf(")\n");
}
/* ------------------------------------------------------------------ */
int main(void)
{
int i;
ArrayOfVertices G;
InitGraph(G);
printf("print the graph of Figure 10.11 on p. 420:\n");
PrintLinkedListGraph(G);
/* make a list of the vertices of G in topological order */
InitializeQueue(&TopoOrderList);
TopologicalOrder(G, &TopoOrderList);
/* comment out function calls above and comment in these three */
/* InitializeQueue(&TopoOrderList); */
/* ComputeInDegrees(G); */
/* Compute the*/
/* InDegrees of the Graph G */
/* RecursiveTopoOrder(G,1); */
/* This function */
/* assumes InDegrees are already computed */
/* and that the TopoOrderList is initialized to empty */
printf("The list of vertices in topological order is = \n");
PrintQueue(&TopoOrderList);
/* Print the list of vertices */
/* in topological order */
}
250
255
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* end main */
/* The print out of the above program is as follows:
print the graph of Figure 10.11 on p. 420:
G[ 1] = [ 2 3 4 5 ]
G[ 2] = [ 4 ]
G[ 3] = [ 2 5 ]
G[ 4] = [ 5 ]
G[ 5] = [ ]
The list of vertices in topological order is =
(1 3 2 4 5)
*/
10
15
20
25
30
35
40
45
50
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
*
*/
#include <stdio.h>
#include<stdlib.h>
#define MaxVertex 6
#define Infinity 32000 /* it can't be INT_MAX, since adding small edge */
/* lengths to INT_MAX causes it to wrap to a */
/* big negative number. */
#define NumberOfVertices 7
#define ByteSize 8
#define ByteLength (NumberOfVertices/ByteSize +
(((NumberOfVertices % ByteSize) != 0)?1:0))
typedef int Weight;
typedef int Vertex;
typedef Weight AdjacencyMatrix[NumberOfVertices][NumberOfVertices];
typedef char Set[ByteLength];
AdjacencyMatrix T;
Set W;
Weight ShortestDistance[NumberOfVertices];
/* -------------------------------------------------------------- */
int Member(int i, Set S)
{
i ;
/* membership is shifted from 1:n ==> 0:n1 */
return ( ( S[i/ByteSize ] >> (i % ByteSize) ) & 1);
}
/* -------------------------------------------------------------- */
void InitializeSet(Set S)
{
int i;
for (i=0; i<ByteLength; ++i) S[i]='\0';
}
/* -------------------------------------------------------------- */
55
60
65
70
75
80
85
90
95
100
105
110
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120
125
130
135
140
145
150
155
160
165
170
175
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
T[4][5] = 6;
T[5][6] = 7;
T[6][4] = 2; T[6][3] = 8;
}
/* -------------------------------------------------------------- */
void PrintAdjacencyMatrix(AdjacencyMatrix T)
{
int i,j;
printf("---");
for (i=1; i<=MaxVertex; ++i) printf("%3d",i);
putchar('\n');
for (i=1; i<=MaxVertex; ++i) {
printf("%3d",i);
for (j=1; j<=MaxVertex; ++j) {
if (T[i][j] == Infinity) {
printf(" ");
} else {
printf("%3d",T[i][j]);
}
}
putchar('\n');
}
putchar('\n');
putchar('\n');
}
/* -------------------------------------------------------------- */
void PrintDistances(void)
{
int i;
printf("Shortest Distances to Vertices in Graph G\n");
for (i=1; i<=MaxVertex; ++i) {
printf("vertex %2d: %5d\n",i, ShortestDistance[i]);
}
}
/* -------------------------------------------------------------- */
Weight Minimum(Weight x, Weight y)
{
if (x < y) {
return x;
} else {
return y;
}
}
/* -------------------------------------------------------------- */
void ShortestPath(void)
{
/* Let MinDistance be a variable that contains edge weights */
/* as values and let Minimum(x,y) be a function whose value */
180
185
190
195
200
205
210
215
220
*/
225
230
235
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* W = [v1]; */
InitializeSet(W);
InsertIntoSet(v1,W);
ShortestDistance[v1] = 0;
for (v2 = 1; v2<=MaxVertex; ++v2) {
/* for each v2 in V [v1] */
if (!Member(v2,W)) ShortestDistance[v2] = T[v1][v2];
}
/* PrintDistances(); */
/* Now repeatedly enlarge W until W includes all vertices in V */
while (!Full(W)) {
/* while (W != V) { */
/* find the vertex v2 in V W of minimum distance from v1 */
MinDistance = Infinity;
for (w1=1; w1<=MaxVertex; ++w1) { /* for each w1 in V W */
if (!Member(w1,W)) {
/* if w1 in (V W) */
if (ShortestDistance[w1] < MinDistance) {
MinDistance = ShortestDistance[w1];
v2 = w1;
}
}
}
/* add v2 to W by doing W = W + [v2]; */
InsertIntoSet(v2,W);
printf("new vertex to add to W = %2d\n",v2);
/* update the shortest distances to vertices in V W */
for (u1=1; u1<=MaxVertex; ++u1) {/* for each u1 in V W
if (!Member(u1,W)) {
ShortestDistance[u1] =
Minimum(ShortestDistance[u1],
ShortestDistance[v2] + T[v2][u1]);
}
}
} /* end while */
}
/* end ShortestPath */
/* -------------------------------------------------------------- */
int main(void)
{
240
245
250
255
260
265
270
275
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initialization */
InitializeAdjacencyMatrix(T);
printf("The adjacency matrix for graph G is:\n");
PrintAdjacencyMatrix(T);
/* Find Shortest Path */
ShortestPath();
/* Print the ShortestDistances */
putchar('\n');
PrintDistances();
PrintSet(W);
}
/* end main program */
/* the printout obtained from running the above program is:
The adjacency matrix for graph G is:
--- 1 2 3 4 5 6
1 0 3 5
2 0 7 10
3 0 5 1
4 0 6
5 0 7
6 8 2 0
new
new
new
new
new
vertex
vertex
vertex
vertex
vertex
to
to
to
to
to
add
add
add
add
add
to
to
to
to
to
W
W
W
W
W
=
=
=
=
=
2
6
4
3
5
*/
S =
C*
=
=
(1in) [(n + 1) i] n
C*
[ n *(n + 1)
n (n +1)
n]
2
n (n +1)
2n
]
2
2
n 2 + n 2n
C * [
]
2
n2 n
C *[
]
2
n (n 1 )
C * [
] ,
2
C*
which is what we
wanted to show.
/*
10
15
20
25
30
35
40
45
50
55
60
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "QueueInterface.h"
#define MaxVertex 12
/* Actually MaxVertex == 1 + maximum vertex number used, in order */
/* to accommodate arrays indexed by 1:n instead of 0:n1 */
70
75
80
85
90
95
100
105
110
115
120
125
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
T[3][5] = 1;
T[4][5] = 1;
T[5][6] = 1; T[5][7] = 1; T[5][8] = 1;
T[6][9] = 1;
T[7][9] = 1;
T[8][9] = 1;
T[9][10] = 1;
T[10][11] = 1;
}
/* -------------------------------------------------------------- */
void PrintAdjacencyMatrix(AdjacencyMatrix T)
{
int i,j;
printf("The Adjacency Matrix is:\n\n");
printf("---");
for (i = 1; i<MaxVertex; ++i) printf("%3d",i);
putchar('\n');
for (i = 1; i<MaxVertex; ++i) {
printf("%3d",i);
for (j = 1; j<MaxVertex; ++j) {
printf("%3d",T[i][j]);
}
putchar('\n');
}
putchar('\n');
putchar('\n');
}
/* -------------------------------------------------------------- */
void PrintDurationArray(DurationArray D)
{
int i;
printf(" i = ");
for (i = 1; i<MaxVertex; ++i) printf("%3d",i);
putchar('\n');
printf(" A[i] = ");
for (i = 1; i<MaxVertex; ++i) printf("%3d",D[i]);
putchar('\n');
}
/* -------------------------------------------------------------- */
void PrintTopoOrderArray(void)
{
int i;
printf("
i = ");
for (i = 1; i<MaxVertex; ++i) printf("%3d",i);
putchar('\n');
printf("TopoOrder = ");
for (i = 1; i<MaxVertex; ++i) printf("%3d",TopoOrderArray[i]);
putchar('\n');
}
130
135
140
145
150
155
160
165
170
175
180
185
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------- */
void PrintQueue(Queue *Q)
{
ItemType x;
putchar('(');
while (!Empty(Q)) {
Remove(Q,&x);
printf("%2d ",x);
}
printf(")\n");
}
/* -------------------------------------------------------------- */
void TopologicalOrder(void)
{
DurationArray InDegree;
ItemType x,w,i,j;
/* vertices are item types for use in queues */
Queue Q,L;
/* Compute the in-degrees InDegree[x] of the vertices x in G */
for (x=1; x<MaxVertex; ++x) InDegree[x] = 0;
/* initialize */
/* InDegree[x] to zero */
for (x=1; x<MaxVertex; ++x) {
for (w=1; w<MaxVertex; ++w) InDegree[x] += T[w][x];
}
/* Initialize the queue Q to contain all vertices */
/* having zero in-degrees */
InitializeQueue(&Q); /* initialize Q to be the empty queue */
for (x=1; x<MaxVertex; ++x) {
if (InDegree[x] == 0) Insert(x,&Q);
/* insert x */
/* on the rear of Q if InDegree[x] = 0 */
}
/* Initialize the list L to be the empty list */
InitializeQueue(&L);
/* for simplicity, we let the list L */
/* be represented by a queue, also. */
/* Process vertices in the queue Q until the */
/* queue becomes empty */
while (!Empty(&Q)) {
Remove(&Q,&x);
/* Remove vertex x from front of Q */
Insert(x,&L);
/* Insert x on rear of list L */
for (w=1; w<MaxVertex; ++w) { /* for each successor w */
/* of x, where w in Vx */
if (T[x][w] == 1) {
/* i.e., if w is a successor of x */
InDegree[w] ;
/* decrease predecessor */
/* count of w */
if (InDegree[w] == 0) {
Insert(w,&Q);
/* insert w */
}
/* on the rear of Q */
}
}
}
/* The list L now contains the vertices of G in topological order */
/* Remove them one by one and put them into TopoOrderArray. */
for (i=1; i<MaxVertex; ++i) {
190
195
200
205
210
215
220
225
230
235
240
245
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Remove(&L,&x);
TopoOrderArray[i] = x;
}
}
/* end TopologicalOrder */
/* -------------------------------------------------------------- */
Boolean EmptyPred(VertexNumber v)
{
VertexNumber w;
Boolean result;
result = true;
for (w=1; w<MaxVertex; ++w) {
if (T[w][v] == 1) {
result = false;
break;
}
}
/* w is a predecessor of v */
return result;
}
/* -------------------------------------------------------------- */
void ComputeEarliestFinishTimes(void)
{
VertexNumber i,v,w;
for (i=1; i<MaxVertex; ++i) {
v = TopoOrderArray[i];
if (EmptyPred(v)) {
EFT[v] = D[v];
} else {
EFT[v] = 0;
for (w=1; w<MaxVertex; ++w) {
/* w in Pred(v) */
if (T[w][v] == 1) {
/* if w is a predecessor of v */
if (EFT[w] + D[v] > EFT[v]) {
EFT[v] = EFT[w] + D[v];
}
}
}
}
}
}
/* -------------------------------------------------------------- */
void ComputeProjectFinishTime(Duration *PFT)
{
VertexNumber v;
/* The earliest Project Finish Time, PFT, is the latest of the */
/* earliest finishing times for any of the vertices in the graph. */
*PFT = 0;
for (v=1; v<MaxVertex; ++v) {
255
260
265
270
275
280
285
290
295
300
305
310
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* w is a successor of v */
}
/* -------------------------------------------------------------- */
void ComputeLatestFinishTimes(void)
{
VertexNumber i,v,w;
for (i=MaxVertex; i>=1; i) {
v = TopoOrderArray[i];
if (EmptySucc(v)) {
LFT[v] = PFT;
} else {
LFT[v] = PFT;
for (w=1; w<MaxVertex; ++w) {
/* w in Succ(v) */
if (T[v][w] == 1) {
/* w is a successor of v */
if (LFT[w] D[w] < LFT[v]) {
LFT[v] = LFT[w] D[w];
}
}
}
}
}
}
/* ComputeLatestFinishTimes */
/* -------------------------------------------------------------- */
void ComputeLatestStartTimes(void)
{
VertexNumber v;
for (v=1; v<MaxVertex; ++v) LST[v] = LFT[v] D[v];
}
/* -------------------------------------------------------------- */
void ComputeEarliestStartTimes(void)
{
315
320
325
330
335
340
345
350
355
360
365
370
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VertexNumber v;
for (v=1; v<MaxVertex; ++v) EST[v] = EFT[v] D[v];
}
/* -------------------------------------------------------------- */
void PrintVerticesOnCriticalPath(void)
{
VertexNumber v;
printf("Vertices on Critical Path = \n");
for (v=1; v<MaxVertex; ++v) {
if (EST[v] == LST[v]) printf(" %3d",v);
}
}
/* -------------------------------------------------------------- */
int main(void) /* MainProgram */
{
/* Note: the following are declared globally:
AdjacencyMatrix T;
DurationArray D,EFT,EST,LFT,LST;
Duration PFT;
VertexNumber TopoOrderArray[MaxVertex];
*/
/* Initialization */
InitializeAdjacencyMatrix(T);
/* PrintAdjacencyMatrix(T); */
InitializeDurationArray(D);
/* printf("Duration Array:\n"); */
/* PrintDurationArray(D); putchar('\n'); */
/* Compute Topological Order */
TopologicalOrder();
PrintTopoOrderArray(); putchar('\n');
/* Compute Critical Path & Other Times in Activity Network */
ComputeEarliestFinishTimes();
ComputeProjectFinishTime(&PFT);
ComputeLatestFinishTimes();
ComputeLatestStartTimes();
ComputeEarliestStartTimes();
/* Print Results */
printf("Earliest Finish Times:\n");
PrintDurationArray(EFT); putchar('\n');
printf("Project Finish Time, PFT = %d\n",PFT);
printf("Latest Finish Times:\n");
PrintDurationArray(LFT); putchar('\n');
printf("Latest Start Times:\n");
PrintDurationArray(LST); putchar('\n');
printf("Earliest Start Times:\n");
PrintDurationArray(EST); putchar('\n');
/* Print vertices on Critical Path */
PrintVerticesOnCriticalPath();
380
385
390
395
400
405
410
415
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
/* main program */
/* the printout obtained from running the above program is:
The Adjacency Matrix is:
--1
2
3
4
5
6
7
8
9
10
11
1
0
0
0
0
0
0
0
0
0
0
0
2
1
0
0
0
0
0
0
0
0
0
0
3
0
1
0
0
0
0
0
0
0
0
0
4
1
0
0
0
0
0
0
0
0
0
0
6
0
0
0
0
1
0
0
0
0
0
0
7
0
0
0
0
1
0
0
0
0
0
0
8
0
0
0
0
1
0
0
0
0
0
0
Duration Array:
i =
1 2
A[i] =
0 5
3 4
9 20
5
2
6 7 8
3 10 15
9 10 11
2 10 0
i =
TopoOrder =
2
2
4
3
5
5
8
8
1
1
5
0
0
1
1
0
0
0
0
0
0
0
3
4
9 10 11
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
1 0 0
1 0 0
1 0 0
0 1 0
0 0 1
0 0 0
6
6
7
7
9 10 11
9 10 11
11
*/
2. Two noncritical tasks share the same slack time if they are in
series (i.e., if one task either precedes or follows the other along
a path), whereas two noncritical tasks are independent if they are
in parallel (i.e., if they are on separate paths or path segments
such that neither precedes or follows the other). Independent
noncritical tasks have independent slack times that do not need to
be shared. A slack time t shared between two tasks t 1 and t 2
means that if t 1 uses a portion u of t to delay its completion
time, then t 2 cannot delay its completion time by more than t u
without delaying the project completion time. That is, shared slack
B2
J10
W23
X24
S19
N14
B2
J10
W23
X24
N14
S19
10
15
20
25
30
35
40
45
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
*
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#define MaxIndex 6
#define TableSize 7
typedef char KeyType;
typedef struct NodeTag{
KeyType
Key;
struct NodeTag *Link;
}Node;
typedef Node * HashTable[TableSize];
/* -------------------------------------------------------------- */
int h(KeyType K)
{
return (1+ (int)(K) (int)('A')) % TableSize;
}
/* -------------------------------------------------------------- */
void InitializeTable(HashTable T)
{
int i;
for (i=0; i<TableSize; ++i) T[i] = NULL;
}
/* -------------------------------------------------------------- */
void Insert(KeyType K, HashTable T)
{
Node *L, *N;
L = T[h(K)];
/* obtain pointer to list on which to insert K */
N = (Node *)malloc(sizeof(Node)); /* create a new list node, N */
50
55
60
65
70
75
80
85
90
95
100
105
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
N>Key = K;
N>Link = L;
T[h(K)] = N;
}
/* -------------------------------------------------------------- */
Node *Find(KeyType K, HashTable T)
{
Node *L;
L = T[h(K)];
while (L != NULL) {
if (L>Key == K) {
return L;
}
L = L>Link;
}
return L;
}
/* -------------------------------------------------------------- */
void PrintTable(HashTable T)
{
int i; Node *L;
for (i=0; i<TableSize; ++i) {
L = T[i];
printf("T[%2d] = (",i);
while (L != NULL) {
putchar(L>Key);
if (L>Link != NULL) putchar(',');
L= L>Link;
}
printf(")\n");
}
putchar('\n');
}
/* -------------------------------------------------------------- */
void SearchAndPrint(KeyType K, HashTable T)
{
Node *N;
printf("Searching for Key '%c' in Table T\n",K);
N = Find(K,T);
if (N != NULL) {
printf(" Found %c\n",N>Key);
} else {
printf(" Key '%c' not Found in Table T\n",K);
}
}
/* -------------------------------------------------------------- */
int main(void)
115
120
125
130
135
140
145
150
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
HashTable T;
InitializeTable(T);
Insert('X',T);
Insert('W',T);
Insert('J',T);
Insert('B',T);
Insert('N',T);
Insert('S',T);
PrintTable(T);
10
15
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
*
*/
#include <stdio.h>
#include <stdlib.h>
double P(int n)
{
int i;
double temp;
temp = 1.0;
for (i=2; i<=n; ++i) {
temp = temp * (365.0 i + 1) / 365.0;
}
20
25
30
35
40
45
50
55
60
65
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
P(n)\n");
P(n)
0.02713557
0.11694818
0.25290132
0.41143838
0.47569531
0.50729723
0.56869970
0.70631624
0.81438324
0.89123181
0.94097590
0.97037358
0.98626229
0.99412266
0.99768311
0.99915958
0.99971988
0.99991433
0.99997600
0.99999385
0.99999856
0.99999969
*/
1.45
1
5.50
1
Hence, theoretically, separate chaining takes the least number of
probes.
2.56
Proof :
Suppose there exist i, j 1:2n for which i j and
i( i 1 )
j( j 1 )
n
mod
2
=
mod 2n.
2
2
Then,
But
=
=
=
i( i 1 )
2
i( i 1 )
i2
j( j 1 )
j( j 1 )
j2
+ j
( i2 j2 ) ( i j)
( i + j) ( i j) ( i j)
2
( i + j 1 ) ( i j)
Thus,
( i + j 1 ) ( i j)
2
Therefore, ( i + j 1 ) ( i j )
2 n + 1. Now, we consider two cases:
i
1
2
3
4
5
6
7
8
9
10
i( i 1 ) i( i 1 )
2
0
1
3
6
10
15
21
28
36
45
0
1
3
6
2
7
5
4
4
5
mod 8
10
15
20
25
30
35
40
45
50
55
60
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
*
*/
#include <stdio.h>
#define TABLESIZE 8
#define EmptyKey '\0'
typedef char KeyType;
typedef int InfoType;
typedef struct {
KeyType Key;
InfoType Info;
} TableEntry;
typedef TableEntry Table[TABLESIZE];
Table T;
/* ------------------------------------------------------ */
int h(KeyType L)
{
return (1 + (int)(L) (int)('A')) % TABLESIZE;
}
/* ------------------------------------------------------ */
void InitializeTable(Table T)
{
int i;
for (i=0; i<TABLESIZE; ++i) {
T[i].Key = EmptyKey;
T[i].Info = 0;
}
}
/* ------------------------------------------------------ */
void PrintTable(Table T)
{
int i;
for (i=0; i<TABLESIZE; ++i) {
if (T[i].Key != EmptyKey) {
printf("%2d: %c%d\n",i,T[i].Key,1 + (int)(T[i].Key) (int)('A'));
} else {
printf("%2d: %c\n",i,T[i].Key);
}
}
putchar('\n');
}
/* ------------------------------------------------------ */
void HashInsert (KeyType K, InfoType I)
65
70
75
80
85
90
95
100
105
110
115
120
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
int i, j;
KeyType ProbeKey;
/* Initializations */
i = h(K);
/* first hash */
j = 0;
/* initialize counter for triangle number hashing */
ProbeKey = T[i].Key;
/* find first empty slot */
while (ProbeKey != EmptyKey) {
++j;
/* increment triangle number hashing counter */
i = j;
/* compute next probe location */
if (i < 0) {
i += TABLESIZE;
/* wrap around if needed */
}
ProbeKey = T[i].Key;
}
/* Insert new key and info into table */
T[i].Key = K;
T[i].Info = I;
}
/* ------------------------------------------------------ */
int HashSearch (KeyType K)
{
int i,j;
KeyType ProbeKey;
/*Initializations */
i = h(K);
/* first hash */
j = 0;
/* intialize counter for triangle number hashing */
ProbeKey = T[i].Key;
/* Find either an entry with key K, or the first empty entry */
while (ProbeKey != K && ProbeKey != EmptyKey) {
++j;
/* increment triangle number hashing counter */
i = j;
/* decrement probe location by amount j */
if (i < 0) {
/* wrap around if needed */
i += TABLESIZE;
}
ProbeKey = T[i].Key;
}
/* return the position of key K in table, or return -1 if K not in T */
if (ProbeKey == EmptyKey) {
return 1;
/* return 1 to signify K was not found */
} else {
return i;
/* return location, i, of key K in table T */
}
}
/* ------------------------------------------------------ */
void SearchAndReportLocation(KeyType K)
{
int result;
result = HashSearch(K);
printf("Searched for Key %c, ",K);
130
135
140
145
150
155
160
165
170
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
X-24
J-10
B-2
S-19
A-1
N-14
W-23
Searched
Searched
Searched
Searched
Searched
Searched
Searched
Searched
for
for
for
for
for
for
for
for
Key
Key
Key
Key
Key
Key
Key
Key
N,
B,
J,
X,
S,
W,
A,
C,
Found
Found
Found
Found
Found
Found
Found
Found
it
it
it
it
it
it
it
it
at
at
at
at
at
at
at
at
Table
Table
Table
Table
Table
Table
Table
Table
Location
Location
Location
Location
Location
Location
Location
Location
== 6
== 2
== 1
== 0
== 3
== 7
== 4
== 1
*/
10
15
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
*
*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
long A, Result, W, i;
A = 20071;
W = 32768;
for (i=0; i<16; ++i) {
Result = ((A*(i+1)) % W) / 2048;
printf("%3ld",i);printf(": %3ld\n",Result);
}
25
30
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
/* end main */
/* The printout for this program is:
0: 9
1: 3
2: 13
3: 7
4: 1
5: 10
6: 4
7: 14
8: 8
9: 2
10: 11
11: 5
12: 15
13: 9
14: 3
15: 12
*/
1
2*60
1
120
0.008333,
or 8 1 / 3
n +1
3
n2
where
n +1
(n +1)( n )( n 1)
.
6
| i j |
j= 1
.
n2
Consider an n n matrix T with rows i and columns j such that T[ i, j]
= |i j|. The matrix is symmetric and has a zero diagonal, since T[ i,
j ] = |i j | = |j i |= T[ j , i ] and T[ i , i ] = |i i | = 0. So if S is the sum of
the elements above the diagonal, the average is given by A =
2*S/ n 2 . The n elements of T on the diagonal are zero. The (n 1 )
elements above the diagonal are 1. The ( n 2) elements two above
the diagonal are 2. And so on, until the one element in the upper
right corner is (n 1). Hence, the sum S of the elements of T above
n
the diagonal is, S = i * ( n i ) .
i= 0
We need to compute A =
i= 1
0 1 2 3
0 1 2
Here, we have S =
4*1.
0 1
i* ( n i) =
Hence, S =
i= 0
i= 0
i= 0
i* n i 2 .
Using Formula A.29 from the Math Reference appendix for the
sum of the squares ( 1 i n ) i2 = n ( n +1)(2 n +1)/6, we get,
n
i = 0
S= n
n (n +1)(2n +1)
6
n ( n +1)
= n
n (n +1)(2n +1)
n (n +1)
=
[3n 2n 1]
6
6
n +1
(n +1)( n )(n 1)
= 3 .
But A = 2 S/n 2 , so
n +1
3
n2
2
A =
3. We can use the result of the previous exercise to prove that the
average of |i j| for i, j chosen randomly from 1:n is n / 3 .
n +1
3
n2
2
A =
2( n +1)( n )(n 1)
.
6n2
Simplifying A, we get
n3
n
n
1
.
2
2
3n
3n
3
3n
Hence, the difference between n / 3 and A is n / 3 A = 1 / 3 n . The
quantity 1 / 3 n . becomes small as n becomes large. For example, for
n = 100,
A
( n 2 1) n
3n2
1 0 1
3
1002
33.333333... .
2*166650
10000
= 33.33,
and
3 =
100
3
7 t r a c k s
c y l i n d e r s
* 6 4 s e c t o r s * 2 0 4 8 b y t e s =
*
disk
track
s e c t o r
cylinder
110,100,480 bytes
A.31 (which is
1 i n
lg i
= (n + 1 ) q 2( q + 1 ) + 2, where q =
S =
2 i n
1 i n
lg i + 2 ) =
2 i n
lg i +
2 i n
lg( n +1)
<
array index
i=
0 1 2 3
initial array A = [ 2, 7, 4, 1,
== 1
R = A[1:6 ] in
A = [ 1, 7, 4, 2, 3, 5,
R = A[2:6 ] in
A = [ 1, 2, 4, 7, 3, 5,
R = A[3:6 ] in
A = [ 1, 2, 3, 7, 4, 5,
R = A[4:6 ] in
A = [ 1, 2, 3, 4, 7, 5,
R = A[5:6 ] in
A = [ 1, 2, 3, 4, 5, 7,
R = A[6:6 ] in
A = [ 1, 2, 3, 4, 5, 6,
A complete C program which uses
10
|
|
|
|
|
|
|
|
|
|
|
|
4 5 6
3, 5, 6 ] , swap A[ 0 ] == 2 & A[ 3 ]
6 ] , swap A[ 1 ] == 7 & A[ 3 ] == 2
6 ] , swap A[ 2 ] == 4 & A[ 4 ] == 3
6 ] , swap A[ 3 ] == 7 & A[ 4 ] == 4
6 ] , swap A[ 4 ] == 7 & A[ 5 ] == 5
6 ] , swap A[ 5 ] == 7 & A[ 6 ] == 6
7 ].
this example is as follows:
/*
* Ex. 13.4.1 -- Worst Case QuickSort
*/
#include <stdio.h>
#include <stdlib.h>
#define MaxIndex 7
typedef int KeyType;
15
20
25
30
35
40
45
50
55
60
65
70
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initialize A to [2,7,4,1,3,5,6] */
80
85
90
95
100
105
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3
1
=
0,
3
2
1,
3
7
2,
3
7
3,
3
4
4,
3
4
5,
3
4
3
4
4
3
i
4
3
i
4
3
i
4
4
i
4
7
i
4
5
i
4
5
4
5
5
5
=
1,
5
5
2,
5
5
3,
5
5
4,
5
5
5,
5
7
6,
5
6
5
6
6
6
and
6
6
and
6
6
and
6
6
and
6
6
and
6
6
and
6
7
6
7
Array A =
Array A =
Array A =
Array A =
Array A =
Array A =
*/
n1
S=
i= 1
i
2
+ 1 =
1
2
n1
i = 1
i + (n 1)
1
2
1
4
[ n ( n 1 ) + 4 ( n 1 )]
S =
n ( n 1 )
+ (n 1)
2
(n + 4)(n 1 )
4
moves of keys.
10
15
20
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
* Ex. 13.6.1 -- Radix Sorting Example Using 3-Letter Airport Codes
*/
/* This program uses a parallel array representation of linked-list nodes. */
/* The SortingArray, A, contains the keys, which are three-letter Airport */
/* Codes. In parallel to the SortingArray is a Link array holding links to */
/* successor nodes on the linked list of nodes holding AirportCodes and */
/* links. There is also an array of 26 "Bins" -- one for each letter of the */
/* alphabet. Each bin has a Front pointer and a Rear pointer which point to */
/* the respective front and rear of a linked list of nodes that fall into that bin */
/* during Radix Sorting. */
#include <stdio.h>
#include <stdlib.h>
#define MaxIndex 32
#define MaxLetter 'Z'+1
#define null
0
typedef int LinkAddress;
25
30
35
40
45
50
55
60
65
70
75
80
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90
95
100
105
110
115
120
125
130
135
140
145
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Link[MaxIndex] = null;
for (i = (MaxIndex - 1); i>0; i) {
Link[i] = i+1;
}
*ListHead = 1;
}
/* ------------------------------------------------------------------------------- */
void InitializeBins(void)
{
int C;
for (C = 'A'; C <= 'Z'; ++C) {
Front[C] = null;
Rear[C] = null;
}
}
/* ------------------------------------------------------------------------------- */
void PrintList(SortingArray A, LinkAddress L)
{
int counter = 0;
while (L != null) {
printf("%s ",A[L]);
if (((++counter)%11) == 0) {
putchar('\n');
/* print a return every 11 airport codes */
}
L = Link[L];
}
printf("\n\n");
}
/* ------------------------------------------------------------------------------- */
LinkAddress RadixSort(SortingArray A)
{
int k;
LinkAddress ListHead, CurrentNode;
/* initialize the linked list and let ListHead point to first node */
InitializeLinkedList(&ListHead);
/* make three passes from least to most significant radix digit k */
for (k = 2; k>=0; k) {
/* initialize the bins to point to empty lists */
InitializeBins();
/* scan the list and insert key-records into lists in the bins */
while (ListHead != null) {
CurrentNode = ListHead;
ListHead = Link[ListHead];
Insert(CurrentNode,k);
}
/* sweep the bins and link them into a linked list */
150
155
160
165
170
175
180
185
190
195
200
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ListHead = SweepBinsAndLink();
printf("pass number = %1d\n",3-k);
PrintList(A,ListHead);
}
return ListHead;
}
/* ------------------------------------------------------------------------------- */
int main(void)
{
/* Initialize the array A and print it */
InitializeLinkedList(&ListHead);
printf("Original Unsorted Array =\n");
PrintList(A,ListHead);
/* Then RadixSort the array A and print it */
ListHead = RadixSort(A);
printf("Final Sorted Array =\n");
PrintList(A,ListHead);
}
/* main program */
/* -------------------------------------------------------------- */
/* when executed, the above program prints:
Original Unsorted Array =
DUS MEX ORD RAL ABQ ONT NRT YYZ GLA ZRH BUF
DFW DEN ARN JAX BRU CRQ MIA SEA STL HOU SAN
GCM HKG PIT MKC SFO JFK ORY LGA ORL
pass number = 1
GLA MIA SEA LGA MKC ORD BUF HKG ZRH JFK RAL
STL ORL GCM DEN ARN SAN SFO ABQ CRQ DUS ONT
NRT PIT BRU HOU DFW MEX JAX ORY YYZ
pass number = 2
RAL SAN JAX ABQ GCM SEA DEN MEX JFK SFO DFW
LGA MIA PIT MKC HKG GLA ONT HOU ORD ZRH ORL
ARN CRQ NRT BRU ORY STL BUF DUS YYZ
pass number = 3
ABQ ARN BRU BUF CRQ DEN DFW DUS GCM GLA HKG
HOU JAX JFK LGA MEX MIA MKC NRT ONT ORD ORL
ORY PIT RAL SAN SEA SFO STL YYZ ZRH
Final Sorted Array =
ABQ ARN BRU BUF CRQ DEN DFW DUS GCM GLA HKG
HOU JAX JFK LGA MEX MIA MKC NRT ONT ORD ORL
ORY PIT RAL SAN SEA SFO STL YYZ ZRH
*/
/* -------------------------------------------------------------- */
10
11
12
4.2,
1.5,
5.7, 12.6,
4.7,
7.2, 12.1,
2.9,
0.7,
8.1,
9.3]
hit counts:
i = 0
H[i] = 1
1
1
2
1
3
1
4
2
5
1
6
0
7
1
8
1
9
1
10
0
11
0
12
3
prox map:
P[i] = 0
10
insertion locations:
L[i] = 3
10
4
i = 0
1
2
1
3
6
4
10
5
4
6
7
7
10
8
2
9
0
10
8
11
9
12
10
15
20
25
30
35
40
45
50
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
* Ex. 13.6.2 -- Computing Hit Counts, Proxmap, and Insertion Locations
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MaxIndex 13
typedef long int
typedef double
LongInt;
KeyType;
Status;
Proxmap, InsertionLoc;
Key;
/* -------------------------------------------------------------- */
void PrintArray1(SortingArray A)
{
int i,K;
putchar('[');
for (i = 0; i < MaxIndex; ++i) {
K = MapKey(A[i].Key);
if ((A[i].Status == NotYetMoved) || (A[i].Status == Empty) ) {
printf("-----");
} else {
printf("%5.1f",A[i].Key);
}
if (i<MaxIndex-1) putchar(',');
}
printf("]");
}
60
65
70
75
80
85
90
95
100
105
110
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------- */
void ProxmapSort(SortingArray A)
{
int
i, j, RunningTotal, TempInt;
KeyType
KeyToInsert, TempKey;
Boolean
NotInserted;
char
c;
/* Initialize Status and Proxmap */
for (i = 0; i < MaxIndex; ++i) {
A[i].Proxmap = 0;
/* init Proxmap to all zeroes */
A[i].Status = NotYetMoved;
}
/* Count hits when keys are mapped into insertion locations */
for (i = 0; i < MaxIndex; ++i) {
j = MapKey(A[i].Key);
A[i].InsertionLoc = j;
A[j].Proxmap++;
}
/* Print hit counts */
printf("\nhit counts:\n");
for (i = 0; i < MaxIndex; ++i) printf("%6d",i);
putchar('\n');
for (i = 0; i < MaxIndex; ++i) printf("%6d",A[i].Proxmap);
putchar('\n');
/* Convert hit counts to a Proxmap */
RunningTotal = 0;
for (i = 0; i < MaxIndex; ++i) {
if (A[i].Proxmap > 0) {
TempInt = A[i].Proxmap;
A[i].Proxmap = RunningTotal;
RunningTotal += TempInt;
}
}
/* Print Proxmap and check it */
printf("\nprox map:\n");
for (i = 0; i < MaxIndex; ++i) printf("%6d",A[i].Proxmap);
putchar('\n');
/* Compute InsertionLocs */
for (i = 0; i < MaxIndex; ++i) {
A[i].InsertionLoc = A[A[i].InsertionLoc].Proxmap;
}
/* Print insertion locations */
printf("\ninsertion locations:\n");
for (i = 0; i < MaxIndex; ++i) printf("%6d",A[i].InsertionLoc);
putchar('\n');
for (i = 0; i < MaxIndex; ++i) printf("%6d",i);
putchar('\n');
PrintArray1(A);
putchar('\n');
/* Now, A[i].InsertionLoc gives insertion location for A[i].Key */
115
120
125
130
135
140
145
150
155
160
165
170
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If KeyToInsert < */
/* A[j].Key */
TempKey = A[j].Key;
/* swap KeyToInsert */
A[j].Key = KeyToInsert;
/* and A[j] */
KeyToInsert = TempKey;
}
j++;
} else {
A[j].Key = KeyToInsert;
A[j].Status = Moved;
NotInserted = false;
}
PrintArray1(A);
c = getchar();
}
/* end while */
}
/* end if */
}
/*end for */
}
/* end ProxmapSort */
/* -------------------------------------------------------------- */
void PrintArray(SortingArray A)
{
int i,K;
for (i=0; i<MaxIndex; ++i) printf("%6d",i);
printf("\n[");
for (i=0; i<MaxIndex; ++i) {
K = MapKey(A[i].Key);
printf("%5.1f",A[i].Key);
if (i < MaxIndex1) putchar(',');
/* A[j].Status = Empty */
180
185
190
195
200
205
210
215
220
225
230
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
printf("]\n");
}
/* -------------------------------------------------------------- */
void InitArray(SortingArray A)
{
int i;
KeyType B[ ] = { 3.5, 12.3, 4.2, 1.5, 5.7, 12.6,
4.7, 7.2, 12.1, 2.9, 0.7, 8.1, 9.3
};
for (i=0; i<MaxIndex; ++i) A[i].Key = B[i];
}
/* -------------------------------------------------------------- */
int main(void)
{
SortingArray A;
/* Initialization */
InitArray(A);
PrintArray(A);
/* sort the array A */
ProxmapSort(A);
PrintArray(A);
}
/* end main */
/* -------------------------------------------------------------- */
/* the printout was:
0
1
3.5, 12.3,
2
4.2,
3
1.5,
4
5
5.7, 12.6,
6
4.7,
7
8
7.2, 12.1,
9
2.9,
10
0.7,
11
8.1,
12
9.3]
1
1
2
1
3
1
4
2
5
1
6
0
7
1
8
1
9
1
10
0
11
0
12
3
10
10
10
hit counts:
0
1
prox map:
0
insertion locations:
3
10
240
245
|
|
|
|
|
|
|
|
|
|
|
|
[
[
[
[
[
[
[
[
0.7,
0.7,
0.7,
0.7,
0.7,
0.7,
0.7,
0
0.7,
1.5,-----,
1.5,-----,
1.5,-----,
1.5,-----,
1.5,-----,
1.5, 2.9,
1.5, 2.9,
1
2
1.5, 2.9,
3.5,
3.5,
3.5,
3.5,
3.5,
3.5,
3.5,
3
3.5,
4.2,
4.2,
4.2,
4.2,
4.2,
4.2,
4.2,
4
4.2,
4.7,
4.7,
4.7,
4.7,
4.7,
4.7,
4.7,
5
4.7,
5.7,-----,
5.7,-----,
5.7,-----,
5.7,-----,
5.7,-----,
5.7,-----,
5.7, 7.2,
6
7
5.7, 7.2,
8.1,-----,
8.1,-----,
8.1,-----,
8.1,-----,
8.1, 9.3,
8.1, 9.3,
8.1, 9.3,
8
9
8.1, 9.3,
12.3,
12.1,
12.1,
12.1,
12.1,
12.1,
12.1,
10
12.1,
12.6,-----]
12.6,-----]
12.3,-----]
12.3, 12.6]
12.3, 12.6]
12.3, 12.6]
12.3, 12.6]
11
12
12.3, 12.6]
*/
/* -------------------------------------------------------------- */
10
|
|
|
|
|
|
|
|
|
|
|
/*
* Ex. 13.7.1 & 13.7.2 -- Three Versions of BubbleSort including
*
FasterBubbleSort & CocktailShakerSort
*/
#include <stdio.h>
#include <stdlib.h>
/* -------------------------------------------------- */
void BubbleSort(SortingArray A)
15
20
25
30
35
40
45
50
55
60
65
70
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
int
KeyType
Boolean
i;
Temp;
NotFinished;
do {
NotFinished = false;
for (i = 0; i < MaxIndex 1; ++i) {
if (A[i] > A[i+1]) {
/* exchange A[i] and A[i+1] */
Temp = A[i]; A[i] = A[i+1]; A[i+1]=Temp;
/* if you made an exchange you are not finished and */
/* you need another pass */
NotFinished = true;
}
}
} while (NotFinished);
/* NotFinished = false iff you made a */
/* pass and no pair of keys was out of order */
}
/* -------------------------------------------------- */
void FasterBubbleSort(SortingArray A)
{
int
i, UpperIndex;
KeyType Temp;
Boolean NotFinished;
UpperIndex = MaxIndex 2;
do {
NotFinished = false;
for (i = 0; i <= UpperIndex; ++i) {
if (A[i] > A[i+1]) {
/* exchange A[i] and A[i+1] */
Temp = A[i]; A[i] = A[i+1]; A[i+1]=Temp;
/* if you made an exchange you are not finished and */
/* you need another pass */
NotFinished = true;
}
}
UpperIndex ;
} while (NotFinished);
/* NotFinished = false iff you made a */
/* pass and no pair of keys was out of order */
}
/* -------------------------------------------------- */
void CocktailShakerSort(SortingArray A)
{
int
i, LowerIndex, UpperIndex;
KeyType Temp;
Boolean NotFinished;
LowerIndex = 0;
UpperIndex = MaxIndex 2;
do {
NotFinished = false;
for (i = LowerIndex; i <= UpperIndex; ++i) {
if (A[i] > A[i+1]) {
/* exchange A[i] and A[i+1] */
80
85
90
95
100
105
110
115
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
to rewrite it as
E+T
E + T*F
E + T*P
E + T*a
E + F*a
E + P*a
E + a*a
T + a*a
F + a*a
F P + a*a
F a + a*a
P a + a*a
( E ) a + a*a
(E T) a + a*a
(E F) a + a*a
(E P) a + a*a
(E a) a + a*a
(T a) a + a*a
(F a) a + a*a
(P a) a + a*a
apply production
EE+T
TF
FP
Pa
TF
FP
Pa
ET
TF
FF P
Pa
FP
P(E)
EET
TF
FP
Pa
ET
TF
FP
Pa
EE+T | ET | F
TT*F | T/F | F
FFU | U
UP |+P | P
P(E) | a
10
15
20
25
30
35
40
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
* Ex. 14.3.1 the "ParserUtilities.c" module
*
* This module exports parser utility services. It uses the same sequential
* stack representation as is used for Program 7.5, the parenthesis matching
* program in Chapter 7.
*/
#include "ParserUtilities.h"
/******
*
* The ParserUtilities.h file contains the following external declarations:
*
*****/
/*
#include
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<string.h>
<ctype.h>
"SeqStackInterface.h"
45
50
55
60
65
70
75
80
85
90
95
100
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Next;
char
*Answer = "blank",
/* a reply from the user */
*InputString
/* the input string */
= "a blank input string long enough for an expression";
Stack
InputStack, ParseStack;
/* gets an Input */
/* string from user to parse */
/* initialize the ParseStack */
/ to the empty stack */
/* initialize the InputStack */
/* to the empty stack */
/* put a 'pad' character */
/* at bottom of InputStack */
/* scanf("%s",InputString); */
105
110
115
120
125
130
135
140
145
150
155
160
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Shift('#');
}
/* ------------------------------------------------------------------------------- */
char FetchNext(void)
{
char d, f;
d = Next;
do {
return d;
}
/* ------------------------------------------------------------------------------- */
void PrintErrorMessageIfNecessary(char c, char d)
{
/* if d isn't equal to the expected character c, write an error message. */
if (c == 'a') {
if (! (islower(d) | | isdigit(d)) ) {
printf("Syntax Error: expected <letter> or <digit> but got %c\n", d);
}
} else if (c != d) {
printf("Syntax Error: expected %c but got %c\n", c, d);
}
}
/* ------------------------------------------------------------------------------- */
void Shift(char c)
{
char d;
/* d holds the character Shifted from the Input string */
d = FetchNext( );
170
175
180
185
190
195
200
205
210
215
220
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Output = "
";
Output[2*n] = '\0';
for (i = n 1; i >= 0; i) {
Pop(&ParseStack,&Output[2*i]);
Output[2*i+1] = ' ';
}
if (n == 1) {
if (S == 'P') {
/* PFstring = Concat(PFString,Output); */
printf(" %c >
} else {
printf(" %c >
%s\n",S,Output);
}
} else {
printf(" %c > %s\n", S, Output);
/* later for use in Program 14.8, add:
if ((n == 3) && (S != 'P') ) {
PFstring = Concat(PFstring, Output[3],' ');
printf("
%s\n", PFString);
} else {
putchar('\n');
}
*/
}
/* end if */
/* push S on stack */
Push(S,&ParseStack);
}
/* end Reduce */
/* ------------------------------------------------------------------------------- */
int UserWantsToContinue(void)
{
printf("Do you want to give another string? (y/n) ");
gets(Answer);
/* scanf("%s",Answer); */
return (Answer[0] == 'y');
}
/* -----------------------------< end of ParserUtilities.c >----------------------------- */
10
15
20
25
30
35
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
* Solution to Ex.14.3.2 -- Marked Palindrome Parser
*/
#include "ParserUtilities.h"
extern char Next;
/* ------------------------------------------------------------------------------- */
void ParseE(void)
/* parse a marked palindrome */
{
if (Next == '2') {
Shift('2');
Reduce(1,'E');
} else if (Next == '0') {
Shift('0');
ParseE( );
Shift('0');
Reduce(3,'E');
} else if (Next == '1') {
Shift('1');
ParseE( );
Shift('1');
Reduce(3,'E');
}
}
/* ------------------------------------------------------------------------------- */
int main(void)
{
do {
GetInputStringFromUser( );
ParseE( );
/* call the parser to parse the input string. */
} while ( UserWantsToContinue( ) );
}
G3 = { E 1 1 0, E 1 1 E 0 }.
10
15
20
25
30
35
40
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****
*
* Exs 14.4.1 & 14.4.2 -- Augmented Infix-to-Postfix translator & evaluator
*
-- which handles unary minus
*
***/
/****
*
* To complete the module "YourCalculationModule" of Ex. 14.4.2 add a
* headerfile "YourCalculationModule.h" to the current ".c" file containing
* the extern declaration:
*
*
extern char *Evaluate(char *);
*
* as shown in Program 4.12 on p. 109
*
***/
/****
*
* This program augments the Recursive Descent Parser of Program 14.6
* to handle unary minus operators according to the grammar of Ex 14.2.2
* shown immediately below, translates infix to postfix, evaluates the
* postfix, and prints the string representing the floating point value.
*
*
E --> E + T | E T | T
*
T --> T * F | T / F | F
*
F --> F ^ U | U
*
U --> P | + P | P
*
P --> ( E ) | a
*
* Here, we let 'a' stand for any letter or digit:
*
*
a --> <letter> | <digit>
*
* The grammar above uses E, T, F, and P to stand for the following
* "standard" abbreviations in the literature:
*
* E = Expression, T = Term, F = Factor, and P = Primary.
*
* In addition, it uses U to stand for a Unary operand.
*
****/
50
55
60
65
70
75
80
85
90
95
100
105
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "ParserUtilities.h"
#include "EvalStackInterface.h"
/* -< The ParserUtilities.h file contains the following external declarations >- */
/*
#include
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<math.h>
<ctype.h>
<string.h>
/+ appends X to postfix
/+ output string
+/
+/
/+ ----------------------------------------------------------------------------- +/
*/
/* ------< three external variables imported from ParserUtilities.c >--------- */
extern char Next;
= "00000000000000000000";
/* the string */
/* for the value of the output */
/* ------------------------------------------------------------------------------- */
110
115
120
125
130
135
140
145
150
155
160
165
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ParseP(void)
{
char Operand;
/* parse a Primary */
if (Next == '(') {
Shift('(');
ParseE( );
Shift(')');
Reduce(3,'P');
} else {
Operand = Next;
Shift('a');
/* 'a' stands for any <letter> or <digit> */
Reduce(1,'P');
AppendToOutput(Operand);
}
}
/* ------------------------------------------------------------------------------- */
void ParseU(void)
{
char Operator;
if ( (Next == '+') || (Next == '') ) {
Operator = Next;
Shift(Next);
ParseP( );
Reduce(2,'U');
if (Operator == '') {
AppendToOutput('~');
}
} else {
ParseP( );
Reduce(1,'U');
}
/* parse a Unary */
}
/* ------------------------------------------------------------------------------- */
void ParseF(void)
{
char Operator;
/* parse a Factor */
ParseU( );
Reduce(1,'F');
while (Next == '^') {
Operator = Next;
Shift(Next);
ParseU( );
Reduce(3,'F');
AppendToOutput(Operator);
}
}
/* ------------------------------------------------------------------------------- */
void ParseT(void)
{
char Operator;
ParseF( );
Reduce(1,'T');
/* parse a Term */
175
180
185
190
195
200
205
210
215
220
225
230
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* parse an Expression */
ParseT( );
Reduce(1,'E');
while ( (Next == '+') || (Next == '') ) {
Operator = Next;
Shift(Next);
ParseT( );
Reduce(3,'E');
AppendToOutput(Operator);
}
}
/* ------------------------------------------------------------------------------- */
void InterpretPostfix(void)
{
float LeftOperand, RightOperand, Result;
int i;
char c;
char *s = "x";
InitializeStack(&EvalStack);
for (i = 0; i < strlen(PostfixString); ++i) {
s[0] = c = PostfixString[i];
if (isdigit(c)) {
if ( Full(&EvalStack) ) {
printf("Stack full. Postfix Evaluation could not be completed.\n");
return;
} else {
Push((float)atof(s),&EvalStack);
}
} else if (c=='~') {
if ( Empty(&EvalStack) ) {
printf("Malformed postfix input string. Too many operators\n");
printf("and too few operands.\n");
return;
} else {
Pop(&EvalStack,&RightOperand);
295
300
305
310
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
strcpy(InputString,S);
ParseE();
/* call the parser to parse the input string. */
InterpretPostfix();
return ResultString;
}
/* --< the main function tests the operation of YourCalculationModule >-- */
int main(void)
{
do {
PostfixString[0] = '\0';
/* initialize PostfixString to empty string */
GetInputStringFromUser( );
ResultString = Evaluate(InputString);
printf("output = %s\n",ResultString);
putchar('\n');
} while ( UserWantsToContinue( ) );
}
/* end main program */
prove that
calls on f
size, as in
Thus, the
Now suppose A[m:n] contains more than one item, so that m < n, and
suppose, by recursion induction, that Find(A,k,m,n) works correctly
for all arrays with fewer than nm+1 items.
The partition algorithm is called with Partition(A, m, n) to partition
A[m:n] into a left partition A[m:j] and a right partition A[i:n] , where i ==
j+1 and m j < n. Lines 30:36 of the Find function below set i and j
appropriately to ensure that these conditions are met. The
elements in the left partition will be less than or equal to the
smallest element in the right partition after returning from the
partition function call. If now, k (jm+1), it means that there are at
least k elements in the left partition (recalling that the number of
elements in A [ m : j ] is j m + 1 according to Eq. A.5 of the Math
Reference appendix). Since all the items in the left partition are
smaller than any of the items in the right partition and there are k
or more items in the left partition, the k th smallest item in A[m:n] is
found by taking the k th smallest item in the left partition, which, by
recursion induction, is correctly found by recursively calling
F i n d ( A , k , m , j ) on line 39 of the F i n d function given below. (It is
guaranteed that A[m:j] is a smaller array than A[m:n] because j < n after
the call to Partition(A,m,n) and after the computations to set i and j on
lines 30:36 of Find below. Hence, the recursion induction condition
applies in this case.)
Now suppose that, after returning from the call Partition(A,m,n) and
after the computations to set i and j on lines 30:36 of Find below, it
is false that k (jm+1) , meaning that there are fewer than k
elements in A[m:j] . Then because all jm+1 items in A[m:j] are less than
or equal to each of the items in A[i:n] , the k th smallest item in A[m:n] is
10
15
20
25
30
35
40
45
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
int Partition(ItemArray A, int i, int j)
/* assume i < j */
{
ItemType Pivot, Temp;
/* the value returned by the Partition */
int k, middle, p;
/* function is the location of the Pivot */
/* after partitioning */
middle = (i+j)/2;
Pivot = A[middle]; A[middle] = A[i]; A[i] = Pivot;
p = i;
for (k= i+1; k <= j; ++k) {
if (A[k] < Pivot) {
Temp = A[++p]; A[p] = A[k]; A[k] = Temp;
}
}
Temp = A[i]; A[i] = A[p]; A[p] = Temp;
return p;
}
/*--------------------------------------------------------------------------*/
void Find(ItemArray A, int k, int m, int n)
/* to move the kth smallest */
{
/* item in A[m:n] into the kth position */
int i, j, p;
if (m < n) {
if ( k <= (j m + 1) ) {
/* if A[m:j] has at least k items, then */
Find(A, k, m, j);
/* Find kth in A[m:j] */
} else {
/* otherwise, */
Find(A, k(jm+1), i, n);
/* Find k(jm+1)th in A[i:n] */
}
}
}
/*--------------------------------------------------------------------------*/
Perm(A,m,n)
A[m:n1]
For the base case , m == 0, we need to show that Perm(A,0,n) prints all
permutations of A[0:n1] with A[0:n1] fixed and A[0:1] varying. The
range 0:1 is empty (because by definition i:j == { k | i k j}, so 0:1 == { k
| 0 k 1} == ). Hence there is only one permutation of A[0:n1] with
A[0:n1] fixed and A[0:1] == varying, and it is obtained by printing
A[0:n1] . But, when m == 0, Perm(A,0,n) calls PrintPerm(A,n) which simply
prints the items in A [ 0 : n 1 ] (see lines 13:21 and 38:39 of the
program below). Hence, for m == 0, Perm(A,m,n) prints A[0:n1] which is
what we needed to show.
Now assume that Perm(A,k,n) prints all the permutations with A[k:n
fixed and A[0:k1] varying for all k < n. In Perm(A,m,n) , when m == n, for
each i in 0:n1 Perm(A,n,n) exchanges A[i] with A[n1] , then calls Perm(A,n
1,n) to print all permutations of A[0:n1] with A[n1] fixed and A[0:n2]
varying, and exchanges A[n1] and A[i] back again. The effect of this
is to choose each of the distinct objects in A [ 0 : n 1 ] as the fixed
object A [ n 1 ] while printing all permutations with the remaining
A [ 0 : n 2 ] objects varying (which must occur correctly by the
recursion induction hypothesis using the recursive call Perm(A,n1,n)
on a problem of size k == n1 where k < n).
1]
10
15
20
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------*/
void Exchange(ItemArray A, int i, int j)
{
ItemType temp;
temp = A[i]; A[i] = A[j]; A[j] = temp;
}
/*------------------------------------------------------------*/
void PrintPerm(ItemArray A, int n)
{
int i;
for (i = 0; i < n; ++i) {
printf("%2d, ",A[i]);
}
putchar('\n');
}
/*------------------------------------------------------------*/
30
35
40
45
50
55
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
to rewrite it as
E+T
E + T*F
E + T*P
E + T*a
E + F*a
E + P*a
E + a*a
T + a*a
F + a*a
F P + a*a
F a + a*a
P a + a*a
( E ) a + a*a
(E T) a + a*a
(E F) a + a*a
(E P) a + a*a
(E a) a + a*a
(T a) a + a*a
(F a) a + a*a
(P a) a + a*a
apply production
EE+T
TF
FP
Pa
TF
FP
Pa
ET
TF
FF P
Pa
FP
P(E)
EET
TF
FP
Pa
ET
TF
FP
Pa
EE+T | ET | F
TT*F | T/F | F
FFU | U
UP |+P | P
P(E) | a
10
15
20
25
30
35
40
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
* Ex. 14.3.1 the "ParserUtilities.c" module
*
* This module exports parser utility services. It uses the same sequential
* stack representation as is used for Program 7.5, the parenthesis matching
* program in Chapter 7.
*/
#include "ParserUtilities.h"
/******
*
* The ParserUtilities.h file contains the following external declarations:
*
*****/
/*
#include
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<string.h>
<ctype.h>
"SeqStackInterface.h"
45
50
55
60
65
70
75
80
85
90
95
100
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Next;
char
*Answer = "blank",
/* a reply from the user */
*InputString
/* the input string */
= "a blank input string long enough for an expression";
Stack
InputStack, ParseStack;
/* gets an Input */
/* string from user to parse */
/* initialize the ParseStack */
/ to the empty stack */
/* initialize the InputStack */
/* to the empty stack */
/* put a 'pad' character */
/* at bottom of InputStack */
/* scanf("%s",InputString); */
105
110
115
120
125
130
135
140
145
150
155
160
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Shift('#');
}
/* ------------------------------------------------------------------------------- */
char FetchNext(void)
{
char d, f;
d = Next;
do {
return d;
}
/* ------------------------------------------------------------------------------- */
void PrintErrorMessageIfNecessary(char c, char d)
{
/* if d isn't equal to the expected character c, write an error message. */
if (c == 'a') {
if (! (islower(d) | | isdigit(d)) ) {
printf("Syntax Error: expected <letter> or <digit> but got %c\n", d);
}
} else if (c != d) {
printf("Syntax Error: expected %c but got %c\n", c, d);
}
}
/* ------------------------------------------------------------------------------- */
void Shift(char c)
{
char d;
/* d holds the character Shifted from the Input string */
d = FetchNext( );
170
175
180
185
190
195
200
205
210
215
220
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Output = "
";
Output[2*n] = '\0';
for (i = n 1; i >= 0; i) {
Pop(&ParseStack,&Output[2*i]);
Output[2*i+1] = ' ';
}
if (n == 1) {
if (S == 'P') {
/* PFstring = Concat(PFString,Output); */
printf(" %c >
} else {
printf(" %c >
%s\n",S,Output);
}
} else {
printf(" %c > %s\n", S, Output);
/* later for use in Program 14.8, add:
if ((n == 3) && (S != 'P') ) {
PFstring = Concat(PFstring, Output[3],' ');
printf("
%s\n", PFString);
} else {
putchar('\n');
}
*/
}
/* end if */
/* push S on stack */
Push(S,&ParseStack);
}
/* end Reduce */
/* ------------------------------------------------------------------------------- */
int UserWantsToContinue(void)
{
printf("Do you want to give another string? (y/n) ");
gets(Answer);
/* scanf("%s",Answer); */
return (Answer[0] == 'y');
}
/* -----------------------------< end of ParserUtilities.c >----------------------------- */
10
15
20
25
30
35
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
* Solution to Ex.14.3.2 -- Marked Palindrome Parser
*/
#include "ParserUtilities.h"
extern char Next;
/* ------------------------------------------------------------------------------- */
void ParseE(void)
/* parse a marked palindrome */
{
if (Next == '2') {
Shift('2');
Reduce(1,'E');
} else if (Next == '0') {
Shift('0');
ParseE( );
Shift('0');
Reduce(3,'E');
} else if (Next == '1') {
Shift('1');
ParseE( );
Shift('1');
Reduce(3,'E');
}
}
/* ------------------------------------------------------------------------------- */
int main(void)
{
do {
GetInputStringFromUser( );
ParseE( );
/* call the parser to parse the input string. */
} while ( UserWantsToContinue( ) );
}
G3 = { E 1 1 0, E 1 1 E 0 }.
10
15
20
25
30
35
40
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****
*
* Exs 14.4.1 & 14.4.2 -- Augmented Infix-to-Postfix translator & evaluator
*
-- which handles unary minus
*
***/
/****
*
* To complete the module "YourCalculationModule" of Ex. 14.4.2 add a
* headerfile "YourCalculationModule.h" to the current ".c" file containing
* the extern declaration:
*
*
extern char *Evaluate(char *);
*
* as shown in Program 4.12 on p. 109
*
***/
/****
*
* This program augments the Recursive Descent Parser of Program 14.6
* to handle unary minus operators according to the grammar of Ex 14.2.2
* shown immediately below, translates infix to postfix, evaluates the
* postfix, and prints the string representing the floating point value.
*
*
E --> E + T | E T | T
*
T --> T * F | T / F | F
*
F --> F ^ U | U
*
U --> P | + P | P
*
P --> ( E ) | a
*
* Here, we let 'a' stand for any letter or digit:
*
*
a --> <letter> | <digit>
*
* The grammar above uses E, T, F, and P to stand for the following
* "standard" abbreviations in the literature:
*
* E = Expression, T = Term, F = Factor, and P = Primary.
*
* In addition, it uses U to stand for a Unary operand.
*
****/
50
55
60
65
70
75
80
85
90
95
100
105
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "ParserUtilities.h"
#include "EvalStackInterface.h"
/* -< The ParserUtilities.h file contains the following external declarations >- */
/*
#include
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<math.h>
<ctype.h>
<string.h>
/+ appends X to postfix
/+ output string
+/
+/
/+ ----------------------------------------------------------------------------- +/
*/
/* ------< three external variables imported from ParserUtilities.c >--------- */
extern char Next;
= "00000000000000000000";
/* the string */
/* for the value of the output */
/* ------------------------------------------------------------------------------- */
110
115
120
125
130
135
140
145
150
155
160
165
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ParseP(void)
{
char Operand;
/* parse a Primary */
if (Next == '(') {
Shift('(');
ParseE( );
Shift(')');
Reduce(3,'P');
} else {
Operand = Next;
Shift('a');
/* 'a' stands for any <letter> or <digit> */
Reduce(1,'P');
AppendToOutput(Operand);
}
}
/* ------------------------------------------------------------------------------- */
void ParseU(void)
{
char Operator;
if ( (Next == '+') || (Next == '') ) {
Operator = Next;
Shift(Next);
ParseP( );
Reduce(2,'U');
if (Operator == '') {
AppendToOutput('~');
}
} else {
ParseP( );
Reduce(1,'U');
}
/* parse a Unary */
}
/* ------------------------------------------------------------------------------- */
void ParseF(void)
{
char Operator;
/* parse a Factor */
ParseU( );
Reduce(1,'F');
while (Next == '^') {
Operator = Next;
Shift(Next);
ParseU( );
Reduce(3,'F');
AppendToOutput(Operator);
}
}
/* ------------------------------------------------------------------------------- */
void ParseT(void)
{
char Operator;
ParseF( );
Reduce(1,'T');
/* parse a Term */
175
180
185
190
195
200
205
210
215
220
225
230
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* parse an Expression */
ParseT( );
Reduce(1,'E');
while ( (Next == '+') || (Next == '') ) {
Operator = Next;
Shift(Next);
ParseT( );
Reduce(3,'E');
AppendToOutput(Operator);
}
}
/* ------------------------------------------------------------------------------- */
void InterpretPostfix(void)
{
float LeftOperand, RightOperand, Result;
int i;
char c;
char *s = "x";
InitializeStack(&EvalStack);
for (i = 0; i < strlen(PostfixString); ++i) {
s[0] = c = PostfixString[i];
if (isdigit(c)) {
if ( Full(&EvalStack) ) {
printf("Stack full. Postfix Evaluation could not be completed.\n");
return;
} else {
Push((float)atof(s),&EvalStack);
}
} else if (c=='~') {
if ( Empty(&EvalStack) ) {
printf("Malformed postfix input string. Too many operators\n");
printf("and too few operands.\n");
return;
} else {
Pop(&EvalStack,&RightOperand);
295
300
305
310
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
strcpy(InputString,S);
ParseE();
/* call the parser to parse the input string. */
InterpretPostfix();
return ResultString;
}
/* --< the main function tests the operation of YourCalculationModule >-- */
int main(void)
{
do {
PostfixString[0] = '\0';
/* initialize PostfixString to empty string */
GetInputStringFromUser( );
ResultString = Evaluate(InputString);
printf("output = %s\n",ResultString);
putchar('\n');
} while ( UserWantsToContinue( ) );
}
/* end main program */
prove that
calls on f
size, as in
Thus, the
Now suppose A[m:n] contains more than one item, so that m < n, and
suppose, by recursion induction, that Find(A,k,m,n) works correctly
for all arrays with fewer than nm+1 items.
The partition algorithm is called with Partition(A, m, n) to partition
A[m:n] into a left partition A[m:j] and a right partition A[i:n] , where i ==
j+1 and m j < n. Lines 30:36 of the Find function below set i and j
appropriately to ensure that these conditions are met. The
elements in the left partition will be less than or equal to the
smallest element in the right partition after returning from the
partition function call. If now, k (jm+1), it means that there are at
least k elements in the left partition (recalling that the number of
elements in A [ m : j ] is j m + 1 according to Eq. A.5 of the Math
Reference appendix). Since all the items in the left partition are
smaller than any of the items in the right partition and there are k
or more items in the left partition, the k th smallest item in A[m:n] is
found by taking the k th smallest item in the left partition, which, by
recursion induction, is correctly found by recursively calling
F i n d ( A , k , m , j ) on line 39 of the F i n d function given below. (It is
guaranteed that A[m:j] is a smaller array than A[m:n] because j < n after
the call to Partition(A,m,n) and after the computations to set i and j on
lines 30:36 of Find below. Hence, the recursion induction condition
applies in this case.)
Now suppose that, after returning from the call Partition(A,m,n) and
after the computations to set i and j on lines 30:36 of Find below, it
is false that k (jm+1) , meaning that there are fewer than k
elements in A[m:j] . Then because all jm+1 items in A[m:j] are less than
or equal to each of the items in A[i:n] , the k th smallest item in A[m:n] is
10
15
20
25
30
35
40
45
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
int Partition(ItemArray A, int i, int j)
/* assume i < j */
{
ItemType Pivot, Temp;
/* the value returned by the Partition */
int k, middle, p;
/* function is the location of the Pivot */
/* after partitioning */
middle = (i+j)/2;
Pivot = A[middle]; A[middle] = A[i]; A[i] = Pivot;
p = i;
for (k= i+1; k <= j; ++k) {
if (A[k] < Pivot) {
Temp = A[++p]; A[p] = A[k]; A[k] = Temp;
}
}
Temp = A[i]; A[i] = A[p]; A[p] = Temp;
return p;
}
/*--------------------------------------------------------------------------*/
void Find(ItemArray A, int k, int m, int n)
/* to move the kth smallest */
{
/* item in A[m:n] into the kth position */
int i, j, p;
if (m < n) {
if ( k <= (j m + 1) ) {
/* if A[m:j] has at least k items, then */
Find(A, k, m, j);
/* Find kth in A[m:j] */
} else {
/* otherwise, */
Find(A, k(jm+1), i, n);
/* Find k(jm+1)th in A[i:n] */
}
}
}
/*--------------------------------------------------------------------------*/
Perm(A,m,n)
A[m:n1]
For the base case , m == 0, we need to show that Perm(A,0,n) prints all
permutations of A[0:n1] with A[0:n1] fixed and A[0:1] varying. The
range 0:1 is empty (because by definition i:j == { k | i k j}, so 0:1 == { k
| 0 k 1} == ). Hence there is only one permutation of A[0:n1] with
A[0:n1] fixed and A[0:1] == varying, and it is obtained by printing
A[0:n1] . But, when m == 0, Perm(A,0,n) calls PrintPerm(A,n) which simply
prints the items in A [ 0 : n 1 ] (see lines 13:21 and 38:39 of the
program below). Hence, for m == 0, Perm(A,m,n) prints A[0:n1] which is
what we needed to show.
Now assume that Perm(A,k,n) prints all the permutations with A[k:n
fixed and A[0:k1] varying for all k < n. In Perm(A,m,n) , when m == n, for
each i in 0:n1 Perm(A,n,n) exchanges A[i] with A[n1] , then calls Perm(A,n
1,n) to print all permutations of A[0:n1] with A[n1] fixed and A[0:n2]
varying, and exchanges A[n1] and A[i] back again. The effect of this
is to choose each of the distinct objects in A [ 0 : n 1 ] as the fixed
object A [ n 1 ] while printing all permutations with the remaining
A [ 0 : n 2 ] objects varying (which must occur correctly by the
recursion induction hypothesis using the recursive call Perm(A,n1,n)
on a problem of size k == n1 where k < n).
1]
10
15
20
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------*/
void Exchange(ItemArray A, int i, int j)
{
ItemType temp;
temp = A[i]; A[i] = A[j]; A[j] = temp;
}
/*------------------------------------------------------------*/
void PrintPerm(ItemArray A, int n)
{
int i;
for (i = 0; i < n; ++i) {
printf("%2d, ",A[i]);
}
putchar('\n');
}
/*------------------------------------------------------------*/
30
35
40
45
50
55
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10
15
20
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////
//
/ / Ex. 15.2.2 -- Extension of Third Stage Drawing Program to use
//
three distinct types of fill patterns for filled shapes
//
/////
#include
#include
#include
#include
#include
#include
<stdio.h>
<string.h>
<oops.h>
"windowUtils.h"
"Shapes.h"
"ShapeList.h"
25
30
35
40
45
50
55
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
");
60
65
70
75
80
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fflush(stdin);
gets(reply);
ReplyLength = strlen(reply);
if ((reply[0] == 'Q') || (reply[0] == 'q')) {
return false;
} else if ((reply[0] == 'M') || (reply[0] == 'm')) {
MoveShapes( );
*theShape = NULL;
return true;
} else {
switch(reply[1]) {
case 'O':
case 'o':
if ((reply[0] == 'H') || (reply[0] == 'h')) {
*theShape = new TOval;
} else {
*theShape = new TFilledOval;
(*theShape)>GetItsPattern( );
}
return true;
// stay in the loop
145
|
|
|
|
return(0);
}
The main program above for Ex 15.2.2 uses the Shapes and ShapeList
modules defined below. We first give the S h a p e s . h header file
followed by the Shapes.c source file.
| //////
| //
| // The Shapes.h header file defines the Shape class hierarchy
| //
5
| //////
|
|
| class TShape {
// the abstract class of which all
|
// actual Shape classes are derivatives
10
|
public:
|
|
// The SetEnclosingRect method sets (left, top, right, bottom)
|
// values for the EnclosingRectangle.
|
15
|
void SetEnclosingRect (short x1, short y1, short x2, short y2);
|
|
void Move(int deltaX, int deltaY);
|
|
void GetItsPattern(void);
20
|
|
// The Draw( ) method draws the shape. All derived classes
|
// override it. At this abstract class level it is virtual,
|
// in order to behave as a place-holder that expects to be
|
// overridden by local customized methods in each derivative
25
|
// subclass.
|
|
virtual void Draw( );
|
|
protected:
30
|
|
Rect
EnclosingRectangle;
// The rectangle that encloses
|
// the shape
|
PatPtr itsPattern;
// The fill pattern for the shape
|
// (if applicable)
35
|
| };
|
| class TRectangle : public TShape {
|
40
|
public:
|
void Draw( );
| };
|
| class TOval : public TShape {
45
|
|
public:
|
void Draw( );
| };
|
50
| class TRoundedRectangle : public TShape {
55
60
65
70
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
void Draw( );
};
class TFilledRectangle : public TRectangle {
public:
void Draw( );
};
class TFilledOval : public TOval {
public:
void Draw( );
};
class TFilledRoundedRectangle : public TRoundedRectangle {
public:
void Draw( );
};
10
15
20
25
30
35
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////
//
// Shapes.c contains the implementations of TShape methods
//
//////
#include
#include
#include
#include
#include
<oops.h>
<stdio.h>
<string.h>
"windowUtils.h"
"Shapes.h"
void TShape : : SetEnclosingRect (short x1, short y1, short x2, short y2)
{
EnclosingRectangle.top
= 100 y1;
EnclosingRectangle.left
= 150 + x1;
EnclosingRectangle.bottom = 100 y2;
EnclosingRectangle.right
= 150 + x2;
}
void TShape : : Move(int deltaX, int deltaY)
{
EnclosingRectangle.top
= deltaY;
EnclosingRectangle.left
+= deltaX;
EnclosingRectangle.bottom = deltaY;
EnclosingRectangle.right
+= deltaX;
}
void TShape : : GetItsPattern(void)
40
45
50
55
60
65
70
75
80
85
90
95
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
char
int
*reply = "
";
ReplyLength;
105
110
115
120
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TFilledRectangle : : Draw
void TFilledRectangle : : Draw ( )
{
FillRect(&EnclosingRectangle,*itsPattern);
TRectangle : : Draw( );
}
// TFilledOval : : Draw
void TFilledOval : : Draw ( )
{
FillOval(&EnclosingRectangle,*itsPattern);
TOval : : Draw( );
}
// TFilledRoundedRectangle : : Draw
void TFilledRoundedRectangle : : Draw ( )
{
FillRoundRect(&EnclosingRectangle,20,20,*itsPattern);
TRoundedRectangle : : Draw( );
}
The main program above for Ex 15.2.2 uses the ShapeList module
defined below. The header file ShapeList.h is given first, followed by
the source file ShapeList.c .
10
15
20
25
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////
//
// ShapeList.h
//
//////
// define the Shape List base class
class TList
{
public:
void InitShapeList( );
void Append(TShape *theShape);
void Move(int deltaX, int deltaY);
void Draw( );
Boolean IsNonEmpty( );
private:
TShape
TList
*Shape;
*Link;
};
//////
10
15
20
25
30
35
40
45
50
55
60
| //
| // ShapeList.c
| //
| //////
|
| #include <oops.h>
| #include "Shapes.h"
| #include "ShapeList.h"
|
| extern WindowPtr DrawingWindow;
// The drawing window is
|
// defined in windowUtils.c
|
| void TList : : InitShapeList( )
| {
|
Shape = NULL;
// Convention: A list node with NULL shape is
|
Link = NULL;
// an empty node awaiting a non-null
|
//Shape to be assigned
| }
|
| void TList : : Append (TShape *theShape)
| {
|
TList *LastNode, *NewNode;
|
|
if (Shape == NULL) {
//overwrite an "empty" shape with
|
// theShape to fill in the empty slot
|
Shape = theShape;
|
|
} else {
|
|
NewNode = new TList;
|
NewNode>Shape = theShape;
|
NewNode>Link = NULL;
|
LastNode = this;
|
while (LastNode>Link != NULL) {
|
LastNode = LastNode>Link;
|
}
|
LastNode>Link = NewNode;
|
}
| }
|
| void TList : : Move(int deltaX, int deltaY)
//calls Move(deltaX, DeltaY)
| {
// method on each Shape in the list
|
TList
*TempNode;
|
TShape *theShape;
|
|
TempNode = this;
|
|
while (TempNode != NULL) {
|
|
theShape = TempNode>Shape;
|
theShape>Move(deltaX, deltaY);
//call theShape's move
|
// method to move it by (deltaX,deltaY)
|
TempNode = TempNode>Link;
//advance to next
|
// node on list
|
}
| }
|
| void TList : : Draw( )
| {
65
70
75
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
//
|
|
TList *TempNode;
TempNode = this;
while (TempNode != NULL) {
TempNode>Shape>Draw( );
m 7 * m 14 * 2.4 * (KDSI)1.05
= 0.93 * 0.83 * 2.4 * 1001.05
= 233.2 person months
Then, substituting this value of PM in Eq. 16.2 to get Td yields,
PM
Td
2.5*
15.4 months
233.2
3.
1 /4
5. 2 (k +2) / 2 n
6. $1656.03 (which is the sum of 100*(1.09) 1 + 100*(1.09) 2 + . . . +
100*(1.09) 10 ).
7. S = a * [ (r n k + 2 1) / (r 1) ].
Step
k<n
k /n < 1
1 + k /n < 2
fact, listed above)
1 + k /n < b
n + k < n* b
both sides
log b (n + k ) < logb (n * b )
1.
log b (n + k ) < logb n + 1.
base- b
logarithms of
i = 0
i * 5 = 0
( i *5) m o d 11 = 0
10 15 20 25 30 35 40 45 50
10 4
5
3
6
8
7
2
8
7
9
1
10
6
[ (nd n 1) d n + 1] yields,
1. Putting d = 1 / 2 in (1 i n ) i d i =
2
(
d
1)
1 /2
( 1 / ) 2 [
2
n+2 1
2
2n
1 n+2
2 [ 1 2 n ] , and finally simplifies to,
2
n+2
2
.
n
2
+ D
8 A + 4B + 2C
+ D
1 0 = 27 A + 9 B + 3 C
+ D
2 0 = 64 A + 16 B + 4 C
+ D
4 =
A +
B +
1. The base case is T(0) = a . The general case is T(k ) = 2 + 2 T(k /2).
2. A summing factor is a multiplier used to multiply several
instances of recurrence relations so that when they are added
together they form a telescoping sum .
3. A telescoping sum is a sum of terms such that the terms in the
middle cancel one another in adjacent pairs.
4. Substitute the general formula for the solution into the original
recurrence relations and verify that the relations hold.
= (a + d) + a
T(3) = (a + 2 d ) + T(2)
= (a + 2 d ) + ( a + d) + a
...
T( n ) =
+ ( a + d) + a
(a + (n 1) d ) + (a + (n 2) d ) + . . . + (a + 2 d )
T( n )
c T(n1)
a
=
Then write,
=
T(1)
1 /c T(2)
c / c T(1) =
a
b /c
{multiply by 1/ c }
c / c 2 T(2) =
b /c 2
{multiply by 1/ c 2 }
b / c n 1
{multiply
. . .
1/ c n 1 T( n ) c/ c n 1 T(n1) =
1/ c n 1 }
{and
by
summing
the
rows
above}
T( n )/ c n 1
a + b /c + b /c 2 + . . . + b /c n 1
In the sum immediately above, if c = 1 then T(n ) = a + (n 1) b = b
n + (a b ), which yields the solution given in the first case of Table
A.12. Now suppose c 1. Then the sum above is,
T( n )/ c n 1 = a + b /c [ 1 + 1/c + 1/c 2 + . . . + 1/c n 2 ]
= a + b / c [ (1 1/c n 1 ) / (1 1/c ) ]
= a + b [ (1 1/c n 1) / (c 1)]
Multiplying both sides by c n 1 gives,
= a *c n 1 + b [ (c n 1 1) / (c 1)]
T( n )
= a * c n 1 + ( b*c n 1 )/( c 1) b /( c 1)
= [ a /c + b /(c ( c 1))] c n b /(c 1)
After some final simplification, this yields the solution for the
case c 1.
=
T( n ) =
b
c
b n
b
c
.
c 1
c 1