0% found this document useful (0 votes)
2K views380 pages

J. P. Tremblay, P. G. Sorenson and D. M. Manegre - Instructor's Solutions Manual To Accompany An Introduction To Data Structures With Applications-McGraw Hill (1984)

The document is an instructor's manual for a textbook on data structures. It provides suggestions for how to teach each chapter, with recommendations on what material is most important to cover and possible ways to supplement or reduce the material depending on time constraints. It also acknowledges those who assisted in creating the manual and provides sample exercises and solutions for Chapter 1.

Uploaded by

Vaibhav Patil
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2K views380 pages

J. P. Tremblay, P. G. Sorenson and D. M. Manegre - Instructor's Solutions Manual To Accompany An Introduction To Data Structures With Applications-McGraw Hill (1984)

The document is an instructor's manual for a textbook on data structures. It provides suggestions for how to teach each chapter, with recommendations on what material is most important to cover and possible ways to supplement or reduce the material depending on time constraints. It also acknowledges those who assisted in creating the manual and provides sample exercises and solutions for Chapter 1.

Uploaded by

Vaibhav Patil
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 380

INSTRUCTOR'S MANUAL

TO ACCOMPANY

AN INTRODUCTION
TO DATA STRUCTURES
‘WITH APPLICATIONS
— SECOND EDITION

JEAN-PAUL TREMBLAY
PAUL G. SORENSON
and
DONNA M. MANEGRE
Department of Computational Science
University of Saskatchewan, Saskatoon
anada

McGraw-Hill Book Company


New York St. Louis San Francisco Auckland Bogota Hamburg
Johannesburg London Madrid Mexico Montreal New Delhi Panama
Paris Sao Paulo Singapore Sydney Tokyo Toronto
Instructor's Manual to Accompany
AN INTRODUCTION TO DATA STRUCTURES
WITH APPLICATIONS Second Edition
Copyright © 1984 by McGraw-Hill, Inc. All rights reserved.
Printed in the United States of America. The contents, or
parts thereof, may be reproduced for use with
AN INTRODUCTION TO DATA STRUCTURES
WITH APPLICATIONS / Second Edition
by Jean-Paul Tremblay
and Paul G. Sorenson
provided such reproductions bear copyright notice, but may not
be reproduced in any form for any other purpose without
permission of the publisher.

0-07-065165-5

1234567890 WHT WHT 8987654


SUGGESTIONS

Unless time permits, Chapter 1 should be covered very quickly with a


maximum of 2 to 3 hours being devoted to this chapter. The important aspects to
emphasize here are that computers have primitive data structures such as integers,
reals, character, and pointers, and these primitive structures can be represented in
the memory of a computer in different ways. Also, computers have machine-
language instructions which manipulate these primitive structures.
Most of the material in Chapter 2 is basic. Grammars are used throughout
the remainder of the book. Since Markov algorithms are very similar to the
SNOBOL language, both topics need not be covered if time is of the essence. A
discussion of SNOBOL may be sufficient. Furthermore, not all applications of
strings in Section 2-5 need be covered.
Most of Chapter 3 is important. Recursion should be strongly emphasized. It
is used extensively in Chapter 5. Stacks and queues, in general, have such wide
applicabilities that they deserve extensive treatment.
In Chapter 4 almost al! of the material should be covered. When the
programming language used in ‘he course does not permit programmer-defined
structures involving linked allocation techniques, particular attention should be
given to Section 4-2. This section, in part, deals with the array representation of
linked lists. Time may permit the coverage of only ene or two applications of
linked lists. The material of Section 4-1 and 4-2 is used very extensively in
Chapters 5, 6, and 7.
In Chapter 5, Sections 5-1, 5-4, and 5-6 should be discussed in detail.
Recursion should be emphasized in Section 5-1, since its use makes the algorithms
easier and simpler to write. Depending on the objectives of the course and the time
available, several applications contained in this chapter can he selected.
Chapter 6 is rather brief and consequently it may be desirable to discuss the
entire chapter. Depending on the objectives of the course, the instructor may want
to supplement the performance and analysis of the sorting and searching algorithms.
One should stress that efficient algorithms for these operations can be realized when
data are properly structured. Section 6-2.4, on hashing techniques is used
extensively in Chapter 7.
If time permits, at least the basic notions of sequential, index sequential, and
direct files should be introduced. The remaining material in Chapter 7, can be
covered in 2 more complete manner depending on the objectives of the course.
Some of the material in this chapter may be given in some other course dealing with
information organization and retrieval.
The course could have a scheduled laboratory period each week. The labs
should further the student’s understanding of the application of data structures
concepts to the various areas of computer science. Problem solving skeuld be
stressed along with the design of modules for small information systems. The grade
associated with each lab should be based on analysis, documentation, and
implementation considera‘ions; not just getting some program that produces correct
results.
ACKNOWLEDGEMENTS

The authors would like to thank Michael Doritich for assisting in providing
solutions to many of the problems, and Shane McDonald for assisting in the
formatting of the manual. We also wish to thank Brent Clark for helping to proof
read sections of the manual.
CHAPTER 1

INFORMATION AND ITS STORAGE REPRESENTATION


EXERCISES SECTION 1-1 PAGE 26

Ur ee= = VAP low?)


=e on loge(1/36) + 1/18 loga(1/18) + 1/12 logo(1/12)
+ 1/9 log,(1/9) + 5/36 loge(5/36) + 1/6 log,(1/6)
+ 5/36 loge(5/36) + 1/9 logs(1/9) + 1/12 logo(1/12)
+ 1/18 logs(1/18) + 1/36 log,(1/36)]
= — [1/36(-5.170) + 1/18(~4.170) + 1/12(-3.585)
+ 1/9(-3.170) + 5/36(~2.848) + 1/6(~2.585)
+ 5/36(-2.848) + 1/9(-3.170) + 1/12(-3.585)
+ 1/18(-4.170) + 1/36(-5.170)]
= ~[-3.274]
I 3.274

2) ROLLED AMOUNT FIXED LENGTH CODE

2 0010
3 C011
4 0100
5 0101
6 0116
7 0111
8 1000
9 1001
10 1010
11 1011
12 1100

The length of the code is greater than the value calculated in proble
m 1. The
value calculated should be less than the length of the code since all
possible
combinations of the code are not used, and the entropy measure, H,
is a bound
on the minimum average code length.

t=1
3) ROLLED AMOUNT VARIABLE LENGTH CODE

2 00101
3 1000
4 000
5 011
6 110
7 111
8 161
9 010
10 001
11 0011
12 00100

AVG(length) = S)length of code * probability


=)

= 5(1/36) + 4(1/18) + --~ + 5(1/26) bits


= 3.3 bits

A code with smaller average length is achieved by assigning short codes to


events with a high probability and long codes to events with a low probability.

EXERCISES SECTION 1-4.2 PAGE 35

1) INTEGER BASE3 INTEGER BASE3

1 1 10 101
Z 2 11 102
3 10 12 110
4 11 13 111
5 12 14 112
6 20 15 120
7 21 16 121
8 22 17 u22
9 100
2) INTEGER BASE9 INTEGER BASE9

1 1 10 11
2 2 11 12
3 3 12 13
4 4 13 14
5 5 14 15
6 6 15 16
i 7 16 17
8 8 Lia 18
9 10

Numbers written in base 3 and base 9 are related. If base 3 numbers are
grouped in groups of two from the ternary point, and these groups are
converted to their decimal equivalent, then the resulting number is the
equivalent base 9 code from the original base 3 code.

EXERCISES SECTION 1-4.3 PAGE 43

—33: 64 — 33 = 31 = (011111), Invalid result


~52: 64 — 52 = 12 = (001100), Invalid result
(-33), = -27: 64 - 27 = 37 = (160101),
(-E)ip = -14: 64 - 14 = 50 = (110010),
—241: It is impossible to represent —241 as a 6-bit number!

6-1 = (0110). + 2’s comp(({0001).)


= (0110), + (1111),
= (0101), = 5
7-(-2) = (0111). + 2’ comp(2’s comp((0010),))
= (0111), + 2’s comp((1110).)
= (0111) + (0010),
= (1001), = —7 Invalid result
-3-3 = 2’ comp((0011)2) + 2’s comp((0011).)
= (1101), + (1101),
= (1010), = 6

3a) 8+8 = (01000), + (01000),


= (10000), = -15 Invalid result
b) 6-1 = (00110). + 1’s comp((00001).)
(00110), + (11110),
= (00100), + (1).
= (00101), = 5

1-3
c) 7-11 = (00111), + 1’s comp((01011),)
= (00111), + (10100),
= (11011), ==4

EXERCISES SECTION 1-4.4 PAGE 48

la) i. 0000000000011011
ii. 0000000000011011
b) i. 1212111011111111
ii. 1111111100006000
c) 1. 1111111111111000
Hi. =.1111111111111001
d) i. 0000000060000111
ii. 0000000000000111
e) i. 0000000000101100
ii. 0000000000101100

2a) 001001111100
b) .0010010101101101
——
ES en

c) O1NJ1103
d) 01141100
~~

e) 010001001100

3), i 25 = (4)e #16"


representation:
010000090 10000000000000000000000

ii, .25 = (.2), *8°


representation:
00000
0100600000000100000060000000000000000000000000600000000

4) .625 = (.101), *2°


representation:
01000000101000000000000000000000

1-4
EXERCISES SECTION 1-4.5 PAGE 56

1) function convbit(ch:char):bitstring;

{ This function returns a sequence of bit values which is representative of the


internal storage representation for that character, i.e. the EBCDIC code. It is
assumed that bitstring has been declared global to the function as type packed
array[1..8] of char. }

var index,value,i,j,rem:integer;
bitrep:bitstring;

begin
{ case statement to determine decimal equiv of code }
case ch of
bal tb! tel td! lel Mtg! th! fil: begin
index := ord(ch) — ord(‘a‘);
value := 129 + index
end;
km!
a!o!,'p! ql /r!: begin
index := ord(ch) — ord('j’);
value := 145 + index
end;
Ish 1th tal ty! tw! bx! ty! tal: begin
index := ord(ch) — ord('s‘);
value := 162 + index
end;
VAN IBIIC!D!
ER! IG! HET: begin
index := ord(ch) — ord('A’‘);
value := 193 + index
end;
yy i PME NGI ORD E TOy eRe begin

index := ord(ch) — ord('J');


value := 209 + index
end;
FOU GAN NEE ETE: begin

index := ord(ch) — ord{'S’);


value := 226 + index
end;
lO ETOP TS OEAE EE! (GO! SiGe begin

index := ord(ch) — ord('0’);


value := 240 + index
end;
ot value := 75;
iS value := 76;
3
i value :== 77;
hol: value := 78;
Fes value :== 80;
ai value := 90;
ist value := 91;
Ls value := 92;
At: value := 93;
ee value := 94;
forte value := 95;
caus value := 96;
Oy value := 97;
ae value := 106;
pes value := 107;
ee value := 108;
pine value := 109;
Sts value := 110;
Riot value := 111;
ne value := 121;
ihe value := 122;
fee value := 123;
'@’: value :== 124;
ate value :== 125;
Feel value := 126;
tere value == 127;
ee value := 64
end;
{ create bit string representation }
1 c==-8;
while (value <> 0) do
begin
rem := value mod 2;
if rem = 1
then bitrep|i] := ‘1’
else bitrep|i] := '0';
value := value div 2;
i:=1i-1
end;
{ pad with zeros }
for j := i downto | do
bitrep[j] :== ‘0’;
{ return result }
convbit := bitrep;
end; { convbit }

1=6
2) procedure conint(val:integer;var equiv:numstring);

{ This procedure converts an integer into its decimal digit character


representation. It is assumed that numstring has been declared global to the
procedure as type packed array [1..10] of char. }

var i,digit:integer;
negflag: boolean;

begin
{ initializations }
for i := 1 to 10 do
equiv[i] :=' ';
{ check for value of zero }
if val = 0
then equiv[10] := ‘0!
else begin
{ check for negative value }
if val < 0
then begin
val := -val;
negflag := true
end
else negfiag := false;
{ convert to char rep }
Lisa 10:
while {val > 0) do
begin
digit := val mod 10;
equiv|i] := chr(digit + ord('0’));
val := val div 10;
i:s=i-1
end;
{ add negative sign if necessary }
if negflag
then equiv{i] := /—
end
{ return }
end;

17
CHAPTER 2

THE REPRESENTATION AND MANIPULATION


OF STRINGS
EXERCISES SECTION 2-2.1 PAGE 73

1) Subject string of the form x#w


MA: EXAMINE (u,y,2,# € V)
Bi: auyzZ + yauz
Po: auu > A
P3: auy > a
tee uffy > #fouy
Pe # — 'b!
Ps: ua>a
Py: a 'c!

Consider the trace of /EXAM#EXAM!


Nothing applicable until...

=> 'EXA#!oa!MEXAM! by P,
=> 'EXA#E'a'MXAM! by P,
=> 'EXA#EX!’a!MAM! by P,
=> 'EXA#EXA!a!MM! by P,
=> 'EXA#EXA! by Ps
=> 'EX#!a! AEXA’ by P,
=> 'EX#E' a! AXA! by P;
=> 'EX#EX'a!' AA! by P,
= 'EX#EX! by Pe
=> 'E#!a!XEX! by P;
=> 'E#E! a!XX! by P,
=> 'E#E! by P,
== al EE’ by Py
—— eu by Ps

=> 'p! by Ps

Nothing else applies, so the algorithm is terminated.

Consider the trace of 'NOT#GO!

=> 'NO#!a'TGO!' by P,
=> 'NO#G'a'TO' by P,
=> 'NO#Gte by Ps
=> 'N#!/a!OG!la by P,
=> 'N#’aa by Ps
=> 'Nb/aa by Ps
== Nae by Pe
=> aa by Pe
=> 'ca by P;

251
=> a , by Pe
=> 'c! by Pz ;

MA: TRANSFORM (x,y « V) LMA: TRANSFORM (x,y € V)


Py: ox — xd Py: Aa
PS 5+ a Po: ax + X@ (Po)
P3: : Bxy — yPx Pz: xa — axPx
Py: pA Py: Bxy > yhx (Pa)
Ps: xa — ax $x Ps: BoA (Ps)
Pe: a— A. Pe: av~kh
Pz: Aw 6

Consider the trace of LMA given ‘abc’

=> alabc! by P;
=> 'ala'bc! by Po
=> 'abla'c! by Po
=> 'abcla by Po
=> 'abla'c! pc! by Ps
=> 'abla'cc! by Ps
=>. ‘a'a'b'p bec’ by Ps
== ‘alatbe’sbe’ by FP,
=> 'ala'bee! pb! by Ps
=> 'ala'becb! by Ps
=> oa Pabech’” . by Ps
=> alab’flacch’~ by P,
=> alabc! flacb’ by Ps
=> alabcc! flab! by P4
=> alabccb!fla' by Py
=> a'abccbal by Ps
=> 'abccba’ by Pe

MA: DIFFERENCE(1,- ¢ V)
Pe 44]! URS

Pe: t _s A
to
The approach involves taking the first character in the string and moving it
If a
the end of the string and matching it with the previous end character.
whole
match is achieved, the last two characters are removed and the
matching process begins again. If a match is not achieved, a palindrome does
the
not exist and we halt with output 'b’. If matching is achieved throughout
entire string, then the algorithm halts with output rat

a2
LMA: PALINDROME (x,y « V)
LOOP: A->a
AGAIN: = axy > yax (AGAIN)
xax + A (LOOP)
Kae (OUTB)
ax + a (OUTB)
a—'al.
OUTB: xa>a _ (OUTB)
ax—+a (OUTB)
a 'b!.

The basic strategy is to take elements of x and move them individually (via
mark symbols) over to corresponding elements of y and check to see if x; = y;
for each 1; i = 1 to length of x. If a match fails, then the element-by-element
matching process must be reinitiated with the substring of y consisting of
Y2, Ya, ---» Ym Where m is the length of the complete string y. This matching
process continues for all such substrings of y. If the process fails, then the
roles of x and y are reversed and the matching process is reinitiated.

LMA: SUBSTRING (x,y € V)


‘#! + '#' Bp
SARA: A->a
AGAIN: a ay
Y#! +A (GOOD)
xX > xx [duplicating z]
ax + xa ' [move a]
LOOPI1: XY —> VX
“xB > Brx (LOOP2)
NSA (LOOP1)
LOOP2: yxy + yyx (LOOP2)
yxpx — xp (AGAIN)
yxp > A
eee (INIT)
[y substring of x|
aA
Bh
A> ay
MARK @: '#! _,' 8B
NEXTCH: fx > xpx8 (CHECK)
eon (GOOD)
CHECKy: 7#' +A (BAD) [hit the end of x]
Ree raney
RY: yxp — xpy (TRY)
XyxXp > xy (NEXTCH)
Vp = K

2-3
BoA
ax + xay (MARK)
BAD: a> aa
GOOD: BoA
ies
pt A
LOOP3: xa->a (LOOP3)
LOOP4: ax—> a (LOOP4)
FINAL: a+ '#! (FINAL)
As A,
INIT: a>
B— Bp (START)
LMA: DIVIDE
P;: [1 /al
Py»: al — la (Pa)
Ps: a—+ B (P;)
Py jo] (Po)
Ps: a—+>A
Pe: fA
Pz: I-A (P7)
P3: Bol (Ps)
Consider the example 7/2 > 1111111/11

1111111/a11 by P,;
1111111/lal by P»
111111/lo1 by P,
1111li/lle by P»
lll11/lla by Py
11111/118 by Ps
lllll/all6 by Py
111l1/lalB by Py
1111/1a1f by P,
l111/lloB by Pp
111/1lap by P,
111/116 by Ps
111/a11p6 iby P,
111/1a1f88 by P,
11/1188 by P;
11/l1a66 by Po
1/11ahp by P,
1/11666 by Ps
1/a11666 by P;
| 1/1a1p88 by Py
2-4
=> /1alp6B by P,
=> /110888 by P,
eR yeisfe. by P;
=> 11/88 by Pe
=> pBp by P;
= lil by Ps

7) LMA: STRING(x ¢ V, z « V + {others})


A 9
MOVES: bz — 2B (MOVES)
ENDQ: 1B» B (FRONTQ)
Aa (INVALID)
FRONTQ: Aa
al”! —» a (INQ)
AA (INVALID)
INQ: mt, (INQ)
via (INVALID)
CHARS: x SPK (CHARS)
ab '1!.
INVALD: 2A (INVALID)
ap — '0'”

8) LMA: BLANKS ('f! =! ‘[blank])


P,: PR > 'B (Pi)
MA: BALANCED (x € {(,<})
Py: <a> a
Pr (a) + a
Ps: ax — Xa
Py: oN
Ps: A ra

10) LMA: WORDCOUNT (x ¢« V — {'p'})


jes 'p!

RMBLKS: ‘pp — ‘Pp! (RMBLKS)


RMCH: x—7A (RMCH)
COUNT: ee (COUNT)

11) LMA: LEFT_PAR (y ¢€ V)


FINDLEFT: 1h + al(! (RM_LEFT)
EMPTY: yo (EMPTY)
A> A,
RM_LEFT: yaoa (RM_LEFT)
‘Vy + '\'B (RM_RIGHT)
aA (EMPTY)

2-5
RM_RIGHT: by > B (RM_RIGHT)
FINAL_OUT: Bond
aos.

12) The Markov model lacks:


i. proper input and output facilities;
ii. the ability to apply pattern matching to more than one Puneet string in
an algorithm;
iii. in general, the character handling facilities are sufficient but are too
primitive for a useful programming system (this is easily demonstrated
by examining the facilities in the SNOBOL language as presented in the
text)

EXERCISES SECTION 2-2.4 PAGE 93

1) function find(var subject,pattern: string;var cursor:integer;var matchstr:


string;replaceflag:boolean;replacestr:string }boolean;

{ Function find returns true if the string, pattern, is found anywhere in the
subject string from the cursor character to the end of the subject string. If a
match occurs, matchstr is set to the string beginning with the cursor character
and including all characters to the left of the first character of the pattern
matched. If pattern is found starting with the cursor character, matchstr is
set to the empty string. If replaceflag is set, then all characters starting from
the cursor character up to the right-most character of the matched substring
are replaced by replacestr. }

var temp:string;
integer;
result:boolean;

begin
{ check if pattern fits in bounds of subject string }
if cursor > length(subject)
then result := false
else begin
{ search for pattern match }
sub(subject,cursor,length(subject),temp);
i := index(temp,pattern);
ifi=0
then result := false
else begin

2-6
{ set matchstr and replace }
sub(subject,cursor,i-1,matchstr);
if replaceflag
then begin
psdsub(subject,cursor,length(pattern)+i-1,
replacestr);
cursor := cursor+length(replacestr)
end
else cursor :== cursor+i+length(pattern)-1;
result := true
end
end;
find := result

end; { find }

EXERCISES SECTION 2-2 PAGE 100

1) Concatenation can be implemented in terms of the SUB function by using


SUB in an assignment mode. For example, C + ‘A’ © ‘'B’, can be expressed
as SUB(C,1,1) + ‘A’, and SUB(C,2,1) + ‘B’. The formulation, however, is
very awkward. INDEX can be implemented using SUB by repeatedly testing
substrings for equality up to the length of the subject string. SUB and
LENGTH are not realizable using the other functions, and as such can be
considered to be ‘‘more’’ primitive. However, concatenation and INDEX are
used so commonly in string applications that, to not have them makes the
task of programming such applications very difficult.

to— Algorithm DUPL. Given a subject string, SUBJECT, this algorithm


generates the string, REPL, with the desired number of replications, N.

1. [Check for valid replication factor]


IfN<0
then Exit
2. [Perform concatenation]
REPL + "
Repeat for I = 1, 2,...,N
REPL «— REPL ©° SUBJECT
3. [Finished]
Exit

2-7]
Algorithm TRIM. Given a subject string, SUBJECT, this algorithm trims
off all trailing blanks.

1. [Initialize cursor to last character]


Ie LENGTH(SUBJECT)
2. [Find first non-blank character tracing back]
Repeat while SUB(SUBJECT,I,1) = ‘#'
I+I-1
3. [Remove blanks]
SUBJECT + SUB(SUBJECT,1,])
Exit

Function BREAK(SUBJECT,PATTERN,CURSOR,MATCHSTR,
REPLACE _FLAG,REPLACE_STR). Given the six pattern matching
parameters, this function scans the subject string on a character by character
basis, starting at the given cursor position and proceeding to the first instance
of a character which is also a character in the pattern string. FOUND is a
boolean variable indicating whether or not a match occurred. I is an integer
variable denoting the position of the match.

1. [Check if pattern fits in bounds of subject]


If CURSOR > LENGTH(SUBJECT)
then Return(false)
2. [Search for pattern match]
FOUND + false
I + CURSOR
Repeat while (;FOUND) and (I < LENGTH(SUBJECT))
if INDEX(PATTERN,SUB(SUBJECT,I,1)) 4 0
then FOUND + true
else I+-I+1
3. [Break character not found]
If -FOUND
then Return(false)
4. [Break character found]
MATCHSTR + SUB(SUBJECT,CURSOR,I - CURSOR)
If REPLACE_FLAG
then SUB(SUBJECT,CURSOR,I-CURSOR) + REPLACE_STR
CURSOR + CURSOR + LENGTH(REPLACE_STR)
else CURSOR + I
Return(true)

2-8
5) procedure delete(var str:string;list:string);

{ All occurrences of each character contained in list are deleted from str. }

var i:integer;
temp,half1,half2:string;

begin
{ initializations }
e—s2°
{ delete bounded characters }
while (i < length(str)) do
begin
sub(str,i,1,temp);
if index(list,temp) <> 0
then begin
sub(str, 1,i-1,half1);
sub(str,i+1,length(str),half2);
concat(half1,half2,str)
end
else i :=i+1
end;
{ delete leading character }
if length(str) <> 0
then begin
sub(str,1,1,temp);
if index(list,temp) <> 0
then sub(str,2,length(str),str)
end;
{ delete trailing character }
if length(str) <> 0
then begin
sub(str,length(str),1,temp);
if index(list,temp) <> 0
then sub(str,1,length(str)-1,str)
end

end; { delete }

6) function verify(str,pat:string):integer;

{ This function returns the position of the first character in str not present in
pat. It is called by the test function below. }

aoe
var i:integer;
next:string;

begin
{ initializations }
ies}
next([1] := str[i];
next([2] := ‘|’;
{ find first char in str not in pat }
while (index(pat,next) <> 0) and (i <= length(str)) do
begin
i:=1+ 1; ‘
next([1] := str[i]
end;
{ check if all chars in str are in pat }
ifi > length(str)
then verify := 0
else verify :=1

end; {verify }

(EBB ROBES EEE BROS IEE OBESE SSEEESE EE IS AGATA AIA AIAAA }

function test(sentence:string):boolean;

{ this function recognizes a sentence of the form: the ‘possession’ belongs to


the ‘possessor’. }

var i:integer;
result:boolean;

begin
{ is ‘the’ the first word? }
i := index(sentence,'The |’);
if (i = 0) or (i <> verify(sentence,’ |'))
then result := false
else begin
{ does possessive phrase and ‘possession’ appear? }
sub(sentence,i + 3,length(sentence),sentence);
i := index(sentence,’ belongs to the|’);
if (i = 0) or (i = verify(sentence,’ |'))
then result := false
else begin
{ does ‘possessor! appear? }
sub(sentence,i+14,length(sentence),sentence);

ae 10
i := verify(sentence,' |');
if i = 0
then result := false
else result := true
end
end;
test := result

end; { test }

program analyze(input,output);

{ This program analyzes text from a data file, giving statistics on the number
of sentences, the average number of words per sentence, and the average
number of character per word. } ;

type string = packed array[1..81] of char;

var numwords,numchars,numsents:integer;
avgwords,avgchars:real;
line:string;
i:integer;
fini:boolean;

GARB SO AS Edn EC doad ed oadindnd dda oa HA nana EHH bree}

procedure getline(var line:string);

{ This procedure reads one line of input text, and places it into the parameter
line. }

var i,j:integer;

begin
{ read one line of input text }
i:== 1;
while (not eoln) and (i < 81) do
begin
read(line[i]);
i1:=i+1
end;
readIn;
{ set delimiter }
line[i] := ‘|!;
{ pad with blanks }
for } := 1+ 1 to linesize do
line[j] :=''
end; { getline }
Saati al aaa eae |

#include 'length.i’;
Sahai lacltdlaediadechteticheechnlatededidecettiaeeh |

begin
{ initializations }
fini := false;
while (not fini) do
begin
{ read one line of text }
getline(line);
{ find first non-blank character }
eo Fe
while line|i] = '' do
1:= i+ 1;
{ process each character in line } .
while (i <= length(line)) and (not fini) do
begin
{ check for end of sentence }
if line[i] = /.!
then begin
numwords := numwords + 1;
numsents := numsents + 1;
i:= 1+ 3;
{ check for end of input }
ifi <= length(line)
then ff line[i] = '/'
then fini := true
end
else { check for end of word }
if line[i] =! !
then begin
numwords := numwords + 1;
ie bt
end
else { check for invalid characters }
= '~’))
if ((line[i] = ',’) or (line[i] = ';’) or (line[i]
then i:=i+1
else { must be valid character }
begin
numchars := numchars + 1;

Zt?
{ check for end of last word of line }
ifi = length(line)
then numwords := numwords + 1;
i:=i+1
end
end
end;
{ output results }
avgchars := numchars/numwords;
avgwords := numwords/numsents;
writeln;
writeln;
writeln(/ NUMBER OF SENTENCES: /:25,numsents:5);
writeln(/ AVERAGE WORDS/SENTENCE ':25,avgwords:5:2);
:
writeln(' AVERAGE CHARS/WORD: ':25,avgchars:5:2);

end.

EXERCISES SECTION 2-3 PAGE 115

1) The language generated is L = {b’a*— € |a,b € V and €is the empty string.}
2a) <nNOI> = <odd digit> | <integer> <odd digit>
<integer> = <digit> | <digit> <integer>
<digit> = <odd digit> ]0|2|4|6|8
<odd digit> :=1|3|5|7|9
<nNEI> == <evenlead> | <lead> <even integer>
<even integer> ::= <evenlead> |0| <digit> <even integer>
<digit> == <lead> |0
<lead> == <evenlead> |1|3|5|7]9
<evenlead> n= 2|446/8

<E> :=b
<E> :=a<E>a
<E> :=b
<b ere ee
<B> Pek
<name> == <alpha> | <alpha> [ <alphanumeric> |°
<alpha> c= ABYC at lag
<alphanumeric> ::= <alpha> |0|1i]2|...|/9| #|$
=—>i*it+i

6a) 7 - = 3
iI
<digit> <op 1>
| <digit> <op 1>
| <digit>

<dec arg> <dec arg> <dec arg>


|
<DDC term> <DDC term> <DDC term>

<DDC expr> <DDC expr> <DDC expr>

<DDC expr>

<DDC expr>

OR:

7
|
=

<op 1>
6

:
=
|
<op 1>
i
3

|
<DDC expr> <DDC expr> <DDC expr>

<DDC expr>
Bene eee

With the first parse, we get the result (7-6)-3 = —2.


The second parse yields the result 7-(6-3) = 4.
Change:
<DDC expr> := <DDC expr> <op 1> <DDC expr>
to
<DDC expr> ::= <DDC expr> <op 1> <DDC term>
The expression will be evaluated as
7 + ((6 * 3) / 2) = 16
This change in the grammar implies that +, — will now have precedence «over
*, /. Therefore the expression is now evaluated as (((7 + 6) * 3) / 2)= 19
<procedure head> ::= PROCEDURE <body>;
<body > ::= OPTIONS(MAIN) | <parm clause> <op clause>
<ret clause>
<parm clause> == (<parm list> )| ¢
< parm list> == <identifier> | <parm list> , <identifier>
<op clause> ==: RECURSIVE | ¢
<ret clause> ::==: RETURNS ( <type> )| €
<type> == FIXED |FLOAT | BIT(*) VARYING |
CHARACTER(#) VARYING

5) < expression > <expression> + <term>


<term> + <term>
<factor> + <term>
<factor> + <factor>
i+ <factor>
VUUNdGit+i

< expression > <expression> — <term>


<expression> — <term> / <factor>
<expression> — <factor> / <factor>
—> <term> - <factor> / <factor>
Viodd
<factor> — <factor> / <factor>

iy Rey
< expression > <term>
<term> * <factor>
<factor> * <factor>
<factor> * (<expression>)
<factor> * (<expression> -++ <term>)
<factor> * (<term> + <term>)
<factor> * (<factor> + <term>)
VUbddddy
<factor> * (<factor> + <factor>)

I > i¥*(iti)
<expression> => <expression> + <term>
=> <term> + <term>
=> <term> * <factor> + <term>
=> <factor> * <factor> + <term>
=> <factor> * <factor> + <factor>

2715
7a) <string> := <A>b <A>
<A> == ala<A>
b) <string> u= <A> <B> <A>
<B><A> = bal <B> <B> <A>‘a
<A><B> :=ab|a<A> <B> <B>
<B> == Dp

8) EXPRESSION = TERM| *EXPRESSION ‘+’ TERM


TERM = FORM |FORM '* TERM
FORM ay

EXERCISES SECTION 2-4 PAGE 123

la) word i

S i R I

x! E! X’ES’ xX'D9! x’ C9!

word i+ 1

N G

X'D5! X'C7!

b) word i |

length field S T

length = 6 X!E2! ES

2=16
wordi+ 1

R I N G

1101 1001 1100 1001 1101 0101 1100 0111

X'D9! x'Cy X'D5! X'C7!

c) length field pointer field

0000 0110 0001 1010 DESCRIPTOR

length = 6 address = 26

S - R I N G

00110011}00110100 | |00110010} 00101001 co101110 00100111


|

word 13 word 14 word 15

| string space

b) No, such assignments cannot be handled using the boundary marker method.
Suppose C + ‘EXAMPLE’ and then S «+ SUB(C,3,2). The result would be

Coe ae |
s {+—
In addition to assigning S the value ‘AM’, the side-effect of changing the value
of C to ‘E’ would occur. With the descriptor method, no such side-effects
would occur.
3) A garbage collection agency would make efficient use of memory; however, it
is gained at the expense of additional processing time. Therefore, the
feasibility is determined by the application. Generally, memory is a scarce
resource so garbage collection is warranted.
Not all of the spuce pointed at by the vector of ‘‘old’”’ descriptors is
necessarily garbage; some active descriptors may point within a string
identified by an “‘old’’ descriptor. This means garbage is recognized as the
space pointed at by the “‘old’’ descriptors, and not by any of the descriptors in
use.
One method for managing the garbage collection agency is to maintain
vectors (ordered by address) of the “old” descriptors and descriptors in use.
Redundant ‘‘old” descriptors could be removed and adjacent free spaces could
be merged to reduce the size of the vector. When memory is requested, a
search is made of the ‘‘old’’ descriptor vector for a chunk of memory large
enough to satisfy the request. Recall that a check must be made to be sure
that no space within the chunk is pointed at by a regular descriptor vector.
If a request is filled by re-using ‘‘old” space then a new descriptor must
be added to the regular descriptor list and the ‘‘old” descriptor must be
modified or removed.

EXERCISES SECTION 2-5.1 PAGE 134

1) Procedure CENTER(INPUT_LINE,LMARGIN,RMARGIN).
the character string, INPUT_LINE, and LMARGIN and RMARGIN, integers
Given

denoting the positions of the left margin and right margin characters
respectively, the text is centered within the bounds, and printed out.
LEADBL is an integer indicating the number of leading blanks on the line.

1. [Determine number of required leading blanks]


LEADBL + TRUNC(((RMARGIN - LMARGIN + 1) -
LENGTH(INPUT_LINE)) / 2)
LEADBL + LMARGIN + LEADBL - 1
2. [Print out}
INPUT_LINE — DUPL(’ }’ LLEADBL) 0 INPUT_LINE
Write(INPUT_LINE)
2. [Finished]
Return
2) Procedure APPEND(TEXT,AVAIL). Given AVAIL, the index into the
next available position in the LINE vector, the procedure inserts TEXT into
that position. MAX is an integer denoting the last possible position in the
LINE vector.

1. [Check for overflow]


If AVAIL > MAX
then Write(/LINE VECTOR OVERFLOW’)
Return
2. [Append text]
LINE[AVAIL] + TEXT
AVAIL + AVAIL + 1
3. [Finished]
Return

Procedure DELETE(X,AVAIL). This procedure deletes the specified


line, in position X, from the LINE vector, and adjusts AVAIL, the index into
the next available position in the LINE vector.

1. [Delete X and adjust vector]


Repeat for I = X, X + 1, ... AVAIL - 2, AVAIL - 1
LINE|I] — LINE|I + 1]
2. [Set AVAIL]
AVAIL + AVAIL - 1
3. [Finished]
Return

Procedure CHANGE(PATTERN,NEW). This procedure finds the first


occurrence of the string PATTERN in the LINE vector, and replaces it with
the string NEW. FOUND is a boolean value indicating whether or not a
match occurred. I is the line number on which a match was made. START is
the position of the pattern in the line.

1. [Initializations]
FOUND + false
Lit
2. [Search for PATTERN]
Repeat while -FOUND and I < AVAIL
If INDEX(LINE[I], PATTERN) + 0
then FOUND + true
else I+I+1
4, |Check if pattern found]
if -FOUND
then Write(/PATTERN NOT FOUND’) -
Retarn :
4, (Make substitution]
START — INDEX(LINE[I PATTERN)
SUB(LINE[] START ,LENGTH(PATTERN)) — NEW
5. [Finished]
Return

EXERCISES SECTION 2-5.2 PAGE 128

1) program sanner(input output),

{ A given wource statement is separated into its constituent lexical classes.


The source forms along with comresponding representation numbers are printed
in 4 manner similar to which they may be passed to 2 parser. Pascal
comments (over line boundaries) are allowed and ignored. }

type rin, = packed array[1. 41) of char;

Var posinteger;
next delim Jine numeric alpha alphanum ,reserved-string,
comment, test: boolean;

[FFE EISEN IIIS ISAS IIIS AEA IIIAAAS)


#include ‘length.i
#include ‘index.
{#449994 4SSEEAENSIEIAI SSISTENIISIESSSIEASSESID EAE AINS ES SASBESSESSSIAS)

procedure revdsym;

{ This procedure handles operator tokens or representations. }

Var ‘integer;

begin 7
{ determine which reserved symbol }
>a i c= index{reserved next);
{ separate into 1 and 2 character symbols }
if(line|pos + 1] = '*’) and (i = 3) { exponentiation }
then begin

2-20
writeln;
writeln(/ TOKEN = ':8,'8 *#':5);
pos := pos + l
end
else if (line[pos + 1] = '=') and (i = 7) { assignment }
then begin
writeln;
writeln(/ TOKEN = ':8,'7 :=':5);
pos := pos + l
end
else ifi = 8 { opening comment delimiter }
then comment := true
else if i = 9 { closing comment delimiter }
then writeln(’/***ERROR: EXTRA DELIMITER##*+’)
else ifi <> 10 { all symbols except ';’ }
then begin
ifi<=4
then write(/ TOKEN = ':8,((i+5)div 2):1,
1 1.9)
else write(/ TOKEN = ':8,i:1,' ':2);
writeln(next:1)
end
end; { rsvdsym }

HEE EH UTE EEE COREE }


{8995448 EEE ELYRIA HESS

function nonblank(var ch:string):boolean;

{ This function passes the next non-blank character in the input stream
through the parameter ch, returning true if an eof has been reached. }

var i,j:integer;
result: boolean;

. begin
{ check for processing of comment }
if (comment)
then if (index(line,delim) <> 0)
then begin
comment := false;
pos := index(line,delim) + 1;
while (pos <= 80) and (line[pos] = ' ') do
pos := pos + 1
end
else comment := true {dummy assignment}

Zoe
else begin
{ find next non-blank character }
pos := pos + 1;
ifpos <> 81.
then while (pos <= 80) and (line[pos] =‘ ') do
pos := pos + l
end;
{ loop to read in new lines until non-blank char or
comment delimiter found }
while ((pos = 81) or (comment)) and (not eof) do
begin
{ read new line }
ele
while (i <= 80) and (not eoln) do
begin
read(line[i]);
l= p+ 1
end;
- readin;
{ pad line with blanks }
for j := ito 80 do
line[j] :=' ';
line[81] := '|';
{ print data of line }
writeln;
writeln;
writeln(!**LINE** ':9 line :80);
writeln;
{ check if comment delimiter is present }
if (comment)
then if (index(line,delim) <> 0)
then begin
comment := false;
pos := index(line,delim) + 1;
while (pos <= 80) and (line[pos] = ' ‘) do
pos := pos + 1
end
else comment := true {dummy assignment}
else begin
{ determine position of first non-blank character }
pos := 1;
while (pos <= 80) and (line{pos] = ' ') do
pos := pos + l
end
end;

2522
{ check for end of data file }
if (eof) and ((pos = 81) or (comment))
then begin
result := false;
if comment
then writeln(!*##£RROR: NO DELIMITER***")
end
else begin
result := true;
ch{1] := line[pos]
end;
nonblank := result
end; { nonblank }
DEBE EEE OE BOAO EOE EAE SE EASES gE ESE BE Gn gE }

procedure scan(valid:string;code:char);

{ This procedure handles numeric and identifier tokens. }

var temp:string;

begin
{ initializations }
temp := ! |;
{ write code number }
write(/ TOKEN = ':8,code:1,' !/:2);
{ pass through all valid characters }
temp[1] := line[pos];
while (index(valid,temp)<>0) and (pos <= 80) do
begin
write(line[{pos]:1);
pos := pos + 1;
if pos <> 81
then temp[1] := line[pos]
end;
if code = '2!
then writeln(' ');
{ adjust pos to point to last valid character }
pos := pos — l

end; { scan }

EBSA SESE MAIN PROGRAM SAS aor aaaEEE es}

2-23
begin
{ initializations }
pos := 80;
comment := false;
next := ! |';
numeric := '0123456789|';
alpha := ‘abcdefghijklmnopqrstuvwxyz|';
alphanum :=='0123456789abcdefghijklmnopqrstuvwxyz|';
reserved := '+--*/():{}5|';
delim := '}|';
{ get first nonblank symbol }
test := nonblank(next);
{ process chars until end of file detected }
while (test) do
begin
if index(numeric,next) <> 0 { check for numeric representation }
then scan(numeric,’2’) :
else if index(alpha,next) <> 0 { check for identifier representation }
then scan(alphanum,'1’)
else if index(reserved,next) <> 0 { check for operator }
then rsvdsym
else begin
{ invalid symbol detected }
writeln;
writeln('#*#*ERROR: BAD SYMBOL /:25,next:1,
' DETECTED IN COLUMN (:20,pos:3);
end;
{ get next nonblank character }
test := nonblank(next)
end;
writeln;
writeln;
writeln(/END OF FILE DETECTED’); -
end.

To include the capability of automatically numbering source statements,


modify the NONBLANK procedure as follows:
i. every time a new line is read, increment a tally variable, NUMLINES,
by 1.
il. when the data of the line is output, write the value of NUMLINES at
the same time.
ill. the initial value of NUMLINES should, of course, be 0.

2<24
EXERCISES SECTION 2-5.3 PAGE 143

1) Function ORD_SEARCH(ORD_WORD,WORD). Given a character


string, WORD, this function searches the ORD_WORD array, looking for the
word string. If the word is present, then its index location in ORD_WORD is
returned; otherwise a value of 0 is returned. The vector size is given by the
global variable LAST_WORD.

1. [Initializations]
LOC + 0
I+ 1
2. [Linear search]
Repeat while I < LASTWORD and LOC 4 0
_If WORD = ORD_WORDII]
then LOC +]
else I+I+1
3. [Finished]
Return(LOC)

Algorithm LIST_KWIC. This algorithm interprets ‘LIST KWIC’


commands and outputs only the KWIC index terms as specified in the index
term expression for the command. PRINT_TITLE is a one-dimensional array
of boolean values; one for every title in the index. If the title is to be printed,
the array value is true; otherwise it is false.

1. [Loop to process all command data]


Repeat thru step 3 while there remains input data
2. [Read command line]
Read (COMMAND)
3. [Check validity]
If SUB(COMMAND, 1,14) eo 'LISTPK WICHFORP!
then Write(/INVALID ENTRY’)
else COMMAND + SUB(COMMAND,15) (isolate expression)
Repeat for L==1):2, ..., BAST TITLE
PRINT_TITLE + false (initialize vector)
Call INTERP(COMMAND,PRINT_TITLE)
Repéat for d= 1.2, a LAS
lL fle,
If PRINT_TITLE[I]. (produce output)
then Write(TITLE[]])
4. [Finished]
Exit
Procedure INTERP(COMMAND,FOUND). This is a_ recursive
procedure which interprets COMMAND as an index term expression and flags
titles to be printed through the parameter vector FOUND. Integer variables
LOC and I are used to find the position of the keyword in the vector. String
variables LIST and NUM and integer variables I, END, and IND are used to
isolate the title numbers. Integer variables CHECK and NUMB are used in
isolating operands of the expression. Boolean vectors OUT1 and OUT2 are
used in recursive calls for evaluating the expression. Function VERIFY returns
the location of the first character in the subject string, not found in the
pattern string.

1. [Check for base case - no relation operators]


If SUB(COMMAND,1,1) <> ‘(' (initializations)
then LOC + 0
I~ 1
Repeat while I < LAST_KEY and LOC 4 0
If COMMAND = KEYWORDI]]_ (find keyword)
then LOC «+ I
else I«+I+1
If LOC 40
then LIST — T_INDEX|LOC] (find titles)
I — VERIFY(LIST,'#’)
Repeat while (I 4 0) (isolate and mark titles)
LIST — SUB(LIST,1)
END « INDEX(LIST,’P’)
NUM + SUB(LIST,1,END-1)
IND «+ CONVINT(NUM)
FOUND|IND] + true
LIST — SUB(LIST,END)
Return
2. {Process relational expressions]
CHECK «+ INDEX(COMMAND,'PAND$’)
If CHECK = 0
then CHECK «+ INDEX(COMMAND,'BOR#’)
NUMB + 1
I+ 2
3. [Find operands by locating brackets or relational operators]
Repeat while NUMB ~ 1 or I < CHECK
If SUB(COMMAND,I,1) = ‘('
then NUMB + NUMB + 1
else If SUB(COMMAND,I,1) = ‘)!
then NUMB «— NUMB - 1
I+I+1
4. [Recursive call with left operand]
Call INTERP(SUB(COMMAND,2,I-1),OUT1)

2-26
5. [Separate into and/or relations]
If SUB(COMMAND, I+ 1,3) 23 AND!
then Call INTERP(SUB(COMMAND, I+5),OUT2)
Repeat for I = 1, 2, .... LAST_TITLE
If OUTI[I] and OUT2II]
then FOUNDII] + true
else FOUNDII] < false
else Call INTERP(SUB(COMMAND, I+4),OUT2)
Repeat for I = 1, 2, ..., LAST_TITLE
If OUT}{I] or OUT[I]
then FOUNDII] + true
else FOUND|I] + false
6. [Finished]
Return

Function KEYSEARCH(WORD). Given a keyword, WORD, this


function searches the KEYWORD array for the keyword. If it is found, then
its index location in KEYWORD is returned; otherwise the word is inserted at
the appropriate location as determined by the lexical ordering of the
keywords. Space is also left at the corresponding location in the TITLE array.
LAST_KEY is the index of the last keyword in KEYWORD. I, J, and LOC
are integer variables.

1. [Initializations]
LOC + LAST_KEY + 1
I+ 1
2. [Linear search]
Repeat while I < LAST_KEY
If WORD > KEYWORD{]]
then LOC +I
I-—I+1
3. [Insert keyword in appropriate location if necessary|
If WORD 4 KEYWORD[LOC]
then Repeat for J = LAST_KEY + 1, LAST_KEY + 2, ...,. LOC + 1
KEYWORD|J] + KEYWORD{J — 1]
T_INDEX[J] — T_INDEX{J — 1]
LAST_KEY + LAST_KEY + 1
KEYWORD|LOC] + WORD
4. [Finished]
Return(LOC)
CHAPTER 3

LINEAR DATA STRUCTURES AND THEIR


SEQUENTIAL STORAGE REPRESENTATION
EXERCISES SECTION 3-2 PAGE 152

1) In general, the location of element Ay in a two-dimensional array with


arbitrary lower and upper bounds on its subscripts can be given as follows:

Assuming b,<i<u, and bo<j<up the location of Ay is given by:


loc(Ay) = Lo + (j — be) * (uy — by + 1) + (i- by)

When b, = 0, be = 1, u, = n- 1, and up = 6
loc(Ay) = Lo + (j - 1) * M- 1-14 1) + (i- 0)
=L)+(j-1)*(n-1) +i

tb — loc(Ay) eas Lo ahi [(i = b:) * (us = be ats 1) = (j a ba)} * 4 bytes


= 2000 + [(4 - 1) * (3-1 +4 1) + (2- 1)] * 4bytes
= 2000 + [(3) * (3) + 1] * 4 bytes
= byte 2040

3) —loe(b;) = Lo + [(4) * (1) + i- 1] * 4 bytes

4) loc(X[i,j,k]) = Lo + 6 * (i-1)+2*(j-1)+k+41

EXERCISES SECTION 3-3 PAGE 161

1) Differences between arrays and structures include:


i. Elements of arrays must be of the same data type whereas structures are
nonhomogenous, that is, their elements can be of different data types.
ii. All elements in an array are uniformly offset from one another; therefore
address calculation can be easily implemented in formulas, whereas
every element in a structure bears some offset from its ancestor element
dependent upon the element’s type; therefore address calculation
formulas are not as straightforward.

=) am n bytes m bytes

b) loc(emp[i].adr) = BASE + (i * n) + ((i - 1) * m) bytes

3-1
3) 1) GRAINS
2 WHEAT
3 PROD (integer)
3 PRICE (real)
2 BARLEY
3 PROD (integer)
3 PRICE (real)
2 OATS
3 PROD (integer)
3 PRICE (real)
2 RAPESEED
3 PROD (integer)
3 PRICE (real)
2 FLAX
3 PROD (integer)
3 PRICE (real)

4) 1 REQUEST
2BOOK_TITLE (string - 80 chars)
2 PRICE (real)
2 WHO(20)
3 NAME (string - 40 chars)
3 ADDRESS (string - 160 chars)

5a) const placesize = 30;

type place = packed array[1..placesize] of char;


class = (connaisseur,tourist,economy);
time = record
hour: 0..23;
min: 0..59
end;
date = record
date: 1..31;
month: 1..12;
year: integer
end;
ticket = record
origin: place;
destination: place;
daydepart: date;
departtime: time;
estarrivaltime: time;
flightno: integer;
seatno: integer;

are
smoking: boolean;
window: boolean;
seatclass: class;
price: real
end;
b) const namelen = 30;
addrien = 80;
contracts = (A,B,C,D);

type card = record


name: packed array[1..namelen] of char;
address: packed array[1..addrlen] of char;
contractnum: integer;
contracttype: contracts;
hospnum: integer;
expiry date: record
day: 1..31;
month: 1..12;
year: integer
end
end;
c) const namelen = 30;
addrlen = 80;
phonelen == 9;

type creditcard = record


name: packed array[{1..namelen] of char;
address: packed array{1..addrlen] of char;
phone: packed array|1..phonelen] of char;
creditrating: integer;
expiry date: record
day: 1..31;
month: 1..12;
year: integer
end
end;
d) const namelen = 30;
addrlen = 80;
strlen = 10;

type measure = record


feet: integer;
inches: integer
end;
date = record
day: 1..31;

oo
month: 1..12;
year: integer
end;
license = record
name: packed array[1..namelen] of char;
address: packed array[1..addrlen] of char;
licnum: integer;
liccode: integer;
birth: date;
expiry: date;
coloreyes: packed array[1..strlen| of char;
height: measure
end;
e) const namelen = 30;

type studentid = record


name: packed array{1..namelen| of char;
number: integer;
librarycode: integer;
expiry: record
day: 1..31;
month: 1..12;
year: integer
end
end;

6) 1 ALCOHOLIC_BEV
2 WINE
3 CHAMPAGNE(10)
3 SHERRY(5)
3 RED(20)
3 WHITE(10)
3 SPARKLING(5)
2 WHISKEY
3 RYE(6)
3 SCOTCH(6)
3 BOURBON(3)
2 RUM(10)
2 COGNAC(5)
2 GIN(7)
2 VODKA(5)

3-4
EXERCISES SECTION 3-4 PAGE 176

1) Procedure PUSH(S,TOP2,TEMP). This procedure inserts an element


TEMP at the top of the second stack, with pointer TOP2 denoting the top
element in the stack.

1. [Check for stack overflow]


IP POP2 POP tite
then Write(/STACK2 OVERFLOW’)
Return
2. [Decrement TOP2]
TOP2 + TOP2-1
3. [Insert element]
S{TOP2] — TEMP
4. [Finished]
Return

In this procedure, TOP2 gradually moves to the front of the vector, S.


Therefore, before insertion, a check is made to see if TOP2 < to TOP1 + 1,
which would indicate an overflow. Upon actual insertion, TOP2 is
decremented, evidence of the leftward movement along the vector.
A procedure to push elements onto the first stack would make the same
overflow check, but in a different manner: check if TOP1 > TOP2- 1. Upon
insertion, TOP1 would be incremented, indicating a rightward motion along
the vector.

2) Procedure PUSHI(S,I,X). This procedure inserts an element, X, on the


top of stack I. The flexibility of the stacks is taken advantage of in that in
the case of single stack overflow the other stacks are moved up/down if
possible to make space.

1. [Check for possible overflow]


If Til] > BUI + 1] -1
then (try to move upward)
FOUND + false
Repeat for J = I+1, I+2, ..., N while 7FOUND
If T[J] < Bl[J+1]
then FOUND < true
SAVE + J
If FOUND
then Repeat for J = SAVE, SAVE-1, ..., I+1
Repeat for M = T[J], T[J]D—-1, ..., BIJ]
S[M+1] + S[M]
T(J] — T[J] +1

3-2
BIJ] — BiJ] + 1
else (try to move downward)
FOUND + false
Repeat for J = I-1, 1-2, ..., 1 while >FOUND
If T[J] < BlJ+1]
then FOUND + true
SAVE + J
If FOUND
then Repeat for J = SAVE, SAVE-+1., ..., I
Repeat for M = B[J], B[J]+1, ..., T[J]
S[M-1] — S|M]
BJ] — Bld] -1
T(J] + T[J] - 1
else (entire stack structure is full)
Write(/STACK OVERFLOW’)
Return
2. [Increment TOP]
Ti] — Tif} +1
3. [Insert element]
S[T[]] -— X
4. [Finished]
Return

Function POPI(S,I). This function removes the top element from a stack
L

1. [Check for underflow]


If T{l] = Bil]
then Write(/STACK’ ,I/UNDERFLOW')
Return
2. [Decrement poixter]
TJ] — T[f] -1
3. [Return former top element of stack]
Return (S[T[I] + 1))

EXERCISES SECTION 3-5.1 PAGE 186

la) Procedure MEDIAN(LOWBOUND,HIGHBOUND). Given the upper


and lower bounds of an array, SCORE, this procedure finds the median value
by successively eliminating the highest and lowest values of successively
smaller intervals. It is assumed that the array contains an odd number of
values.

3-6
1. [Only 1 value left?|
If LOWBOUND = HIGHBOUND
then Write(/MEDLAN VALUE IS ! SCORE[LOWBOUND)])
Return
2. [Exchange minimum value]
TEMP <— MIN(LOWBOUND,HIGHBOUND)
I ~ LOWBOUND
Repeat while SCORE[I] +4 TEMP
era
SCORE[I] <—> SCORE[LOWBOUND]
3. [Exchange maximum value]
TEMP «+ MAX(LOWBOUND,HIGHBOUND)
I + HIGHBOUND
Repeat while SCORE|I] a TEMP
be Ta
SCORE[I| <-> SCORE/HIGHBOUND]
4. [Invoke recursive call]
Call MEDIAN(LOWBOUND + 1, HIGHBOUND - 1)
“ [Finished]
Return

Tracing a recursive program:


1. one indicates the number associated with the depth (level) of recursion,
and the call associated with that level. Level 1 is reached through the
main calling routine, level 2 is.reached through the Ist recursive call ...
li. one indicates the parameters and local variables that are stacked upon
entry to each successive level and popped upon exit
ili. one may show important intermediate calculations

Level Number Description Stack Contents Vector

Enter Step 4: Call MEDIAN LOW |1 ins|tsp etl 9667'S] Be 42


level 1 (LOWBOUND, HIGH Pe mh sees
(main call) HIGHBOUND) RET_ADDR|Main| _|

t
TOP
Enter Step 4: Call MEDIAN Pea 12 67 31 26 88
level 2 (LOWBOUND, Can
ia ee
(1st HIGHBOUND) Step 5
recursive
call) T
TOP
Enter Output: MEDIAN VALUE 12 26 31 67 88
level 3 IS 21 (See
|Armes lia
(2nd Step 5|Step 5
recursive
call) t
TOP

oh
Return to Step 5: Return o 12oo 26
« 31 67i 88
level 2
E Main | Step 5

t
DOP.

in to
Return Step 5: Return pj fT 12 26 31 67 88
Maio| ___|

TOP

Return
ae to Step 5: Return 12 26 31 67 88

c) Modifications to MEDIAN in order to calculate the average deviation from the


median would be as follows:
b; Two parameters, TOPSUM and BOTSUM, would have to be added.
They would hold the sums of the top and bottom halves of the vector
respectively. ;
These parameters would be updated after determining the new minimum
and maximum values.
At the end of step 2: BOTSUM «+ BOTSUM + SCORE[LOWBOUND]
At the end of step 3: TOPSUM «+ TOPSUM + SCORE|HIGHBOUND]
ili. At the time the median is output, the deviation would also be output:
Write(' AVERAGE DEVIATION Is! (TOPSUM — BOTSUM)/NUM)
where NUM is the number of elements in the vector.

Function FIND(K,S,N). Given a vector, S, of N elements, this function


finds the Kth smallest element. CTR is a counter used in the processing of
each element. Sl, $2, and S3 are subset vectors of 5S, and N1, N2, and N3
hold the number of elements in each respective subset. M is the divider
between the subsets.

1. [Initializations]
M + S[1]
N1 + N2+ N3+ 0
oe [Isolate subsets]
Repeat for CTR = 1, 2, 3, ..., N
If SICTR] < M
then Ni«+ Ni1+1
S1[N1] + S[CTR]
else If S[CTR] > M
then N3+ N3+ 1
S3[N3] + S[CTR]

3-8
else N2 + N2+1
S2[NQ] — S[CTR]
3. [Make recursive call]
IitK < NI
then Return(FIND(K,S1,N1))
else IfK < N1 + N2
then Return(M)
else Return(FIND(K-N1-N2,S3,N3)}

Level Number Description Stack Contents

Enter Step 3: FIND(K-N1-N2, K RePEc) Fee


level 1 $3,N3) N Be ee eee
(main call) S
RET_ADDR

Enter Step 3: FIND(K,S1,N1)


level 2
(Ist recursive
call)

Enter Step 3: M=5


level 3
(2nd recursive
call)

Return to Step 3: Return(M)


level 2 7

t
TOP
Return to Step 3: Return(FIND
level 1 (K1,S2,N1)) cht aaah oe
arséege te
Main Pat Tey
t
TOP
Return to Step 3: Return(FIND
main (K-N1-N2,$3,N3))
eee ee
3a) Procedure MAXMIN(S,N,START,MAX,MIN). Given a vector S with
N elements, this procedure simultaneously finds the largest and smallest
elements of the vector.

1. [Vector size 1?|


iftoNe—al
then MAX + MIN < S[START]
Return
2. [Vector size 2?]
If Ne 2
then If S[START] < S[START + ]]
then MAX + S[START + ]]
MIN — S[START]
else MAX + S[START]
MIN «+ S[START -+ 1]
Return
3. [Split S]
Call MAXMIN(S,M,START,MAX1,MIN1)
Call MAXMIN(S,N-M,START+M,MAX2,MIN2)
4. [Compare extremes of subsets]
If MAX1 > MAX2
then MAX + MAXI
else MAX «+ MAX2
If MIN1 < MIN2
then MIN «+ MINI
else MIN «— MIN2
= [Finished]
Return

Procedure MAXMIN(S,N,START,MAX,MIN). This is a stack


implementation of the procedure given in part a. Given a vector, S, with N
elements, this procedure simultaneously finds the largest and smallest elements
of the vector. TEMPREC holds the activation record necessary for each
iteration. Initially it contains the values of the parameters as specified by the
calling program, and the return address to the calling program.

1. [Save activation record]


PUSH(A,TOP, TEMPREC)
2. [Check base conditions]
IfN=1
then MAX + MIN + S[START]
Go To Step 9
If N= 2
then If S[START] < S[START + ]]
3-10
then MAX <— S[START aE 1]
MIN + S[START]
else MAX <— S[START]
MIN <— S[START ta 1]
Go to Step 9

3. [Split S]
M+[N/2]
4. [Process Ist half]
N«-M
ADDRESS + Step 5
Go to Step 1
5. [Receive results of process]
Call MAXMIN(S,M,START,MAX1,MIN1)
6. [Process 2nd half
TEMPREC + POP(A,TOP) (restore original environment)
PUSH(A,TOP,TEMPREC) (save activation record)
M+|N/2]
N+N-M
START «+ START + M
ADDRESS + Step 7
Go to Step 1
7. [Receive results of process]
Call MAXMIN(S,N-M,START+M,MAX2,MIN2)
8. [Determine results] ,
If MAX1 > MAX2
then MAX + MAXI
else MAX «+ MAX2
If MIN1 < MIN2
then MIN «+ MINI
else MIN «— MIN2
ad [Restore activation record]
TEMPREC + POP(A,TOP)
Go To ADDRESS

Level Number Description


Stack Contents

Enter Step 1: PUSH(1,TOP,


level 1 TEMPREC)
(main call)
Enter Step 1: PUSH(A,TOP, 21 86 72 21 86 72
level 2 TEMPREC) ASO Se IsO0SL I
(1st pie oF Oeeae
aes
recursive
call)

Enter Step 1: PUSH(A,TOP,


level 3 TEMPREC)
(2nd
recursive
call)

Return to Step 5: Call MAXMIN(S,M


level 2 START,MAX1,MIN1)

Enter Step 1: PUSH(A,TOP,


level 3 TEMPREC)
(2nd
recursive
call)

Step 7: Call MAXMIN(S,N-M, 21 86 72 21 86 72


Return to
level 2 START+M,MAX2,MIN2) 13 99 51 13 99 51

1
21 or 86
Pisce
Gael SeBone a

t
TOP

BhiZ
Return to Step 5: Call MAXMIN(S,M,
level 1 START,MAX1,MIN1)

PUSH(A,TOP, feves72
|ovse72 | |
faseas [is.e9 1[I
Enter Step 1:
TEMPREC)
level 2
(1st ceees
recursive
call)

t
TOP
Enter Step 1: PUSH(A,TOP,
level 3 TEMPREC) 13 9951 | 139951 | 139951
(2nd Owen Pino sl 2
recursive
call)

Return to Step 5: Call MAXMIN(S,M, 2136.72)


218672:| ae
level 2 START,MAX1,MIN1) Hh

genre eae
Ls
Mai

Enter Step 1: PUSH(A,TOP, 21 8672 | 218672


level 3 TEMPREC) 139951 | 13 99 51Hora
(2nd
recursive
call)

ane
Return to Step 7: Call MAXMIN(S,N-M, 21 86 72 21 86 72
level 2 START+M,MAX2,MIN2) 13 99 51 13 99 51

1 PaaS
cae

Return to Step 7: Call MAXMIN(S,N-M,


level 1 START+M,MAX2,MIN2) 13 99 51
eG ea
Paar
1 |
86 or 99

Return to Step 9: TEMPREC + POP


main (A, TOP)

4a) Function BC(N,K). This recursive function finds the Kth binomial
coefficient of the polynomial of degree N given by (A + Bye

1. [Apply recursive definition]


If N= K or kK = 0
then Return(1)
else Return(BC(N-1,K) + BC(N-1,K-1))

b) Level Number Description Stack Contents Computations

Enter BC(2,2
level 1
(main call)

Enter N=K
level 2 Return(1)
(1st recursive
call)

Return to BC(2,1) 1 + BC(2,1)


level 1
Enter BC(1,1)
level 2
(Ist recursive
call)

Enter N=K 3 eqns


level 3 Return(1) Oia ral aeTore|
Pons
2nd recursive Maino| 21 oie
call)
T
TOP

Return to BC(1,0) et 1 + (1 + B(1,0))


level 2 PR RE
Mane [Sion
t
TOP

Enter K=0 Shot ae acted


level 3 Return(1) a
(2nd recursive RES a a
call)
t
TOP

Return to Return(1 + 1) 1+ (1+ 1)


level 2 ioe te aL
eee
i 1

OP

Return to Return(1 + 2)
level 1

t
TOP

Return to Return(3) 3
main

A recursive procedure is basically composed of three parts: a prologue, a body,


and an epilogue. In the prologue, parameters, local variables, and a return
address are saved. In the body, a partial computation is made, and a
recursive call transfers control to the prologue, unless, of course, the base
condition has been met, in which case, control is passed to the epilogue. In
the epilogue, the most recently saved parameters and local variables are
restored and control is passed to the most recently saved address. Clearly
there is a LIFO process here which is best handled by a stack. At each level
of recursion, the necessary information is pushed onto the stack, and upon
exiting from a level, the information is popped.

3715
6) Function TRIM(TEXT). This recursive function removes leading and
trailing blanks from the input string, TEXT.

1. [Check for remaining blanks]


If SUB(TEXT,1,1) = '}’ (at front)
then If SUB(TEXT,LENGTH(TEXT),1) = "p! (at back) -
then Return(TRIM(SUB(TEXT,2,LENGTH(TEXT) — 2)))
else Return(TRIM(SUB(TEXT,2))) :
else If SUB(TEXT,LENGTH(TEXT),1) = 'P! (at back)
then Return(TRIM(SUB(TEXT, 1,ENGTH(TEXT) - 1)))
else Return(TEXT)

7a) Function CONVERT(NUMBER,RADIX). This recursive function


converts a decimal integer, NUMBER, into its radix r form by applying
successive divisions. ANSWER is a string variable that holds the final result.

1. [Recursive call]
If TRUNC(NUMBER/RADIX) > 0
then ANSWER «+ CONVERT(TRUNC(NUMBER/RADIX),RADIX)
else ANSWER + "
2. [Convert integer to character]
ANSWER «+ ANSWER © SUB('0123456789', MOD(NUMBER, RADIX)
ois)
3. [Finished]
Return(ANS WER) '

b)
Level Number Description Stack Contents

Enter Step 1: CONVERT(25,6) INUIMBER iiss irae eee


level 1 RADING oy Ouiet |See ely Sc
(main call) RET_ADDR| Maia fo
t
TOP

Enter Step 1: CONVERT(4,6) 153 25


level 2 POUR OSS GO eee (|
(Ist recursive Slep oh [tow |
call)
t
TOP

Enter Step 1: TRUNC(NUMBER, 153 25


level 3 RADIX) < 0 Biren he Be
(2nd recursive Step 2
call)
t
TOP
Return to Step 2: ANSWER + '! 0 '4! 153 25 f. Bend
level 2 Step 3: Return(ANSWER) [Bye a |tOoe Re lee eee
Stepa!he cae
t
TOP
Return to Step 2: ANSWER + ‘4! 0 ‘1! 153
level 1 Step 3: Return(ANSWER) emit rar
[Mains et]
t
TOP

Return to Step 2: ANSWER + /41/ 0 '3!


main Step 3: Return(ANSWER)

8a) Function CHANGE(INT). This recursive function changes the given


integer into its character string representation according to the method
outlined. STR is a string variable that holds the result.

1. [Has leftmost digit been reached?]


If INT > 10
then STR — CHANGE(INT/10) (integer divided to remove rightmost digit)
else STR+!!
2. [Base condition]
STR + STR © SUB(!0123456789',MOD(INT,10) + 1,1)
3. [Finished]
Return(STR)

b)
Level Number Description

Enter Step 1: STR + CHANGE ices ee


level 1 (INT /10) RET_ADDR [Main | |
(main call)
t
TOP

Enter Step 1: STR + CHANGE {10541|1054 |


_
level 2 (INT /10) Main Step 2 ce]
(1st
recursive _
call) TOP

Enter Step 1: STR — CHANGE 10541


level 3 (INT/10) Main |Step2'[Step2[|
(2nd
recursive t
call) TOP
Enter Step 1: STR + CHANGE 0541
level 4 (INT/10) Main | Step2
E| Step2
(3rd
recursive t
call) TOP

Enter Step 2: STR +"! 0/1! 4


S on 10 1
level 5 ain
FE Step 2 | Step 2 | Step 2
(4th
recursive
call) 4 Oovu

Return to Step 3: Return(STR) So 54 _ S an


level 4 =i
FE fain : ep 2 ep2
t+1O
F

t
TOP

Return to Step 2: STR + '1' 0 /0! 0541


_ _ S on

level 3 Step 3: Return(STR) fain two

|pPy° eyeo
y-
Return to Step 2: STR + '10' 0 /5!
level 2 Step 3: Return(STR)

Return to Step 2: STR -— '105! 0 '4!


level 1 Step 3: Return(STR)

Return to Step 2: STR + /1054! 0 ‘1!


main Step 3: Return(STR)

Function CONVERT(FRACTION,BASE,N). This recursive function


converts a decimal fraction into another base by the process of repeated
multiplication as specified in the text. RESULT is a string variable which
holds the resulting fraction. N indicates the number of significant digits.

1. [Base condition]
If N=0
then Return('.’)
De [Recursive cal]]
RESULT — CONVERT(FRACTION,BASE,N-1)
3. [Perform computation]
TEMP + FRACTION «+ FRACTION * BASE
FRACTION + MOD(FRACTION,1)
TEMP ~— TEMP - FRACTION
S216
4. [Convert digit to character]
RESULT «+ RESULT © SUB('0123456789',TEMP + 1,1)
5. [Return result]
RETURN(RESULT)

10) program poly(input,output);

{ This program invokes a recursive procedure in evaluating N-degree


polynomials in x. }

var n,x:integer;

DEBE BEE BEBE EEE EAE BEE GEER EEE HDDS SAH BE EEE BE GE #4}

function eval(n,x:integer):integer;

var a,result:integer;

begin
{ apply recursive definition }
ifn = 0
then begin
readIn(a);
eval :=a
end
else begin
read(a);
result := (x * eval{n—1,x)) + a;
eval := result
end
end;

(EHH R EER EEE EEE EEE BEEBE OEE EE EEE CECE CEE AEE 4 44}

begin
{ engage loop to process all data }
while not eof do
begin
read(n,x);
ifn <0
then writeln(/ERROR: NEGATIVE VALUE FOR POLYNOMIAL!)
else writeln(/POLY EVALUATED AT /:18,x:2,! = ':3,eval(n,x):4)
end
end.
POLY EVALUATED AT 2= 27

11) program expr(input,output);

{ Consider the set of all valid, completely parenthesized, infix arithmetic


expressions consisting of single-letter variable names, nonnegative integers,
and the four operators +,—,/,*. This program recursively scans an input string
of symbols and outputs ‘VALID EXPRESSION’ if the string is a valid infix
expression; ‘INVALID EXPRESSION! otherwise. }

type string = packed array[1..80] of char;

var i:integer;
next,expression:string;

a ladle lalate deel |

#include 'length.i';
#include 'index.i’;
#include 'sub.i';
#include 'verify.i';
#include 'getline.i’;
GER EBB EACH ORES SES SABE OBESE EEE AAAS AAAI TATE IA AAT }

function nextsym:string;

{ This function returns the next unexamined nonblank character from the
global input string of symbols. When all characters have been examined, a
blank is returned. }

var temp:string;
result:string;

begin
{ initializations }
result[2] := '|!;
{ check for end of input string }
ifi = length(expression)
then result[1] :=‘''
else begin
{ pass over blanks }
sub(expression,i + 1,length(expression),temp);
{ check for end of input string }
if verify(temp,’ |’) = 0
then result[1] :=‘ ’
else begin

5720
{ isolate next symbol }
i := i + verify(temp,’ |’);
result({1] := expression{i]
end
end;

nextsyi := result
end;

Scedcicetcinedcindi ine lacialninlaiatealaetaaedaeataceaaeaa

function eval:boolean;

{ This function evaluates the infix expression, returning true if valid; false
otherwise. }

var next:string;

begin
{ remove next symbol }
next := nextsym;
{ evaluate expression }
if next/1] = ‘(' ;
then if (not eval) or (index('+—*/|' nextsym)=0) or (not eval)
then eval := false
else begin
next := nextsym;
if next(1] =‘)
then eval := true
else eval := false;
end
else if index('ABCDEF GHI JKLMNOPQRSTUV WXY 20123456789" next) =
then eval := false
else eval := true
end;

DARE EBB BESS SSBB EEA EBB EEE GCE CSCSE


SECA B
HEH aEEE inet}

begin
{ engage loop to process all data }
while not eof do
begin
{ read expression }
getline(expression);
write(expression:length(expression),’ ':2);

Stal
{ evaluate validity of expression }
1 :=.0;
if (eval)
then begin
next := nextsym;
if next(1] = //
then writeln(' VALID EXPRESSION’
:18)
else writeln('INVALID EXPRESSION’
:20)
end
else writeln(/ INVALID EXPRESSION’)
end
end.

J-(4/(A*((3+N)-(8/E)))))) VALID EXPRESSION


Soie B+C) | INVALID EXPRESSION
A VALID EXPRESSION
) INVALID EXPRESSION
A*B)-C)+((9*D)/(8*F))) | VALID EXPRESSION
12) program sqroot(input,output);

{ This program recursively computes the square root of a number. }

var n:integer;
a,e:real;

EBB ABBE EEE E EAE E CECB ABOBBIE CS ACE CEES CECE EEE KE ++}

function root(n:integer;a,e:real):real;

begin
{ apply recursive definition }
if abs(a
* a—n) <e
then root := a
else root := root(n,(a * a + n)/(2 * a),e)
end;

DEBE E ESSE EO CHEE HAC HEE CHEE BA ES GEAR yi kts +}

;
begin
{ engage loop to process all data }
while not eof do
begin
{ read data }

B22
readIn(n,a,e);
{ check for valid data }
if (n < 0) or (a< 0) or (e < 0)
then writeln(/ERROR IN DATA! :15,n:3,a:3:3,e:3:3)
else writeln('SQ ROOT WITHIN /:15,e:3:3,’ = ':3,root(n,a,e):3:3)
end
end.

SQ ROOT WITHIN 0.001 = 1.414


SQ ROOT WITHIN 0.001 = 1.732
SQ ROOT WITHIN 0.001 = 2.829
SQ ROOT WITHIN 0.001 = 15.000

13) program permut(input,output);

{ Given a set of symbols in the form of a character string, all possible


permutations of these symbols are printed out. }

type string = packed array|1..80] of char;

var data:string;

FEBSBEEE ESSE EEASES ESSA EAS OBOE IEEEAE FOS ASABE EE Ea}

#include 'length.i’;
#include ‘sub.i’;
#include ‘concat.i';
#include 'getline.i';
GABE BEERS B EGE EES EEE ESSE IEEE IARI I TATE AAAA AIS]

procedure perm(sofar,rest:string);

{ This procedure forms the permutations of the input string recursively. }

var |,i:integer;
templ,temp2,temp3,temp4:string;

begin
{ check for string of one character }
1 := length(rest);
ifl!=—1
then begin
concat(sofar,rest,temp1);
writeln(temp1:length(temp
1))
end

3723
else begin
{ recursive calls }
sub(rest,1,1,temp 1);
concat(sofar,temp1,temp2);
sub(rest,2,length(rest),temp1);
perm(temp2,temp1);
for i := 2to!—1do
begin
sub(rest,i,1,temp!);
concat(sofar,temp1,temp2);
sub(rest,1,i — 1,temp3);
sub(rest,i + 1,length(rest), temp4);
concat(temp3,temp4,temp
1);
perm(temp2,temp1)
end;
sub(rest,1,1,temp1);
concai(sofar,temp1l,temp2);
sub(rest,1,1- 1,temp1);
perm(temp2,temp1)
end
end;

GABE SHEE EER SOS OBESE IEEE AHORA TATA AAAS }

begin
{ engage loop to process all data }
while not eof do
begin
getline(data);
writeln(/ PERMUTATIONS OF: ‘ data:length(data));
perm(' |data)
end
end.

PERMUTATIONS OF: 1234


1234
1243
1324
1342
1423
1432
2134
2143
2314

3-24
2341
2413
2431
3124
3142
3214
3241
3412
3421
4123
4132
4213
4231
4312
4321

14) program numsum(input,output);

{ This program determines the number of different partitions for given


integers as read from data. By a partition we mean a way in which an integer
can be expressed as the sum of other positive integers. }

var int:integer;

(ABS B SEAS Ba HE ABE ESB AGEEG HE naa Boa aan Et 6)

function q(m,n:integer):integer;

{ This function recursively determines the partitions. }

var temp:integer;

begin
{ apply recursive definition }
if (m= 1) or (n = 1)
then temp := 1
else ifm <n
then temp := q(m,m)
else if m =n
then temp := 1 + q(m,m-1)
else temp := q(m,n-1) + q(m-n,n);
{ return }
q := temp
end;

3525
Saladin lahacidediedaclaclatiedi diclei dada: Iaiatadacacetiedaddiadiedancadedaedtdedcecttecteietndieiniicaiedeiniaiaiaiad |

begin
{ process all data }
while not eof do
begin
readIn(int);
writeln(q(int,int),’ PARTITIONS FOR', int)
end
end.

3 PARTITIONS FOR 3
5 PARTITIONS FOR. 4
7 - PARTITIONS FOR ..-9
11 PARTITIONS FOR 6

EXERCISES SECTION 2-5.2 PAGE 213

1) program rpolish(input,output);

{ This program recursively scans an input string of symbols and outputs


‘VALID EXPRESSION’ if the string is a well-formed reverse Polish
expression; ‘INVALID EXPRESSION! otherwise. Valid symbols are single
letter variables, digits, and the four basic arithmetic operators - interspersed
blanks are allowed. }

type string = packed array(1..80] of char;

var expression:string;
next:char;
isinteger;

JAAS ESSEC HEE HSA EA ESA EGE Eda bee tee tt}

#include 'length.i’;
#-include 'index.i';
#include 'verify.i';
#include 'getline.i’;
GABE EEE EEE EEE EE IEEEEE EAE AAAI REAR EATS TAS FASTA EASES }

function expr:boolean;

3-26
var temp:string;

begin
ifi <= 6
then expr := false { missing subexpression }
else begin
next :== expression{i]; { get next symbel }
b= 1—
if next =="?
then expr := expr { ignore blanks }
else begin
temp{1] := next;
temp|[2] :-='|';
if index('+—*/|',temp) <> 0
then if (expr) and (expr)
then expr := true
else expr := false
else if index('ABCDEF GHIJKLMNOPQRSTUVW
XYZ0123456789' temp) <> 0
then expr := true
else expr := false
end
end
end;

FEE SRSA EE SSE EEE AEE IIE IIIA EE EE RICEEEE IEEE EES }

begin
{ process al! data }
while not eof do
begin
getline(expression);
write(expression:length(expression));
i := length(expression);
if (expr) and (verify(expression,’ |!) = i + 1)
then writeln(’ VALID EXPRESSION’)
else writeln(' INVALID EXPRESSION’)
end
end.

AB+C+D+E* VALID EXPRESSION


ABC+-—AB/* VALID EXPRESSION
A+BC+-AB/#C+ INVALID EXPRESSION
ABCD+-/EFG*+-H+I-J/K* VALID EXPRESSION
to

PRECEDENCE
SYMBOL INPUT PRECEDENCE STACK PRECEDENCE RANK
FUNCTION f FUNCTION g FUNCTION r
— if 2 -l
+,- 3 4 -l
*,/ 5 6 -1
6 8 2 0
t 10 9 =i
variables 1l 12 1
( 13 0 -
0 = 7"

Let the unary minus operator be denoted by @. Recognition of the unary


minus has been discussed, so we introduce the following step, to be inserted
into algorithm REVPOL to handle this new capability.

3.5 [Unary minus?}


If NEXT = '~! and (S[TOP] = '(! or S[TOP] = '')
then NEXT < @

Note that it is not necessary to consider the case of a minus sign


indicating the sign of a constant. This is detected by the scanner in
compilation; a negative constant is stored instead.
Note, also, that the introduction of the assignment operator is not
accompanied by adequate error detecting capabilities. Though the (modified)
algorithm REVPOL correctly converts valid infix assignment statements, there
exists invalid or nonsensical expressions which would be converted without
detection. Examples include:

A+BeC
(A + B) /12

The algorithm REVPOL, as now modified, cannot differentiate between an


expression or an assigninent statement.

3) PRECEDENCE
SYMBOL INPUT PRECEDENCE STACK PRECEDENCE RANK
FUNCTION f FUNCTION g FUNCTION r
| 1 2 -1
& 3 4 -l
a 6 5 0

8 -l
<,<,>,2,=,4 7
+,- 9 10 -1
*,/ 11 12 =}
9 14 13 0
t 16 15 ay
variables 17 18 1
19 0 :
0 - :

3-28
A| B= C([D 40 ABC=|Do|
A<B&7A(C|6TQ<Q/V) AB<C6QTQV/<|7&
A&B&(AC)=ARZBEAC AB&Cr&
Algorithm PREFIX. Given an input string, INFIX containing an infix
expression which has been padded on the right with ‘)’, this algorithm creates
the equivalent prefix expression. Two string stacks are used: S1, indexed by
TOP1, which contains the operators; and S2, indexed by TOP2, which
contains the intermediate operands. OP contains the current operator being
removed from the operator stack. LEFT and RIGHT contain the left and
right operands of the current operator respectively. Algorithms PUSH, POP,
and NEXTCHAR (as described in the text) are invoked. Precedence functions
are given below.

SYMBOL INPUT PRECEDENCE STACK PRECEDENCE


oe FUNCTION f FUNCTION g
+,- 2 3
*,/ 4 5
variables 6 -
( 7 0

1. [Initializations]
VALID + true
TOPI1+ 1
Si[TOP]] — '(!
TOP2 + 0
2. [Get first input symbol]
NEXT + NEXTCHAR(INFIX)
3. [Scan expression]
Repeat thru step 4 while (NEXT > '') and VALID
4. [Logical end of expression?
If TORT = G6
then VALID + false
else If (NEXT) = 6 (operand?)
then Call PUSH(S2,TOP2,NEXT)
else Repeat while (f((NEXT) < g(S1[TOP1])) and VALID
If TOP2 <1
then VALID + false
else OP + POP(S1,TOP1)
RIGHT ~ POP(S2,TOP2)
LEFT — POP(S2,TOP2)
Call PUSH(S2,TOP2,OP © LEFT o RIGHT)
If NEXT = '}
then TOP1< TOP1-1

a20
else Call PUSH(S1,TOP1,NEXT)
NEXT + NEXTCHAR(INFIX)
5. [Valid expression?]
If VALID and (TOP1 = 0) and (TOP2 = 1)
then Write(/VALID EXPRESSION’)
else Write(‘INVALID EXPRESSION’)

Note that it is possible to incorporate a rank function to check for valid


expressions rather than checking for empty stacks.

5) program driver(input, output);

{ This program translates suffix expression into assembly language. }

type string = packed array[1..80] of char;


stack = array([1..100] of string;

var polish:string;
s:stack;
top:integer;

CABBIE EEE EES BE EEO SSSA EEE EEE ABE EE EAE EAA ES }

#include ‘length.i';
#include 'getline.i';
#include 'concat.i';
GABE EEE ESSE EE EBSA G ABABA EEE EE EE EEA A AA TAA TIE}

procedure push(var s:stack;var top:integer;x:string);

{ This procedure pushes x onto stack s. }

begin |
{ check for stack overflow }
if top >= 100
then writeln(/STACK OVERFLOW’)
else begin
{ increment top and insert x }
top := top + 1;
s[top] := x
end
end;

GER EG OBE HOHSS EOEES OHA B REESE EBA BEASE AAA IAAI }

3-30
function pop(var s:stack;var top:integer):string;

{ This function returns the top element of stack s. }

begin
{ check for stack underflow }
if top = 0
then writeln(/STACK UNDERFLOW’)
else begin
{ decrement top and return element }
pop <= s|top];
top := top — l
end
end;

Saadallah adalat |

procedure assemblycode(polish:string);

{ This procedure generates assembly code for the given polish string. For
simplicity, it is assumed that there will be a maximum of nine
temporary holders in order that the built-in chr function may be used. }
var top,i,j:integer;
next,right, left, first,second,third,temp,chari,opcode:string;

begin
{ initializations }
top := 0;
bi "0;
{ scan expression }
for j := 1 to length(polish) do
begin
next[1] := polish{j];
next[2] :=—= ‘';
if (‘A’ <= next[1]) and (next[1] <= 'Z')
then push(s,top,next)
else begin
case next|1] of
‘+! opcode == "ADD: |!
‘1: opcode := 'SUB |};
‘+!: opcode := 'MUL |;
'/': opcode := 'DIV|
end;
right := pop(s,top);
left := pop(s,top);

Bra
concat(/LOD |! left,first);
concat(opcode,
right second);
writeln(first:length(first));
writeln(second:length(second));
1:=i+ 1;
chari[1] := chr(i + ord('0’));
chari{2| := '|!;
concat('T|' ,chari,temp);
concat('STO |!,temp, third);
writeln(third:length(third));
push(s,top,temp)
end
end
end;

FEES E EOE CE ESO BOEE EOE OE SHORES AES OBEOS ESB EB AEH EEE +}

begin
{ initialize stack }
top := 0;
{ engage loop to process all data }
while not eof do
begin
{ read expression }
getline(polish);
writeln;
writeln(polish:length(polish));
{ call proc to generate assembly code }
assembly code(polish)
end
end.

ABCDEF+-—/*+

LOD E
ADD F
SLO Pl
LOD D
SUB T1
STO-T2
LOD C

a9
DIV T2
STO T3
LOD B
MUL T3
STO T4
LOD A
ADD T4
S bOMio

AB+CD/-
LOD A
ADD B
STO Ti
LOD C
DIV D
STO T2
LOD T1
SUB T2
STO T3
6) Algorithm ASSEMBLY_CODE. Given a string, POLISH, as previously
discussed, this algorithm generates assembly language instructions, taking
advantage of the commutativity of operator * and +. #£xThe
COMMUTATIVITY flag is set when applicable to indicate the omission of
redundant code. All other variables are as discussed previously.

1. [Initializations]
TOP +I+0O
COMMUTATIVITY << false
2. [Process all symbols]
Repeat thru step 4 for J = 1, 2, .... LENGTH(POLISH)
3. [Obtain current input symbol]
NEXT + SUB(POLISH,J,1)
4. [Determine type of symbol]
IAG < NEXT and NEXT: < $7?
then Call PUSH(S,TOP,NEXT) (push variable on stack)
else Select case (NEXT)
Case '+!:
OPCODE «+ ‘ADD !
Case pen
OPCODE + ‘SUB!
Case '*!:
OPCODE + MUL !
Case !/':
OPCODE + ‘DIV!
Doe
RIGHT + POP(S,TOP) (unstack two operands)
LEFT — POP(S,TOP)
NEXT =" /"or NEXT =!
then If COMMUTATIVITY
then COMMUTATIVITY + false
Write('STO' © LEFT)
Write((LOD ! © LEFT) (output load instruction)
Write(OPCODE © RIGHT) (output arithmetic instruction)
I-I+1 .
TEMP + 'T! oI
Write(/STO ‘ © TEMP) (output temporary storage)
Call PUSH(S,TOP, TEMP)
else If COMMUTATIVITY
then Write(OPCODE © RIGHT)
else Write(/LOD‘ 0 LEFT)
Write(OPCODE © RIGHT)
COMMUTATIVITY << true
I+I+4+1
TEMP + 'T! 0 I
Call PUSH(S,TOP, TEMP)
5. [Output storage if necessary]
If COMMUTATIVITY
then TEMP «'T’ 0]
Write(/STO! 0 TEMP)
6. [Finished] :
Exit

7) program driver(input,output);

{ This program translates suffix expression into assembly language taking


advantage of the commutativity of the operators + and *. }

type string = packed array[1..80] of char;


stack = array[1..100] of string;

var polish:string;
s:stack;
top:integer;

(EEE EEEEEEEEE EE EEEEEEEEEE OEE EEE AIR IIIT IIE A IA AIA ATES

#include ‘length.i’;
#include 'getline.i’;
#include ‘concat.i';
GE EEEAREA E EERE EE ESSE EEE CEE EEE ASIA ITAA IAAAI IAAF

3-34
procedure push(var s:stack;var top:integer;x:string);

{ This procedure pushes x onto stack s. }

begin
{ check for stack overflow }
if top >= 100
then writeln(/STACK OVERFLOW’)
else begin
{ increment top and insert x }
top := top + 1;
s[top] := x
end
end;

FEBS EESSE SESE IE SEO ESSS ESAS EOE EAE AEB AREA tote }

function pop(var s:stack;var top:integer):string;

{ This function returns the top element of stack s. }

begin
{ check for stack underflow }
if top = 0
then writeln(/STACK UNDERFLOW’)
else begin
{ decrement top and return element }
pop := s[top];
top := top -1
end
end;

GABBER ERE R SESS EE EE EOE COA EEE COOH SAECO nn Er}

procedure assemblycode(polish:string);

{ This procedure generates assembly code for the given polish string. For
simplicity, it is assumed that there will be a maximum of 9 temporary holders,
in order that the built-in chr function may be used. }
var top,i,j:integer;
next,right,left, first,second, third ,temp,chari,opcode:string;
commutativity :boolean;
begin
{ initializations }
top := 0;

355
p= 0;
commutativity := false;
{ scan expression } )
for j := 1 to length(polish) do.
begin
next[1] := polish{j];
next[2] c= “|;
if ('A’ <= next/1]) and (next[1] <= '2’)
then push(s,top,next)
else begin
case next[1] of
'4!: opcode := ‘ADD |;
!_!. opcode := ‘SUB |;
'x!: opcode := ‘MUL |;
'/': opcode := 'DIV |!
end;
right := pop(s,top);
left := pop(s,top);
if (next{1] = '/') or (next[1] = ‘-')
then begin
if commutativity
then begin
commutativity := false;
concat('STO |’ left, first);
writein(first,length(first))
end;
concat(/LOD |’ left, first);
concat(opcode,right,second);
writeln(first:length(first));
writeln(second:length(second))};
j= 1-1;
chari[1] := chr(i + ord(‘0’));
chari[2] := “|!
concat('T|' ,chari,temp);
concat(/STO |temp,third);
writeln(third:length(third));
push(s,top,temp)
end
else begin
if commutativity
then begin
concat(opcode,
right, first);
writeln(first:length(first))
end
else begin

3-36
concat(/LOD | left, first);
concat(opcode,right,second);
writeln(first:length(first));
writeln(second:length(second));
commutativity := true;
Leslie
end;
chari[1] := chr{i + ord('0’));
chari[2] :==-"|/;
concat(! T|’ chari,temp);
push(s,top,temp);
end
end
end;
if commutativity
then begin
chari[1] := chr(i + ord(’0’));
chari[2] := ‘|’;
concat('T|’ chari,temp);
concat('STO |’ ,temp,third);
writeln(third:length(third))
end
end;

GAB ESSE OEE SESE ESE nOBo EES a abo aaa nSrb Rrarab EEL

begin
{ initialize stack }
top := 0;
{ engage loop to process all data }
while not eof do
begin
{ read expression }
getline(polish);
writeln;
writeln(polish:length(polish));
{ call proc to generate assembly code }
assembly code(polish)
end
end.

3238
BC*¥A+
LOD B
MUL C
ADD A
STO Tl

BC*A+D*
LOD B
MUL C
ADD A
MUL D
Seoul s

8) The following modification to algorithm ASSEMBLY_ CODE in exercise 6 is


sufficient to incorporate the assignment operator.

4, [Determine type of symbol]


if 2 A°< NEXT and NEXT "2!
then Call PUSH(S,TOP,NEXT)
else If NEXT = /’
then TEMP + POP(S,TOP)
Write(/STO' © TEMP)
else Select case (NEXT)

9) The following modifications are necessary to generate code for the six
relational operators:

else Select case (NEXT)


Case !-+!: OPCODE + /ADD !
Case '—! OPCODE + 'SUB!
Case '*!: OPCODE + ‘MUL !
Case !/!: OPCODE + 'DIV!
Case !=!: OPCODE + ‘EQ '
Case ae OPCODE + 'NEQ'
Case '>": OPCODE + 'GTE '
Case !<!: OPCODE + 'LTE!
Case '>!: OPCODE + 'GT !
Case 1! OPCODE <—'LT !
i NEXT = ‘Tf! or NEXT = ‘/— or NEXT = '<'
or NEXT = ued or <GNEXT i= or !>!

3-38
then

else

In order to generate code for the six relational operators, we have created 6
more machine instructions. Zero denotes false; anything else (usually one)
denotes true.

EQ a If the value in the accumulator equals contents of ‘a’ then the value
of the accumulator is changed to 1; otherwise it is changed to 0.
NEQ a_ If the value in the accumulator is not equal to contents of ‘a’ then
the value in the accumulator is changed to 1; otherwise to 0.
LT 2a If accumulator < ‘a! then ...
GT a If accumulator > ‘a! then ...
LTE a _ If accumulator < ‘a’ then ...
GTE a__siIf accumulator > ‘a! then ...

In the above operations, the value of ‘a’ is not changed. It is a simple


extension to generate code for the logical operators. Consider the following
operator definitions for the symbols &, |, and 7:

AND a_ If ‘a’ = 0 then accumulator is set to 0.


OR a leat Sie 0 then accumulator is set to 1.
NOT If accumulator oe 0 then accumulator is set to 0; otherwise it is set
tomls

10) Modifications necessary to handle the unary minus operator:

4. [Determine type of symbol]


If (At NEXT and NEXT 27)
then Call PUSH(S,TOP,NEXT)
else If NEXT = '@
then RIGHT + POP(S,TOP)
Write(/LOD' 0 RIGHT)
Write('NEG‘ © RIGHT)
Betta
TEMP + 'T’ o ]
Write(/STO! 0 TEMP)
else Select case (NEXT)

3-39
11) An unconditional statement, for our restricted language is a simple assignment
statement as previously discussed. The infix expression is translated to reverse
polish and code can be easily generated by algorithm ASSEMBLY_CODE.
Let us now consider a conditional statment. It has the form If.
<condition> then <statement> where the <condition> or the
<statement> can be simple, compound, or arbitrarily complex. This
statement can be translated, (via algorithm REVPOL with minor
modification) to the reverse polish form <suffix form of condition> ? <suffix
form of statement>. As an example, If A<B & C=D | A>B & CSD then
A =At (A+B - 1) would be translated aa AB<CD=&£AB>CDS
& |? ABAB+1-f +. Code generation from this form is solved in
exercise 9 of this section, with the exception of the '? operator. It generates a
conditional branch instruction to a strategically placed table. We demonstrate
this by using our example once more:

LOD A
LTB
evaluate condition SPorrt
LOD C
EQ D

if accumulator = 0 BOZ 0
then branch to labeled
statement
perform statement LOD A
ADD B

next statment er:

BOZ is mnemonic for ‘branch on zero’. This method is just one


implementation of conditional and unconditional statements in a reverse-
Polish framework.

12) Algorithm CONPREFIX. Given an input string, PREFIX, consisting of a


prefix Polish assignment statement, this algorithm generates assembly code for
that statement. Integer I is used as a cursor index into the string. String
NEXT holds the next non-blank character in the string.

1. [Initializations]
EceuQ
Call SCAN(I,NEXT)
2. [Remove identifier, and call function to generate term code]
If IDENT(IDENTIFIER) (call function to isolate identifier)
then If TERM('LOD ') (call function to generate code)
then Write('STO! 0 IDENTIFIER)
3-40
else Write(/INVALID TERM’)
else Write(/INVALID IDENTIFIER’)
3. [Finished]
Exit

Procedure SCAN(I,NEXT). This procedure scans through the input text


string until it reaches the first non-blank character after position I. I] is then
set to point at that character and NEXT is assigned the value of the
character.

1. [Scan line of text]


I+I+1
Repeat while PREFIX[{I] = 'p!
I+I+1
2. [Set NEXT]
NEXT « SUB(PREFIX,],1)
3. [Finished]
Return

Function IDENT(IDENTIFIER). This procedure isolates an identifier


and returns true if it is found to be valid; otherwise false.

1. [Scan through all non-blank characters]


CHECK + true
IDENTIFIER + !!
Repeat while NEXT '}! and CHECK
If INDEX(' ABCDEF GHIJKLMNOPQRSTUVWXYZ0123456789' ,
NEXT) = 0
then CHECK <false
else
IDENTIFIER «+ IDENTIFIER 9° NEXT
I+-I+1
NEXT + SUB(PREFIX,],1)
2. [Return appropriate value]
If CHECK
then Call SCAN(I,NEXT)
Return(true)
else Return(false)

Function TERM(OPCODE). This function generates assembly code for


the term of the given prefix Polish assignment statement, returning true if the
entry is found to be valid, false otherwise.

Se
1. [Initializations]
Call SCAN(I,NEXT)
2. [Check for identifier]
If IDENT(IDENTIFIER)
then Write(OPCODE © IDENTIFIER)
Return(true)
3. [Check for operator]
If INDEX(!+-*/!, NEXT) = 0
then Return(false)
4, [Determine opcode]
Select Case (NEXT)
Case !-+!:
OPCODE « ‘ADD!
Case {.!*
OPCODE + SUB!
Case ys
OPCODE + ‘MUL '
Case '/!
OPCODE + 'DIV!
5. [Scan to next non-blank character]
Call SCAN(I,NEXT)
6. [Check for terms]
If TERM('LOD ‘)
then If TERM(OPCODE)
then Return(true)
else Return(false)
else Return(false)

EXERCISES SECTION 3-6 PAGE 222

1,3a Procedure DQINSERT(F,R,DQ,Y,FRONT,REAR). Given values for


pointers F and R which denote the front and rear elements of a deque, a
vector DQ consisting of N elements, this algorithm inserts element Y to the
front or rear of the deque depending on how the boolean valued variables
REAR and FRONT have been set. If insertions are allowed on both ends at
the same time, priority is given to insertion in the front.

1. [Insertion to front?]
If FRONT and F 4 1
then IfF =O
rep iahoe R= I
else F—F-1
3-42
DQ[F] — Y
Return
2. [Insertion to rear?|
If REAR and R 4 N
then IfFf =O
then fi)
else: ER Reral
DQ|R] — Y
Return
3. [Insertion disallowed]
Write(/DEQUE OVERFLOW’)
Return

2,3b) Function DQDELETE(F,R,DQ,N,FRONT,REAR). This function


deletes and returns an element from the given deque. All variables are as
discussed above in exercise 1.

1. [Check for underflow]


IfF =0
then Write(/DEQUE UNDERFLOW’)
Return(0) (0 denotes underflow)
2. [Delete from front?|
If FRONT
then Y + DQIF]
tR=F+1
then F+R<0O
else F+F+1
Return(Y)
3. [Delete from rear?|
If REAR
then Y + DQ[R]
IffF=R-1
then oP A= 0
else R+R-1
Return(Y)
4. [Deletion disallowed]
Write(/DELETION DISALLOWED’)
Return(0)

By calling these algorithms with the appropriate values for the arguments
FRONT and REAR, it is possible to:
i. disallow all insertions/deletions
ii. allow insertions/deletions only at front
iii. allow insertions/deletions only at rear
iv. allow insertions/deletions at either front or rear
3eh3
4) initially
after insert l| ~

after delete I
after delete | I|
after insert ~

after delete yy 0 Dum


yyy rm mw LD
CONDO WLW
Ww
Ph
me
W

qn

Procedure REVERSE(F,R,Q,N). Given a queue, Q, front and rear
pointers to its elements, F and R, and N, the size of the vector, this procedure
reverses the order of the elements in the queue. S denotes a stack with its
associated index, TOP.

1. [Delete all the elements and place on stack]


TOP + 0
Repeat while F a 0
X— QIF]
IfF=R
then F+R+0O
else IfF =N
then F+ 1
else) FF 7
Call PUSH(S,TOP,X)
2. [Unstack elements and insert into queue]
Repeat while stack not empty
X + POP(S,TOP)
R+R+1 (should not wrap around or overflow)
QIR| —X
IfF =0
then F+-1
3. [Finished]
Return

EXERCISES SECTION 3-8 PAGE 242

1) Procedure PQINSERT(P,Y). This procedure inserts element Y with


priority P into the priority queue.

1. [Check for overflow]


If PRIORITY_R[P] > LENGTH(P)
then Write(/PRIORITY ',P,/ QUEUE OVERFLOW’)
Return
2. [Increment rear pointer]
PRIORITY_R[P] — PRIORITY_R[P] + 1
3-4
3. [Insert element]
Q|P,PRIORITY_R[P]] — Y
4. [Check front pointer]
If PRIORITY_F[P] = 0
then PRIORITY_R[P] + 1
5. [Finished]
Return

Function PQDELETE(P). This procedure deletes and returns an element


from the queue with priority P.

1. [Check for underflow]


If PRIORITY_F|P] = 0
then Write(/PRIORITY ',P,’ QUEUE UNDERFLOW’')
Return(0)
2. [Delete element]
Y + Q[P,PRIORITY_FIP]]
3. [Empty queue]
If PRIORITY_F[P] = PRIORITY_R[P]
then PRIORITY_F|P] + PRIORITY_R[P] — 0
else PRIORITY_F[P] + PRIORITY_F|P] + 1
4, [Return element]
Return(Y)

2) Procedure Q_INS_I(I,Y). This procedure inserts element Y into queue I.

1. [Check for possible overflow]


If RI] > F[I+4]
then (try to move upward)
FOUND + false
Repeat for J = I+1, I+2, ..., N while AFOUND
If R{J] < F{J + ]]
then FOUND < true
SAVE <— J
If FOUND
then Repeat for J = SAVE, SAVE - 1,:..,14+1
Repeat for M = RIJ], R[J] — 1, ... F[J]
QIM +1] — QiM
RJ] — RJ] +1
F[J] + F[J] +1
else (try to move downward)

3-45
FOUND + false
Repeat for J = 1I-1,I-2,..., 1 while AFOUND
If R[J] < F[J + 1]
then FOUND <- true
SAVE + J
If FOUND
then Repeat for J = SAVE, SAVE + 1, ..., I
Repeat for M = F{J], F[J] + 1, ..., R[J]
Q[M - 1] = QiM]
R[J] — Ri] - 1
F{J] — F{J] -1
else (entire queue structure is full)
Write(‘STACK OVERFLOW’)
Return
~) [Increment rear pointer]
Ri — Ri] +1
[Insert element]
QIRIM]
—Y
[Check front pointer]
If F{l] = TRUNC(M/N) « (I- 1)
then F{I] — F[i] + 1
[Finished]
Return

Function Q DEL_I(I). This function deletes and returns an element from


queue I.

1. [Check for underflow]


If F[I] = TRUNC(M/N) ¢ (1-1)
then Write(/'QUEUE ',I,, UNDERFLOW’)
Return(0)
[Delete element]
Y ~ OF
[Empty queue?]
If F[I] = R{l]
then Fil] — R[I] — TRUNC(M/N) « (I-1)
else F{I] + Fil] + 1
[Return element]
Return(Y)

3-46
s ; as ,
g,(- e MD SE SES Oe ae e he
y — : , : f ithe? a wees Phe
ol atue Pegs reg
co. ta rid ait é ‘roe FRY +

’ ee, ©

se
. pore
ee oi
iwyieiale
‘ ae ks

het
CHAPTER 4

LINEAR DATA STRUCTURES AND THEIR


LINKED STORAGE REPRESENTATION
EXERCISES SECTION 4-2.1 PAGE 275

1) Function COUNT(FIRST). Given a linked list whose first node is given


by FIRST, this function returns the number of nodes in the list. TEMP is a
temporary pointer variable; I is an integer variable, used in counting the
nodes.

1. [Initializations]
TEMP «+ FIRST
ca
2. [Scan through list]
Repeat while TEMP ee NULL
P~I+1
TEMP <— LINK(TEMP)
3. [Finished]
Return(I)

2) Procedure CHANGE(FIRST,K,Y). Given a linked list, whose first node


is given by FIRST, this procedure changes the INFO field of the Kth node to
the value given by Y. TEMP is a temporary pointer variable.

1. [Valid K?|
IfkK <0
then ~\Write('INVALID Kk’)
Return
2. [Scan through list]
TEMP + FIRST
Repeat while K 54 1 and TEMP 54 NULL
K+K-1
TEMP + LINK(TEMP)
3. [Change info field if Kth node exists]
If TEMP = NULL
then Write(‘K TOO LARGE’)
else INFO(TEMP) + Y
4. [Finished]
Return

Ww Procedure INLEFT(FIRST,K,Y). Given a linked list whose first node is


given by FIRST, this procedure inserts a new node to the immediate left of
the Kth node in the list. The INFO field of the new node is given by the
variable Y. NEW and NEXT are pointer variables.
1. [Check for valid K]
ItK <0
then Write('INVALID Kk’) °
Return :
2. [Allocate new node]
NEW <— NODE
INFO(NEW) + Y
3. [Insertion at head of list?|
Ifk =1
then LINK(NEW) < FIRST
FIRST — NEW
Return
4. [Find node to left of Kth node]
NEXT + FIRST
Repeat while NEXT Oa NULL and K =f 2
NEXT + LINK(NEXT)
K+K-1
5. [Insert new node]
fhe 2
then LINK(NEW) < LINK(NEXT)
LINK(NEXT) + NEW
else Write(/K TOO LARGE’)
o> [Finished]
Return

4) Function APPEND(A,B). Given A and B, the addresses of the first nodes


of two linear linked lists, this function concatenates the lists and returns a
pointer to the new list. TEMP is a temporary pointer variable.

1. [Check for null lists]


If A = NULL
then Return(B)
If B = NULL
then Return(A)
2. [Find end of first list]
TEMP + A
Repeat while LINK(TEMP) 34 NULL
TEMP + LINK(TEMP)
3. [Reset last field in first list]
LINK(TEMP) + B
4, [Return pointer to new list]
Return(A)
SPLIT). Given a linked list whose first node
5) Procedure L_SPLIT(FIRST,
procedure deconcatenates the list into two linked
is given by FIRST, this
lists. The first element in the second linked list is given by SPLIT. TEMP is
a temporary pointer variable.

1. [Find node that links to SPLIT]


TEMP + FIRST
FOUND + false
Repeat while TEMP 54 NULL and -FOUND
If LINK(TEMP) = SPLIT
then FOUND + true
LINK(TEMP) «- NULL
else TEMP + LINK(TEMP)
2. [Check if no node was found]
If “FOUND
then Write(/NODE GIVEN BY SPLIT NOT CONTAINED IN LIST’)
SPLIT + NULL
3. [Finished]
Return

Procedure DELETE_BY_KEY(FIRST,KMIN,KMAX). Given a linked


list whose first node is given by FIRST, this procedure deletes all nodes whose
KEY value is greater than or equal to KMIN and less than or equal to KMAX.
The nodes in the list are in ascending order by the value of the KEY field.
SAVE and NEXT are temporary pointer variables.

1. [Check for null list]


If FIRST = NULL
then Return
2. [Find last node whose key value < KMIN|
NEXT + FIRST
SAVE + NULL
Repeat while LINK(NEXT) 54 NULL and KEY(NEXT) < KMIN
SAVE + NEXT
NEXT + LINK(NEXT)
3. [Check if no node found]
If KEY(NEXT) < KMIN
then Return
4. [Find first node whose key value > KMAX]
Repeat while LINK(NEXT) 4 NULL and KEY(NEXT) < KMAX
NEXT + LINK(NEXT)
5. [Reset link fields]
If KEY(NEXT) < KMAX
then NEXT + NULL

4-3
If SAVE = NULL
then FIRST — NEXT
else LINK(SAVE) + NEXT
6. [Finished]
Return

procedure delete(var first:pointer;k


min, kmax:integer);

{ This procedure deletes all nodes within the range such that kmin <= x
<= kmax. }

var next,save:pointer;

begin
{ check for empty list }
if first <> nil
then begin
{ find last node whose key value < kmin }
next := first;
save := nil;
while(nextf.link < >nil)and(nextt.key<kmin)do
begin
save := next;
next := nextf.link
end;
{ check if no node found }
if nextf.key >= kmin
then begin
{ find first node whose key value > kmax }
while (nextf.link <> nil) and (nextt.key <= kmax) do
next := nextf.link;
{ reset link fields }
if nextf.key < kmax
then next := nil;
if save = nil
then first := next
else savef.link := next
end
end
end;

4)
7) Algorithm COLLEGE_REPORT. This algorithm creates a linked list of
student records ordered by student number. The information fields in a
typical student record include STUDENT_NO, NAME, COL, SEX, YEAR.
The first node in the list is given by FIRST, and the link fields are referenced
as LINK. Within this linear list there is a smaller linked list for each college.
The college names are stored in the vector COLLEGE, and pointers to the
first node of each list are stored in the respective locations of the vector
COL_HEAD, and the link fields are referenced as COL_LINK. Each college
linked list is ordered alphabetically by student name. COL_CT hold the
number of colleges. Several subalgorithms are referenced: INSORD_BY_.NO
is used to maintain the linear list ordered by student number;
INSORD_BY_NAME is used to maintain the college lists; UPDATE_LIST is
responsible for reflecting the changes made in an update transaction and
OUTPUT_REPORT causes the display of all student records from a specified
college.

1. [Initializations]
FIRST — NULL
COL_CT + 0
2. [Create linked list in order]
Read(STUDENT#)
Repeat while STUDENT# 999999
NEW <— NODE
STUDENT_NO(NEW) + STUDENT#
Read(NAME(NEW),COL(NEW),SEX(NEW),
YEAR(NEW))
Call INSORD_BY_NO(NEW)
Call INSORD_BY_NAME(NEW)
Read(STUDENT#)
Read(DUMMY_NAME,DUMMY_COL,DUMMY_SEX,DUMMY_YR)
3. [Update linked list]
Read(STUDENT#)
Repeat while STUDENT# 999999
Read(NEW_COL,NEW_YR)
Call UPDATE_LIST(STUDENT#,NEW_COL,NEW_YR)
Read(STUDENT#)
Read(DUMMY_COL,DUMMY_YR)
4. [Output college reports]
Read(COL_NAME)
Repeat while not end of file
Call OUTPUT_REPORT(COL_NAME)
Read(COL_NAME)
5. [Finished]
Exit

4-5
Procedure INSORD_BY_NO(P). This procedure places the node given
by P in the appropriate location within the linked list ordered by student
number.

1. [Check for empty list]


If FIRST = NULL
then LINK(P) — NULL
FIRST +P
Return
2. [New node precedes first node?|
If STUDENT_NO(FIRST) > STUDENT_NO(P)
then LINK(P) — FIRST
FIRST «+ P
Return
3. [Search for predecessor of node]
SAVE + FIRST
FOUND + false
Repeat while LINK(SAVE) 4 NULL and -FOUND
If KEY(LINK(SAVE)) > KEY(P)
then FOUND + true
else SAVE « LINK(SAVE)
4. [Reset fields]
LINK(P) + LINK(SAVE)
LINK(SAVE) <— P
5. [Finished]
Return

Procedure INSORD_BY_NAME(P). This procedure inserts the node


given by P in the appropriate location of a linked list for students of the same
college.

1. [Isolate head of college list]


COLLEGE|COL_CT + 1] + COL(P)
It :
Repeat while COLLEGE|I] 4 COL(P)
Le T+
2. [New college?|
If 1 = COL_CT + 1
then COL_CT +I
COL_HEAD|I] + P
COL_LINK(P) — NULL
Return

4-6
[Empty college?|
TEMP + COL_HEAD|]]
If TEMP = NULL
then COL_HEAD|I] ~— P
COL_LINK(P) — NULL
Return
[New node precedes first node?|
If NAME(TEMP) > NAME(P)
then COL_HEAD|I] — P
COL_LINK(P) + TEMP
Return
[Search for predecessor in list]
FOUND + false
Repeat while COL_LINK(TEMP) +4 NULL and ~FOUND
If NAME(COL_LINK(TEMP)) > NAME(P)
then FOUND + true
else TEMP «+ COL_LINK(TEMP)
[Reset link fields]
COL_LINK(P) — COL_LINK(TEMP)
COL_LINK(TEMP) — P
[Finished]
Return

Procedure UPDATE_LIST(STUDENT#,NEW_COL,NEW_YR).
Given the student number of a record to be updated, and the updated values
for the COL and YEAR fields, this procedure implements those changes in the
record and the linked lists of the colleges.

[Isolate student record]


SAVE + FIRST
FOUND + false
Repeat while SAVE 54 NULL and ~FOUND
If STUDENT_NO(SAVE) > STUDENT#
then FOUND < true
else SAVE + LINK(SAVE)
[Node not found?|
If -FOUND
then Write(/RECORD NOT FOUND‘)
Return
If STUDENT_NO(SAVE) +4 STUDENT#
then Write(/RECORD NOT FOUND’)
Return
[Change information]
YEAR(SAVE) + NEW_YEAR

4-7
If COL(SAVE) = NEW_COL
then Return
[Find head of old college list].
Eat 4
Repeat while COLLEGE|I] 54 COL(SAVE)
Petia
[Remove from old college list]
If COL_HEAD|I] = SAVE
then COL_HEAD|I] — COL_LINK(SAVE)
else TEMP + COL_HEAD|I]
Repeat while COL_LINK(TEMP) oe SAVE
TEMP «+ COL_LINK(TEMP)
COL_LINK(TEMP) — COL_LINK(SAVE)
[Reset new college list links]
COL(SAVE) — COL_NAME
Call INSORD_BY_NAME(SAVE)
[Finished]
Return

Procedure OUTPUT_REPORT(COL_NAME). Given a college name,


COL_NAME, this procedure outputs all records of students in that college
alphabetically by student name.

1. [Initializations]
COLLEGE|COL_CT+1] — COL_NAME
I— 1
[Find head of college list]
Repeat while COLLEGE|I] 4 COL_NAME
I+I+1
[College not found?|
If l-= COL_CT + 1
then Write('0 STUDENTS IN COLLEGE/BAD COLLEGE NAME’)
Return
[Output title and students in college}
Write(COL_NAME)
SAVE + COL_HEAD|I]
Repeat while SAVE NULL
Write(NAME(SAVE),STUDENT_NO(SAVE),SEX(SAVE),
YEAR(SAVE))
SAVE + COL_LINK(SAVE)
[Finished]
Return

4-8
Procedure INSERT_LINES(BLINE). Given BLINE, the line number of
the line preceding the point of insertion, this procedure processes text
insertions into the array FREE_TEXT. LINENUM holds BLINE’s line
number; SAVE holds the following line’s number; INDEX holds the index of
BLINE in the array, and LINK holds the link of BLINE. Three functions are
invoked: CONVERTCHAR returns the character equivalent of a given integer;
CONVERTNUM returns the integer equivalent of a given character;
FINDINDEX returns the array index of the line with the given line number.
LASTLINE is a global variable which holds the index of the last line in the
array. MAXLINE is the largest index possible.

1. [Initializations|
LINENUM «+ CONVERTNUM(BLINE)
INDEX + FINDINDEX(BLINE)}
2. [Appending to end of text?|
LINK « SUB(FREE_TEXT|INDEX],6,5)
If LINK = '00000!
then SAVE + 0
else SAVE + CONVERTNUM(LINK)
SUB(FREE_TEXT|INDEX],6,5) CONVERTCHAR(LASTLINE + 1)
3. [Move inserted text into free text]
Repeat for I = 1, 2,..., 9 while there remains insertion text
LASTLINE + LASTLINE pit
SUB(FREE_TEXT|LASTLINE],1,5) —
CONVERTCHAR(10*INDEX + I)
SUB(FREE_TEXT|LASTLINE],6,5) —
CONVERTCHAR(LASTLINE + 1)
SUB(FREE_TEXT[LASTLINE],11,80) + next line of inserted text
4. [Set link field of last inserted line]
SUB(FREE_TEXT[LASTLINE],6,5) ~ CONVERTCHAR(SAVE)
5. [Check for incomplete insertion]
If not end of insertion text
then Write(/NO ROOM FOR FURTHER INSERTION’)
6. [Call proc to renumber text file]
Call RENUMBER
7. [Finished]
Return

Procedure RENUMBER. This procedure renumbers the lines of the array


FREE_TEXT to be 10 apart. PRESENT holds the line number of the current
line; LINK holds the index of the next line of text; NEXTLINE holds the line
number of the next line of text.
1. [Initializations]
PRESENT «+ CONVERTNUM(SUB(FREE_TEXT]1],1,5))
LINK + CONVERTNUM(SUB(FREE_TEXT/1],6,5))
2. [Engage loop to scan through all lines of the array]
Repeat while LINK ee 0
NEXTLINE + CONVERTNUM(SUB(FREE__ TEXT[LINK],1,5)
If NEXTLINE +4 PRESENT + 10
then SUB(FREE_TEXT|LINK],1,5) — PRESENT + 10
PRESENT + CONVERTNUM(SUB(FREE_TEXT|LINK],1,5))
LINK + CONVERTNUM(SUB(FREE_TEXT|LINK],6,5))
3. [Finished]
Return

10) Function REVERSE(FIRST). Given FIRST, a pointer to the beginning


_ of a linked list, this function reverses the list; and returns a pointer to the
start of the new list.

1. [Empty list?]
If LINK(FIRST) = NULL
then Return(NULL)
2. [Only one element?]
If LINK(FIRST) = NULL
then Return(FIRST)
3. [Reverse list]
PRED «+ NULL
Repeat while FIRST 54 NULL
TEMP + LINK(FIRST)
LINK(FIRST) — PRED
PRED + FIRST
FIRST «+ TEMP
4. [Return pointer to new list]
Return(PRED)

11) Procedure REC_INSERT(START,VALUE). Give START, a pointer


to the front of a linear linked list, this recursive procedure creates a node with
INFO field equal to VALUE and inserts it into the list which is ordered
according to increasing values.

1. [Check for null pointer]


If START = NULL
then P <NODE
INFO(P) + VALUE
LINK(P) + START
START «+ P
Return
4-10
2. [Check if proper position]
If INFO(START) > VALUE
then P <= NODE
INFO(P) — VALUE
LINK(P) — START
START + P
Return
3. [Invoke recursive call]
VALUE)
Call REC_INSERT(LINK(START),
Return

12) Function SEARCH(FIRST,X,DATA). Given FIRST, a pointer to the


front of a linear linked list, this function searches the linked linear list for an
element with key X. If it is found, the information contents of the node are
returned through the parameter DATA and the node is moved to the start of
the list. The function returns true if the search is successful; false otherwise.

1. [Empty list?]
If START = NULL
then Return(false)
2. [Is X the first element?|
If KEY(START) = X
then DATA + INFO(START)
Return(true)
3. [Search for desired key]
TEMP + LINK(START)
PRED «+ START
FOUND + false
Repeat while TEMP 34 NULL and ~FOUND
If KEY(TEMP) = X
then FOUND < true
else PRED + TEMP
TEMP + LINK(TEMP)
4. [Was element found?|
If ~FOUND
then Return(false)
5. [Move element to front of list]
LINK(PRED) « LINK(TEMP)
LINK(TEMP) + START
START «+ TEMP
6. [Return desired information|
DATA + INFO(START)
Return(true)
13) Algorithm CUSTOMERS. This algorithm handles the processing of a
company’s list of customers with outstanding bills. The data structure used
requires two types of nodes: CUST.NODE has fields NAME, ADDR, TOTAL,
LINK, FIRST, and LAST; ITEM has fields COMMOD, OWING, and NEXT.
The entire structure is pointed at by CUSTOMER. Construction of the
structure is handled by procedure PURCHASE as new customers are added to
the list. Since searching is required by procedures PURCHASE, PAYMENT,
and BILL, it is implemented in a separate procedure, which is also capable of
inserting new elements depending on value of a flag parameter.

1. [Initialize structure pointer]


CUSTOMER + NULL
2. [Process all input]
Repeat thru step 4 while there remains input
3. [Input a command]
Read(COMMAND)
4. [Choose appropriate action]
Select Case (COMMAND)
Case ‘PURCHASE’:
Call PURCHASE
Case ‘PAYMENT!:
Call PAYMENT
Case ‘BILL’:
Call BILL
Case ‘DEBTORS’:
Call DEBTORS
5. [Finished]
Exit.

Function SRCH_INS(CUST_NAME,ADDRESS,FLAG). This function


searches through the list of customer nodes for one corresponding to
CUST_NAME, and returns a pointer to the node if found. FLAG indicates
whether a CUST_NODE is to be inserted if CUST_NAME is not found in the
list.

1. [Empty Structure?]
If CUSTOMER = NULL
then If FLAG
then P <= CUST_NODE
CUSTOMER+ P
LINK(P) + NULL
NAME(P) + CUST_NAME
ADDR(P) + ADDRESS
FIRST(P) + LAST(P) «— NULL

4-12
TOTAL(P) + 0
Return(P)
else Return(NULL)
2. [Insert at top of list?]
If CUST_NAME < NAME(CUSTOMER)
then If FLAG
then P <= CUST_NODE
LINK(P) — CUSTOMER
CUSTOMER+ P
NAME(P) + CUST_NAME
ADDR(P) + ADDRESS
FIRST(P) + LAST(P) + NULL
TOTAL(P) + 0
Return(P)
else Return(NULL)
3. [Check rest of list]
FOUND + false
SAVE + CUSTOMER
PRED «+ NULL
Repeat while SAVE 54 NULL and =FOUND
If NAME(SAVE) > CUST_NAME
then FOUND + TRUE
else PRED «+ SAVE
SAVE + LINK(SAVE)
4. [Insertion in list?]
If “FOUND
then If FLAG
then P <= CUST_NODE
LINK(P) + LINK(PRED)
LINK(PRED) «— P
NAME(P) «+ CUST_NAME
ADDR(P) + ADDRESS
FIRST(P) + LAST(P) — NULL
TOTAL(P) + 0
Return(P)
else Return(NULL)
5. [Return location of node already in list]
Return(SAVE)

Procedure PURCHASE. This procedure reads a customer’s name,


address, and purchases, adding a node to his list of outst
anding debts for each
purchase. Procedure SRCH_INS finds the desired CUST_NODE and inserts
one if it is not already there.

4-13
[Input customer’s name, address, and number of purchases}
Read(CUST_NAME,ADDRESS OM)
[Find customer node]
C_NODE + SRCH _INS(CUST_ NAME,ADDRESS ame)
[Add an item node for each CES
Repeat thru step 5 for I = 1, 2, .... NUM
[Create and add node]
If FIRST(C_NODE) = NULL (no items in list)
then NEW <—ITEM
FIRST(C_NODE) + LAST(C_NODE) + NEW
NEXT(NEW) «— NULL
else NEW <—ITEM
SAVE «+ LAST(C_NODE) (mark current last node)
NEXT(SAVE) + LAST(C_NODE) + NEW (place at end of list)
NEXT(NEW) «— NULL
[Initialize ITEM fields and update total debt]
Read(COMMOD(NEW),OWING(NEW))
TOTAL(C_NODE) + TOTAL(C_NODE) + OWING(NEW)
[Finished]
Return

Procedure PAYMENT. This procedure reads in a customer’s name and


the commodity for which he has paid. The node corresponding to this
commodity in the item list is deleted and the customer’s total outstanding
debt is updated. If the customer has paid all his bills, his name is dropped
from the customer list.

1. [Read customer’s name and commodity paid for]


Read(CUST_NAME ,;COMMODITY)
a [Find customer node]
C_NODE « SRCH_INS(false)
[Check for valid input]
If CINODE = NULL
then Write(/;CUSTOMER NOT IN LIST’)
Return
[Search for commodity in item list]
SAVE + FIRST(C | NODE)
FOUND + false
Repeat while SAVE 34 NULL and ~FOUND
If COMMOD(SAVE) = COMMODITY
then FOUND < true
else PRED + SAVE
SAVE + LINK(SAVE)

h-14
[Was commodity found?|
If -FOUND
then Write(/COMMODITY NOT FOUND IN LIST’)
Return
[Delete commodity from list]
If SAVE = FIRST(C_NODE) (is commodity first in list?)
then FIRST(C_NODE) — NEXT(SAVE)
else NEXT(PRED) ~ NEXT(SAVE)
[Was commodity last in list?]
If NEXT(PRED) = NULL
then LAST(C_NODE) — PRED
[No items left in list?]
If FIRST(C_NODE) = NULL
then If CLNODE = CUSTOMER (first node in list?)
then CUSTOMER + LINK(C_NODE)
else LINK(PRED) — LINK(C_NODE)
Return
9. [Update total debt]
TOTAL(C_NODE) «+ TOTAL(C_NODE) - OWING(SAVE)
10. [Finished]
Return

Procedure BILL. This procedure reads a customer’s name, and produces a


list of items and amounts for which:he is in debt.

1. [Read customer’s name]


Read(CUST_NAME)
os [Find customer node]
C_NODE + SRCH_INS(false)
[Check for valid input]
If C_LNODE = NULL
then Write(/CUSTOMER NOT IN LIST’)
Return
[Print appropriate output]
Write(} OUTSTANDING DEBT: ',CUST_NAME)
SAVE — FIRST(C_NODE)
Repeat while SAVE 34 NULL
Write(COMMOD(SAVE),OWING(SAVE))
SAVE — NEXT(SAVE)
Write(" TOTAL DEBT: ',TOTAL{CUST_NODE))
on (¥inished]
Return
Procedure DEBTORS. This procedure traverses the customer list and
prints the names of all the customers with outstanding debts.

1. [Empty structure?]
If CUSTOMER = NULL
then Write('NO CUSTOMERS IN LIST’)
Return
[Print heading]
Write(‘'CUSTOMERS WITH OUTSTANDING DEBTS:')
[Traverse list]
SAVE + CUSTOMER
Repeat while SAVE oe NULL
Write(NAME(SAVE), TOTAL{SAVE))
SAVE + LINK(SAVE)
[Finished]
Return

EXERCISES SECTION 4-2.2 PAGE 284

1) Procedure C_DELETE(HEAD,X). Given a circular list with head node


HEAD, this procedure deletes from the list the node whose address is given by
the pointer X. TEMP is a temporary pointer variable.

i [Deletion of head node?]


If X = HEAD
then Write(/ATTEMPTED DELETION OF HEAD NODE’)
Return
[Find predecessor of X|
TEMP «+ HEAD
Repeat while LINK(TEMP) 34 HEAD and LINK(TEMP) 7 X
TEMP <— LINK(TEMP)
[Was node found?|
If LINK(TEMP) + X
then Write(/ NODE NOT CONTAINED IN LIST’)
Return
[Change link field of predecessor]
LINK(TEMP) + LINK(X)
[Finished]
Return
Function C_APPEND(A,B). Given A and B, the head nodes of two
circular lists, this function concatenates the list, and returns a pointer to the
new list. TEMP is a temporary pointer variable.

1. [Check for null lists]


If LINK(A) = A
then Return(B)
If LINK(B) = B
then Return(A)
2. [Find end of first list]
TEMP + A
Repeat while LINK(TEMP) + A
TEMP + LINK(TEMP)
3. [Connect end of A to front of B]
LINK(TEMP) — LINK(B)
4. [Find end of list B]
TEMP + B
Repeat while LINK(TEMP) + B
TEMP + LINK(TEMP)
5. [Reset links]
LINK(TEMP) + A
Return(A)

3) Procedure C_SPLIT(HEAD,SPLIT). Given a circular list with head


node HEAD, this procedure splits the list into two circular lists. The node
whose address is given by SPLIT will be the first node in the second list. A
head node will be allocated to this second list, and SPLIT will be assigned to
its address. TEMP and NEW are temporary pointer variables.

1. [Find node with link to SPLIT]


TEMP + HEAD
- Repeat while LINK(TEMP) SPLIT and LINK(TEMP) 4 HEAD
TEMP + LINK(TEMP)
2. [Split list if node found]
If LINK(TEMP) = SPLIT
then LINK(TEMP) — HEAD
else Write(/NODE GIVEN BY SPLIT NOT CONTAINED IN LIST’)
Return
3. [Find last node of original list]
TEMP + SPLIT
Repeat while LINK(TEMP) + HEAD
TEMP + LINK(TEMP)
4. [Allocate head node for second list and reset links]
NEW <— NODE

4-17
LINK(NEW) + SPLIT
SPLIT + NEW
LINK(TEMP) + SPLIT.
Return

4) Procedure CQ _INSERT(HEAD,Y). Given HEAD, the head node of a


circular list representing a queue, this procedure inserts a new node with
information contents Y at the end of the list. NEW and TEMP are temporary
pointer variables.

1. [Find end of list]


TEMP + HEAD
Repeat while LINK(TEMP) +4 HEAD
TEMP + LINK(TEMP)
2. [Insert new node]
NEW <— NODE
LINK(NEW) + HEAD
LINK(TEMP) — NEW
INFO(NEW) + Y
Return

Function CQ DELETE(HEAD). Given HEAD, the head node of a


circular list representing a queue, this function deletes a node at the front of
the list, and returns the information contents of that node. TEMP is a
temporary pointer variable.

1. [Check for empty list]


TEMP + LINK(HEAD)
If TEMP = HEAD
then Write(/LIST UNDERFLOW’)
Return('’)
2. [Delete the node]
LINK(HEAD) + LINK(TEMP)
3. [Return info contents of node]
Return(INFO(TEMP))

5) Procedure RETURN(HEAD). Given a circular list with head node


HEAD, this procedure returns the list to the availability area of storage.
TEMP is a temporary pointer variable.

1. [Surround alink]
TEMP «— LINK(HEAD)
2. [Join circular list to availability list]
LINK(HEAD) + AVAIL
3. [Reset head of availability list]
AVAIL «+ TEMP
Return

6) Procedure LINK_SUB(S1PTR,S2PTR,K). Given pointers to the last


elements in two circularly linked lists representing strings as outlined in the
exercise, this procedure implements the instruction S1 + SUB(S1,1,K) © S2
© SUB(S1,K+1). P1 and P2 are used to chain through the links of the lists.
I is used as a counter.

1. [Valid K?|
IK <0
then Write(/INVALID K VALUE ',K)
Return
2. [Initializations]
P1 + LINK(S1PTR)
I+ 1
3. [Isolate SUB(S1,1,K)]
Repeat while P1 4 SIPTR and I < K
I+eI+1
P1 — LINK(P1)
MARK + LINK(P1)
OLD + Pl
4. [Link S2]
P2 — LINK(S2PTR)
Repeat while P2 - S22 TR
P < NODE
LINK(OLD) + P
INFO(P) + INFO(P2)
P2 + LINK(P2)
OLD «+ P
5. [Link last element of S2]
P <= NODE
LINK(OLD) + P
INFO(P) — INFO(P2)
6. [Link SUB(S1,K+1)
LINK(P — MARK
7. [Was SUB(S1,K+1) empty?|
If MARK = LINK(S1PTR)
then SIPTR+P
8. [Finished]
Return
EXERCISES SECTION 4-2.3 PAGE 291

1) Procedure DLDQ_INSERT(L,R,X,FRONT,REAR). Given a deque


represented by a linked linear list whose leftmost and rightmost addresses are
given by pointer variables L and R, respectively, this procedure inserts a new
node at one end of the deque. The boolean variables FRONT and REAR
specify which end the insertion is to be made. The information to be entered
in the node is given by X. NEW is a temporary pointer variable.

1. [Allocate new node]


NEW <= NODE
INFO(NEW) « X
2. [Insert into empty list?]
If R = NULL and (FRONT or REAR)
then LL — R— NEW
LPTR(NEW) — RPTR(NEW) — NULL
Return
3. [Insertion at rear of deque?|
If REAR
then RPTR(R) — NEW
LPTR(NEW) + R
R «+ NEW
RPTR(R) + NULL
Return
4, [Insertion at front of deque?|
If FRONT
then LPTR(L) + NEW
RPTR(NEW) + L
L + NEW
LPTR(L) «+ NULL
Return
5. [Insertion disallowed]
Write(/INSERTION DISALLOWED’)
Return

By appropriate setting of REAR and FRONT, this algorithm performs an


insertion on an input-restricted or output-restricted deque.
Function DLDQ DELETE(L,R,FRONT,REAR). Given a deque
represented by a linked linear list as described above, this function deletes a
node from ene end of the end of the deque. The boolean variables FRONT
and REAR specify which on end the deletion is to be made. The information
contents of the deleted node are returned by the function. TEMP is a
temporary pointer variable.

1. [Check for underflow]


If R = NULL
then Write(/LIST UNDERFLOW')
Return
2. {Deletion from rear of deque?]
If REAR
then TEMP -—R
R — LPTR(R)
RPTR(R) — NULL
Return(INFO(TEMP))
3. [Deletion from front of deque?|
if FRONT
then TEMP +L
L + RPTR(L)
LPTR(L) — NULL
Return(INFO(TEMP))
4. [Deletion disallowed] ;
Write(/DELETION DISALLOWED’)
Return(0)

By appropriate setting of REAR and FRONT, this algorithm performs a


deletion on an input-restricted or output-restricted deque.

Function DOUBLE(FIRST). Given FIRST, a pointer to the first element


of a linear linked list, this function creates and returns a pointer to the head
node of an equivalent doubly linked list. PRED and TEMP are temporary
pointer variables.

1. [Creat a head node]


HEAD < NODE
2. [Initializations]
TEMP + FIRST
PRED + HEAD
3. [Create doubly linked list]
Repeat while TEMP +4 NULL
NEW <— NODE
INFO(NEW) + INFO(TEMP)

4-21
RPTR(PRED) — NEW
LPTR(NEW) + PRE
PRED «+ NEW ‘
TEMP + LINK(TEMP)
4. [Complete links]
LPTR(HEAD) — PRED
RPTR(PRED) + HEAD
5. [Finished]
Return(HEAD)

5a) Procedure TERMINATION(FIRST,PROJECT). Given FIRST, a


pointer to the first node (the READY head node) in the project data structure,
and PROJECT, the name of a project which has just been terminated, this
procedure deletes the project head node and returns the list of employees
working on the project to the READY list. TEMP, PRED, START, LAST,
START_READY, and LAST_READY are temporary pointer variables.

1. [Find project head]


PRED «+ FIRST
TEMP + RPTR(FIRST)
FOUND + false
Repeat while TEMP + NULL and -FOUND
If NAME(TEMP) = PROJECT
then FOUND + true
else PRED «+ TEMP
TEMP + RPTR(TEMP)
2. [Was project found?|
If -FOUND
then Write(/PROJECT ',PROJECT,’ NOT FOUND’)
Return
3. [Delete project name from list]
RPTR(PRED) — RPTR(TEMP) .
4, [Find first and last names of READY and PROJECT list]
START + LPTR(TEMP)
LAST + RPTR(START)
START_READY + LPTR(FIRST)
LAST_READY + RPTR(START_READY)
5. [Return employee names to READY list]
LPTR(LAST_READY) +- START
RPTR(START) + LAST_READY
LPTR(LAST) + START_READY
RPTR(START_READY) + LAST
LPTR(FIRST) + START
6. [Finished]
Return
h-22
b) Precedure MOVE(NAME,CURRENT,NEW). Given NAMB, a pointer
to the node of an employee, CURRENT, a pointer to the head node of the
project he is working on, and NEW, a pointer to the head node of the new
project to which he has been assigned, this procedure moves the employee
node to the appropriate new project list. START is a temporary pointer
variable.

1. [Delete employee node from current project list]


If LPTR(NAME) = NAME (only one employee?)
then LPTR(CURRENT) + NULL
else LPTR(RPTR{NAME)) — LPTR(NAME)
RPTR(LPTR(NAME)) — RPTR(NAME)
If LPTR(CURRENT) = NAME (employee first in list?)
then LPTR(CURRENT) «+ LPTR(NAME)
2. [Insert employee node into new project list]
START + LPTR(NEW)
If START = NULL (no employees in list?)
then LPTR(NEW) — NAME
RPTR(NAME) ~ LP'TR(NAME) — NAME
else LPTR(NAME) — START :
RPTR(NAME) + RPTR(START)
RPTR(START) — NAME
LPTR(NEW) — NAME
3. [Finished]
Return

6) Procedure UPDATE(COMPANY,QUOTE). Given a pointer to a


company node in a doubly linked list, COMPANY, and that company’s latest
stock market quotation, QUOTE, this procedure updates the compaay’s
quotation field and moves the node so that an ordered list is maintained.

1. [Update company’s latest stock quotation}


STOCK(COMPANY) + QUOTE
2. [Move company node right if necessary]
NEXT «- RPTR(COMPAN‘)
FOUND + false
Repeat while NEXT A NULL and ~FOUND
If STOCK(NEXT) > QUOTE
then FOUND < true
else NEXT « RPTR(NEXT)
If NEXT 54 RPTR(COMPANY)
then RPTR(LPTR(COMPANY)) + RPTR(COMPANY)
LPTR(RPTR(COMPANY)}) — LPTR(COMPANY)
RPTR(LPTR(NEXT)) + COMPANY
LPTR(COMPANY) + LPTR(NEXT)

4-23
LPTR(NEXT) «+ COMPANY
RPTR(COMPANY) «+ NEXT
Return ‘
3. [Move company node left if necessary]
NEXT + LPTR(COMPANY)
FOUND + false
Repeat while NEXT 54 NULL and — FOUND
If STOCK(NEXT) < QUOTE
then FOUND + true
else NEXT + LPTR(NEXT)
If NEXT = LPTR(COMPANY)
then RPTR(LPTR(COMPANY)) + RPTR(COMPANY)
LPTR(RPTR(COMPANY)) — LPTR(COMPANY)
LPTR(RPTR(NEXT)) + COMPANY
RPTR(COMPANY) + RPTR(NEXT)
RPTR(NEXT) + COMPANY
LPTR(COMPANY) + NEXT
Return
4. [No changes necessary]
Return

EXERCISES SECTION 4-3.1 PAGE 298

1) Function POLY_EVAL(P,X,Y,Z). Given a polynomial in 3 variables


whose first term is referenced by the pointer variable P, this function
evaluates the polynomial for given values of X, Y, and Z, and returns the
result. TEMP is a temporary pointer variable.

1. [Initializations]
TEMP + P
RESULT <— 0
2. [Evaluate each node and keep running total]
Repeat while TEMP +4 NULL
RESULT «+ RESULT + COEFF(TEMP) * XTPOWER_X(TEMP)
* Y{POWER_Y(TEMP)*Z{POWER_Z(TEMP)
3. [Finished]
Return(RESULT)

4-24
Function POLY_SUB(P,Q). Given two polyncmials whose first terms are
referenced by pointer variables P and Q respectively, this function subtracts
the second from the first and stores the difference in a third polynomial, the
head of which is returned by the function. In practice one wou!d combine
algorithms POLY_ADD and POLY_SUB into a more general algorithm. The
small difference in processing could be controlled by a single boolean variable.
LAST is a global variable.

1. [Initializations]
R «— NULL
PSAVE + P
QSAVE + Q
[End of any polynomial?|
Repeat thru step 4 while P ee NULL and Q x NULL
[Get values for each term]
Al — POWER_X(P)
A2 — POWER_X(Q)

C2 + POWER_Z
D1 — COEFF(P)
D2 + -COEFF(Q)
[Compare terms]
If (Al = A2) and (B1 = B2) and (C1 = C2)
then If D1+D2 0
then R + POLYLAST(A1,B1,C1,D1+D2,R)
P + LINK(P)
Q + LINK(Q)
else If(A1>A2) or ((Al=A2) and (B1>B2)) or ((A1=A2) and
(B1=B2) and (C1>C2))
then R + POLYLAST(A1,B1,C1,D1R)
P + LINK(P)
else R + POLYLAST(A2,B2,C2,D2,R)
Q + LINK(Q)
[Not at end of one of polynomials?|
IfP = NULL
then LINK(LAST) + COPY(P)
else Repeat while Q ee NULL
R + POLYLAST(POWER_X(Q),POWER-Y(Q),
POWER_Z(Q),-COEFF(Q),R)
Q + LINK(Q)
[Restore initial pointer values for P and Q]
P -— PSAVE
Q + QSAVE

4-25
i [Return pointer of difference polynomial]
Return{R)

Function POLY_ORDER(P). Given P, a pcinter to the first term of a


pelynomial in three variables that is uncerdered and may have repeated terms,
this function creates an ordered hinear list with no duplicate terms, and
returis a pointer to the new list. The action taken on repeated terms depends
upon the application, but we shall add the cocfticients of duplicate terms
because it turns out to be convenient in many applications. TEMP and SAVE
are temporary pointer variables. Function DELETE deletes a node from a
linked list.

i [Check for null list}


If P = NULL
then Return(NULL)
[Initializations]
HAD — P
P — LINK(P)
LINK(HEAD) + NULL
Oe [Scan all nodes in unordered list] _
Repeat thru step 11 while P me NULL
[Compute values of each power for node in unordered list]
NX « POWER_X(P)
NY +- POWER_Y(P)
NZ + POWER_Z(P)
{Search for predecessor and successor in ordered list]
PRED + SUCC «+ HEAD
FOUND + false
Repeat thru step 7 while SAVE 54 NULL and -FOUND
[Compute values of each power for next node in ordered list]
A «+ POWER_X(SUCC}
B + POWER_Y(SUCC)
C + POWER_Z(SUCC)
{Compare terms]
If (A>NX) or ((A=NX) and (B>NY)) or ((A=NX) and (B=NY) and
(C>NZ))
then PRED «+ SUCC
SUCC + LINK(SUCC)
else FOUND + true
[Save pointer to next node in unordered list]
TEMP + LINK(P)
[Check for duplicate terms|
If A = NX and B = NY and C = NZ
then COEFF(SUCC) + COEFF(SUCC) + COEFF(P)
If COEFF(SUCC) = 0
then HEAD «+ DELETE(HEAD,SUCC)
4-26
else If SUCC = HEAD
then LINK(P) — HEAD
HEAD <— P
else LINK(P) + LINK(PRED)
LINK(PRED) + P
10. [Get next node in ordered list]
P + TEMP
11. [Finished]
Return{HEAD)

en Function P_COPY(P). Given a polynomial in three variables whose first


term is referenced by pointer variable P, this function creates a copy of the
polynomial and returns a pointer to its first term. NEW and SAVE are
temporary pointer variables.

1. [Check for null list]


ifP = NULL
then Return(NULL)
2. [Copy first node]
NEW < NODE
POWER_X(NEW) «- POWER_X(P)
POWER_Y(NEW) + POWER_Y(P)
POWER_Z(NEW) — POWER_2(P)
COEFF(NEW) — COEFF(P)
HEAD «+ NEW
3. [Copy all other nodes]
LAST «— HitAD
SAVE + LINK(P)
Repeat while SAVE 54 NULL
NEW <= NODE
LINK(LAST) + NEW
POWER_X(NEW) — POWER_X(SAVE)
POWER_Y(NEW) + POWER_Y(SAVE)
POWER_Z(NEW) — POWER_2Z(SAVE)
COEFF(NEW) — COEFF{SAVE)
LAST — NEW
SAVE + LINK(SAVE)
4. [Finished]
LINK(LAST) — NULL
Return{HEAD)

4-27
5 ) Function POLY_MUL(A,B). Given two polynomials whose first terms are
referenced by pointer variables A and B, respectively, and Function
POLY_ORDER of Exercise 3, in this section, this function multiplies these
two polynomials together, and returns a pointer to the resultant polynomial.
The original polynomials are to remain unchanged. FRONT, SAVEA,
SAVEB, and NEW are temporary pointer variables.

1. [Check for null list]


If A = NULL or B = NULL
then Return(NULL)
2. [Chain down list A]
SAVEA <A
SAVEB + B
FRONT <— NULL
Repeat thru Step 6 while A ee NULL
3. [Chain down list B]
B — SAVEB
Repeat thru Step 5 while B 54 NULL
4. [Create another node for product polynomial]
NEW <— NODE
POWER_X(NEW) — POWER_X(A) + POWER_X(B)
POWER_Y(NEW) «+ POWER_Y(A) + POWER_Y(B)
POWER_2(NEW) — POWER_Z(A) + POWER_Z(B)
COEFF(NEW) « COEFF(A) * COEFF(B)
LINK(NEW) — FRONT
FRONT — NEW
5. [Get next term from polynomial B}
B < LINK(B)
6. [Get next term from polynomial Al
A + LINK(A)
7. {Reorder list and combine duplicate terms|
HEAD «+ POLY_ORDER(FRONT)
8. [Restore initial pointer values for A and B]
A+ SAVEA
B «— SAVEB
Return(HEAD)
Procedure POLY_DIV(P,Q,QUOT,REM). Given two polynomials
whose first terms are referenced by pointer variables P and Q, respectively,
and functions P_COPY, POLY_MUL, and POLY_SUB, this procedure divides
these polynomials (P/Q), and returns pointers to the quotient and remainder
polynomials, QUOT and REM respectively. The original polynomials are to
remain unchanged. Temporary pointer variables include P_REST, which
referencés the present dividend; Q SECOND, which points at the second node
of the divisor; QU, TEMP, NEW, and PRODUCT. COMP is a boolean loop
control variable.

1. [Check for division by 0]


QUOT + REM + NULL
If Q = NULL
then Write(‘ATTEMPTED DIVISION BY ZERO’)
Return
2. [Initializations]
P_REST — P_COPY(P)
Q SECOND « LINK(Q)
NEW <= NODE
QUOT + QU + NEW
LINK(QUOT) + NULL
3. [Divide until division is exact]
COMP + false
Repeat thru step 5 while P_REST ae NULL and ~COMP
4. [Allocate new node for quotient].
NEW <— NODE
POWER_X(NEW) + POWER_X(P_REST) - POWER_X(Q)
POWER_Y(NEW) «+ POWER_Y(P_REST) - POWER_Y(Q)
POWER_Z(NEW) + POWER_Z(P_REST) - POWER_2(Q)
COEFF(NEW) + COEFF(P_REST) / COEFF(Q)
LINK(NEW) + NULL
5. [Division complete with remainder?|
It POWER_X(NEW) < 0 or POWER-Y(NEW) < 0. or
POWER_Z(NEW) < 0
then COMP + true
else (get next dividend)
PRODUCT « POLY_MUL(NEW,Q_SECOND)
TEMP + LINK(P_REST)
P_REST + POLY_SUB(TEMP,PRODUCT)
(insert the quotient node into the quotient list)
QU + LINK(QU) — NEW
6. [Release dummy head of quotient list]
QUOT + LINK(QUOT)
REM + P_REST
Return

4-29
~J Function POLY_INT(P,VAR). Given a polynomial whose first term is
referenced by the pointer variable P, and a character string variable VAR
which takes on the value of one of 'X', 'Y', or 'Z’, this function integrate? the
polynomial with respect to the variable VAR and returns a pointer to the first
term of the integral. The original polynomial remains unchanged. NEW,
SAVE, and SAVEP are temporary pointer variables.

1. [Check for aull list]


If P = NULL
then Return(NULL)
2. [Initializations]
SAVEP + P
SAVE «— HEAD — NULL
3. [Scan through all terms of polynomial]
Repeat thru step 5 while P 54 NULL
4. [Allocate node of integral]
NEW <= NODE
If VAR = 'X!
then POWER_X(NEW) ~ POWER_X(P) + 1
POWER_Y(NEW) «+ POWER_Y(P)
POWER_Z(NEW) ~ POWER_Z(P)
COEFF(NEW) + COEFF(P) / POWER_X(NEW)
else If VAR =‘Y'
then POWER_Y(NEW) + POWER_Y(P) + 1
POWER_X(NEW) + POWER_X(P)
POWER_Z{NEW) + POWER_Z(P)
COEFF(NEW) «+ COEFF(P) / POWER_Y(NEW)
else POWER_Z(NEW) + POWER_Z(P) + 1
POWER_X(NEW) + POWER_X(P)
POWER_Y(NEW) «- POWER_Y(P)
COEFF(NEW) + COEFF(P) / POWER_Z({(NEW)
5. {Maintain link fields and allocate new node]
If HEAD = NULL
then HEAD «+ NEW
else LINK(SAVE) + NEW
SAVE + NEW
P — LINK(P)
6. [Finished]
LINK(SAVE) + NULL
P + SAVEP
Return(HEAD)

4-30
8) Function POLY_DIF(P,VAR). Given a polynomial whose first term is
referenced by the pointer variable P, and a character string variable VAR,
which takes on the value of one of /X’, 'Y', or ‘Z’, this function differentiates
the polynomial with respect to the variable VAR and returns a pointer to the.
derivative polynomial. The original polynomial remains unchanged. NEW,
SAVE, and SAVEP are temporary pointer variables.

1. [Check for null list]


IifP = NULL
then Return(NULL)
2. [Initializations]
SAVEP + P
HEAD «+ SAVE + NULL
3. [Scan through all terms of polynomial]
Repeat thru step 5 while P = NULL
4. [Allocate node of derivative]
NEW <— NODE
Ie VAR =X!
then COEFF(NEW) — COEFF(P) * POWER_X(P)
POWER_Y(NEW) «+ POWER_Y(P)
POWER_Z(NEW) ~— POWER_Z(P)
POWER_X(NEW) — POWER_X(P) - 1
élser “If VAR = CY!
then COEFF(NEW) — COEFF(P) * POWER_Y(P)
POWER_X(NEW) « POWER_X(P)
POWER_Z(NEW) — POWER_Z(P)
POWER_Y(NEW) — POWER_Y(P) - 1
else COEFF(NEW) — COEFF(P) * POWER_Z(P)
POWER_X(NEW) — POWER_X(P)
POWER_Y(NEW) — POWER_Y(P)
POWER_Z(NEW) + POWER_Z(P) - 1
5. [Maintain link fields]
If HEAD = NULL
then HEAD «+ NEW
else LINK(SAVE) — NEW
SAVE — NEW
P + LINK(P)
6. [Finished]
LINK(SAVE) — NULL
P + SAVEP
Return(HEAD)

4-31
9) Procedure POLY_PRINT(P). Given a polynomial whose first term is
referenced by the pointer variable P, this procedure prints the polynomial.
The format of the output will be as follows:

<coeff> X f <power_x> Y f <power_y> Z f <power_z> [+ <rest of poly.>]

1. [Check for null list]


If P = NULL
then Write(/EMPTY LIST’)
Return
2. [Initializations]
SAVEP + P
3. [Print all terms of polynomial]
Repeat while P ee NULL
Write(!! 0 COEFF(P) © ' Xt! 0 POWER_X(P) 0 / !
© POWER_Y(P) © ! Zt! 0 POWER_Z(P))
P < LINK(P)
If P 4 NULL
then Write(' +’)
4. [Finished]
P + SAVEP
Return

EXERCISES SECTION 4-3.2 PAGE 306

1) program midsq(input,output);

{ This program implements the midsquare hashing method specified in the


text to hash a set of variable names. }

type string = packed array{1..80] of char;

var varname:string;
result:real;
n:integer;

GARB EEEEE ORO OBEER EEO EESBS OBE ABE EEE AA TEE IA AAI ATE IE}

#include ‘getline.’ ;
#include 'length.i’;
[ABBE EE EEE EEO SEES EES ABE BEBE EEE EE SAAB ACRE EIT AEE +}

4-32
procedure precond(varname:string;var i:real);

{ This function preconditions the variable name so as to convert it into


an equivalent integer. }

var j:integer;

begin
1:= 1;
{ pass through each letter of varname }
for j := 1 to length(varname) do
i := i * ord(varname({j])/5
end;
EE ISS EBSD SEAT IAI IITA EIA
EEO RBBB EEE HEBER S
GABE E

function modr(a,b:real):real;

{ This function computes a mod b. }

begin
modr := ((a/b) — trunc(a/b)) * b
end;

GABE BEER EEE E EERE D EOE EEEIEEE EEA AA AAT SATE aaa Aa

function power(a,b:real):real;

{ This function computes a ** b. }

begin
power := exp(b#ln(a))
end;

[EHH E REHAB SESS S OEE AIEEE OBE EEE AEE ABER AAI Ee}

function size(number:real):integer;

{ This function returns the number of digits in a given number. }

var temp:real;
count:integer;

begin
{ count number of digits in number }

4-33
temp := number;
count := 0;
while (temp > 1.0) do
begin
temp := (temp / 10);
count := count + 1
end;
size := count
end;

FABER SRE ESSE SE EEO AAAS ESAS SOSA ACEO IEE EEE EERE te #4}

function hash(key:real;n:integer):real;

{ Given a key and a positive integer, N, this procedure generates an integer


in the range of (0,1, ..., 10**N-1) by the midsquare hashing method. }

var square:real;
s:integer;

begin
{ apply hashing procedure }
square := power(key,2.0);
8 := size(square);
ifs <=n
then hash := square
else begin
square := square / power(10,round((s-n)/2.0));
hash:= modr(square,power(10,n));
end
end;

DEBE BBBEBEAEBS EHC H


ABBR SAREE E SSO BS CACO EEE HE EEE Bi Eor bri)
4

begin
read|n(n);
while not eof do
begin
getline(varname);
precond(varname, result):
writeln(’VARIABLE = ’:12,varname:length(varname),’ PRECOND = ’:12 J

result:8:2,’ HASHED TO ’:12,trunc(hash(result,n)):5)


end
end.

4-34
VARIABLE = __ temp PRECOND = 228846.28 HASHED TO 6
VARIABLE = num PRECOND = 11222.64 HASHED TO 94
VARIABLE = sum PRECOND = 11732.76 HASHED TO _ 65
VARIABLE = location PRECOND = 43828497296.38 HASHED TO 25
VARIABLE = address PRECOND = 1890617222.40 HASHED TO 81
VARIABLE = name PRECOND = 187945.65 HASHED TO 35
VARIABLE = phone PRECOND = 4596617.63 HASHED TO 93
VARIABLE =_ grade PRECOND = 3681163.97 HASHED TO_ 68
VARIABLE = link PRECOND = 213554.88 HASHED TO 56
VARIABLE = info PRECOND = 209230.56 HASHED TO 74
VARIABLE = data PRECOND = 174631.04 HASHED TO 60

2)
“ program fold(input,output);

{ This program implements the hashing method of folding, assuming we are


given 8-digit keys, and wish to obtain a 3-digit address. }

var key ,n:integer;

Satanic acidilactici hatha lahat databace adalat

function size(number:integer):integer;

{ This function returns the number of digits in a given number. }

var temp,count:integer;

begin
{ count number of digits in number }
temp := number;
COUnU >——10;
while (temp <> 0) do
begin
temp := temp div 10;
count := count + 1
end;
size := count
end;

[ABB CR
BEER E EEE EERE E BEES EEE EECAO EEE ECHO CDE E oiereaiii)

function power(a,b:integer):integer;

{ This function computes a ** b. }

var result,i:integer;

fae
begin
result := 1;
for i:=1tobdo
result := result * a;
power := result
end;

GABE Soa a odaonddddacigdcddcicciiagilidknaciiciiiakinckeick it tok)

function hash(key ,n:integer):integer;

{ This function hashes a given key into a three-digit address. }

var sum,rest,s:integer;

begin
{ engage loop to handle each digit }
rest := key;
s := size(key);
while (s > n) do
begin
- sum := sum + (rest div (power(10,s—n)));
rest := (rest) mod (power(10,s—n));
Si=s-n
end;
hash := (sum + rest) mod (power(10,n))
end;

EB EEE EERE ESE EEE EOS ISSO EEEE E AEE EEE IAA IE EAI ES }

begin
{engage loop to process all data }
readIn(n);
while not eof do
begin
readIn(key);
writeln’INTEGER GENERATED FROM ‘key, ’ = ’,hash(key,n))
end
end.

INTEGER GENERATED FROM 97434658 = 378


INTEGER GENERATED FROM 31269857 = 67
INTEGER GENERATED FROM 12345678 = 657
INTEGER GENERATED FROM 98765432 = 673

h-36
INTEGER GENERATED FROM 15926487 = _—510
INTEGER GENERATED FROM 48159263 = —-186
INTEGER GENERATED FROM 78451236 = = 332
INTEGER GENERATED FROM 98776532 = 784
INTEGER GENERATED FROM 55332246 = 921
INTEGER GENERATED FROM 52884759 == —_ 434
INTEGER GENERATED FROM 99999999 = 97
INTEGER GENERATED FROM 55465787 = =. 298
INTEGER GENERATED FROM 23212141 = 394
INTEGER GENERATED FROM 87898999 = 966
INTEGER GENERATED FROM 65485278 = —584

The method which distributes the keys most evenly over the range depends
upon the domain, i.e. the particular set of keys. For example, when a set of
similar eight-digit keys was used, the order of the best performing methods
was midsquare, division, and folding. When a set of random, one to eight-
digit keys were used, there was no observable difference in distribution
(partially due to the small set of test keys and the original randomness in the
set of test keys). In essence, the distribution method should be chosen
according to the set of keys used if any information is available about them.
If the set of keys is fixed and well known, then a ‘‘custom”’ hashing function
can be created to best distribute the particular set. Such a function is known
as a distribution-dependent hashing function. The methods discussed up until
this point have all been distribution independent.

EXERCISES SECTION 4-3.3 PAGE 316

1) Let P = 75,198; Q = -1079,238; and MAX = 128


Then the list representation of P and Q are:

P 62 75 | 4 4 |4
Sri Fuiiy 3 165|]

Conversion to base 10 equivalent:


75198 + (-1079238) = -8 * 128° + -36 + 128! + 61 + 1282
== 1004040

As expected, this is the same answer as the addition done long


hand.
4-37
3) STEP COEF(P) COEF(Q) C SUMCF SECOND SUM
_PASS
NULL
120

91120
66 ——> 91 ——>120

NULL
8
36 ——> 8
61—>36 ——>8

HH
NLT
OHONAAAnNInrB 8 —»> -36 —> -61

Function MULTIPLICATION(P,Q). Given pointers P and Q to list


representing multiple-precision integers, this function constructs a list which
represents the product of the integers, and returns a pointer to the new list.
Algorithms ADDITION, INSERT, and REVERSE are referenced and they
provide some details on the variables used in this function. The CHOP
function is also used: it truncates the fractional part of its arguments.
PRODCR contains the product of corresponding COEF fields and C. The
actual multiplication is done by addition of partial products. The partial
products, however, require leading nodes with coefficient zero for proper place
holding. The place holding list has a first node with address HEAD, and a last
node with address PLACE_HOLDER. Temporary pointer variables PART,
T1, T2, SAVEP, and SAVEQ are also used.

1. [Trivial Case]
If P = NULL or Q = NULL
then Return(NULL)
2. [Initializations]
SAVEM — NULL
SAVEP < P
SAVEQ + Q
3. [Allocated head node for place holding list]
HEAD «+ PLACE_HOLDER + INSERT(0,NULL)
4. [Chain down list P]
Repeat thru step 7 while P 6 NULL
5. [Chain down list Q
If COEF(P) 2 0
then Q + SAVEQ
PART + NULL
C+-0
Repeat while Q +4 NULL
(Calculate value for and insert next node)
4-38
PRODCF + COEF(P)
* COEF(Q) + C
PART «+ INSERT(PRODCF mod MAX, PART)
C + CHOP(PRODCR/MAX)
(Next node from list Q)
Q + LINK(Q)
(Final carry?)
C0
then PART « INSERT( C mod MAX, PART)
(Reverse the resulting list)
PART «+ REVERSE(PART false)
(Incorporate the place holding list)
LINK(PLACE_HOLDER) + PART
(Add partial products)
Tl + SAVEM
T2 — LINK(HEAD)
SAVEM + ADDITION(SAVEM,T2)
6. [Enlarge the place holding list]
HEAD + INSERT(0,HEAD)
7. [Next node from list P]
P + LINK(P)
8. [Restore initial values of pointer variables P and Q]
P — SAVEP
Q + SAVEQ
Return(SAVEM)

EXERCISES SECTION 4-4 PAGE 323

1) Algorithm QUERY. This algorithm processes class records via a command


language using an associative list called STUDENT. The associative item is
the student’s name. The list items of the student record are given and
described in the exercise along with the command language syntax and
semantics. Several subalgorithms are called, but no references are made to
particular language constructs used in associative list processing. Instead,
functional specifications will be made as appropriate. This permits a variety
of implementations including simulation using other data structures.

1. [Process all commands]


Repeat while there remains input data
Read(COMMAND,STUDENT_NAME)
Select case (COMMAND)
Case ‘INSERT’:
Call INSERTION(STUDENT_NAME)

a
Case ‘DELETE’:
Call DELETION(STUDENT_NAME)
Case ‘UPDATE’:
Call UPDATE(STUDENT_NAME)
Case 'OUTPUT!:
Call OUTPUT(STUDENT_NAME)
Default:
Write(‘INVALID COMMAND’)
2. [Finished]
Exit

Procedure INSERTION(STUDENT_NAME). Given the associative


list item, STUDENT_NAME, this procedure creates a record which can be
referenced by the item.

1. [Get record of information]


Read(ID#,COL)
2. [Insert information into student record]
ID of STUDENT <STUDENT_NAME> «+ ID#
COLLEGE of STUDENT <STUDENT_NAME> «+ COL
MARK of STUDENT <STUDENT_NAME> <—
GRADE of STUDENT <STUDENT_NAME> «+ 0
3. [Finished]
Return

Procedure DELETE(STUDENT_NAME). Given the associative list


item, this procedure deletes the record associated with it and returns it to the
availability list.

1. [Delete record]
LINK(pred of record STUDENT <STUDENT_NAME>) —
LINK(record STUDENT <STUDENT_NAME>)
2. [Free record]
DISPOSE(record STUDENT <STUDENT_NAME>)
3. [Finished]
Return

Procedure UPDATE(STUDENT_NAME). Given an associative list


item, this procedure performs an update on the corresponding record.

1. [Get updated information]


READ(ASSIGN#,NEWMARK)

4-0
2. {Record information]
MARK[ASSIGN#| of STUDENT <STUDENT_NAME> + NEWMARK
GRADE of STUDENT<STUDENT_NAME> +
GRADE of STUDENT <STUDENT_NAME> + NEWMARK
3. [Finished]
Return

Procedure OUTPUT(STUDENT_NAME). Given an associative list,


this procedure outputs all records or that of a particular student. The name
of the student, or the code word ‘ALL’ is contained in the variable
STUDENT_NAME.

1. [Code word to print all records?]


If STUDENT_NAME = 'ALL!
then Repeat for all associative lists
TEMP + address of first record in associative list
Repeat while TEMP 54 NULL
Write(NAME(TEMP),ID(TEMP),COL(TEMP),
MARK(TEMP),GRADE(TEMP))
TEMP «+ LINK(TEMP)
else Write(RECORD of STUDENT <STUDENT_NAME>)
2. [Finished]
Return

bo~—- program query(input,output);

{ This program processes class records for a query system by simulating an


associative list with based storage and a hashing method. The four input
commands allowed by this system are INSERT, DELETE, UPDATE, and
OUTPUT.

type string = packed array([1..80] of char;


pointer = fcell;
cell = record
link: pointer;
contents : record
name:string;
college:string;
id:integer;
mark : array[1..10] of integer;
grade:integer
end
end;

4-41
var studentname,command:string;
save, i:integer;
loc:pointer; A
table:array[0..9] of pointer;

(GABBBE BEEBE ESR ABO EOEDEBE EOS EES EE HEB Ean bobbin s44}
#include 'length.i!;
[EBB B
BSH HE ECE E
ESSE BE HOUSES OSHS EEE FEED Ha olor ints }

procedure get(var word:string);

{ This procedure reads data from the current input line until a blank or and
end of line is detected. }

var i,j:integer;
ch:char;

begin
{ read data }
ices]:
ch :== ’?’:
while (i < 80) and (ch <> ’’) and (not eoln) do
begin
read(ch);
word|i] := ch;
i:=i+1
end;
{ adjust to accommodate for blank }
if not eoln
then i:=1-1;
{ set string delimiter }
word|i] := ’|’;
{ pad with blanks }
for }:=1+ 1to 80 do
word|j] :=
end;

Gadaciaciadadeadadedadace taedadatitataetaet tata

procedure insertion(loc:pointer;studentname:string;save:integer);

{ This procedure inserts a new record associated with studentname into the
equivalence class indexed by save if the insertion is unique. }

4-h2
var p:pointer;
isinteger;

begin
{ check for multiple insertions}
if loc <> nil
then begin
{ output error message }
writeln;
write(’**#ERROR#*** ATTEMPTED INSERTION OF RECORD ’);
writen’ ASSOCIATED WITH ’ studentname:length(studentname));
writeln(’DISALLOWED BECAUSE OF MULTIPLE INSERTION’) I

readIn;
end
else begin
{ allocate new node and insert into equivalence class }
new(p);
pf-link := table[save];
table[save] := p;
pf.contents.name := studentname;
get(pf.contents.college);
readIn(pt.contents.id);
for i := 1 to 10 do
pt.contents.mark[i] := 0;
pt.contents.grade := 0;
end
end;

(SOR RE RE IE EEE REESE EE EEE EE EEE EEE EEE EEE EEE EEE EE)

procedure deletion(loc:pointer;studentname:string;save:integer);

{ This procedure deletes the student record associated with studentname from
the equivalence class indexed by save, provided the record exists. }

var temp:pointer;

begin
{ Check if record exists }
if loc = nil
then begin
{ output error message }
writeln;
write(’**#ERROR*** ATTEMPTED DELETION OF RECORD ’);
writeln(’ ASSOCIATED WITH ’studentname:length(studentname));

4-43
writeln(’DISALLOWED BECAUSE OF MISSING INSERTION’);
readIn
end
else begin
readln;
{ delete record }
if table[save] = loc
then table[save] :== loct.link
else begin
temp := table[save];
while tempf.link <> loc do
temp := tempf.link;
tempf.link := locf.link
end;
cdispose(loc)
end
end;

(SS ER EE EE EE EE IE EE EE EE EE)

procedure update(loc:pointer;studentname:string);

{ This procedure updates a given student's record. }

var assign, newmark:integer;

begin
{ Check for valid student name }
if loc = nil
then begin
writeln;
write(’***ERROR##* ATTEMPTED UPDATE OF RECORD ’);
writeln(’ASSOCIATED WITH ’ studentname:length(studentname));
writeln(’DISALLOWED BECAUSE OF MISSING INSERTION. ’);
readin
end
else begin
readIn(assign,newmark);
loct.contents.mark{assiga] = newmark;
locf.contents.grade := locft.contents.grade + newmark
end
eud;

[BREESE EE EEE EERIE EEA IEEE EA EATS IEEE EES IEEE EAST AE ATTA ESSE AAAS

h-hh
procedure out(loc:pointer;studentname:string);

{ This procedure prints eighter a particular student’s record or all records. }

var i,j:integer;

begin
{ Check for all students }
if studentname = ’alll’
then for i := 0 to 9do
begin
loc :== table[il;
while loc <> nil do
begin
writeln;
writeln(’“NAME: ’:9,locf.contents.name:length
(lect .contents.name));
writeln(’;COLLEGE: ’:9 loct.contents.college:length
(loc f .contents.college));
writeln(’ID: ’:9,locf.contents.id:6);
write("MARKS: °:9);
for} := 1to10do
write(loct.contents.mark|j]:6);
writeln;
writeln(’(GRADE: ’:9,locf.contents.grade:6);
loc := loct.link
end
end
else if loc = nil
then begin
writeln;
write(’**##*ERROR*** OUTPUT OF RECORD ’);
writeln(/ASSOCIATED WITH ’ studentname:length
(studentname));
writeln(’DISALLOWED DUE TO MISSING INSERTION’); ’

end
else begin
writeln;
writeln(’NAME: ’:9,locf.contents.name:length
(loc }.contents.name));
writeln(’COLLEGE: ’:9,loct.contents.college:length
{loct .contents.college});
writeln(’ID: ’:9,locf .contents.id:6);
writeln(’GRADE: ’:9,locf .contents.grade:6)
end;

b-4s
readln
end;

eB SBES Reda de ib dodnacdde ica iolbionackicgdiiaiidniiadbiccckictt)

function hash(symbol:string):integer;

{ Given a symbol of the form <initial> . <sumame> this function


generates a key by adding the ascii representations of the initial letters in the
first name and surname. }

var tl1,t2:integer;

begin
t1 := ord(symbol|1]);
t2 := ord(symbol|3});
hash := tl + t2
end;

Glacial alaciniciediadiadlaiceata acdc alec et

function student(studentn ame:string;var save:integer):pointer;

{ Given an associative item from a cell in an associative list, this procedure


returns the location of that cell. The cells are stored in a linked dictionary
with a table of 10 entries pointing to the corresponding equivalence classes. If
the associative item is not found in the list then a null pointer is returned. }

var temp:pointer;
found:boolean;

begin
{ determine index into table }
save :== hash(studentname) mod 10;
temp := table[savel;
found := false;
while (temp <> nil) and (not found) do
begin
if tempt.contents.name = studentname
then found := true
else temp := tempf.link
end;
student :== temp
end;

h-h6
EBA E EEA IGE
ES E AI ATA TIAA }
LEB O RECESS DEBE

begin
{ initializations }
for i:= 0 to9do
table[i] := nil;
{ engage loop to process all data }
while nct eof do
begin
{ read command and student name }
get(command);
get(studentname);
{ determine location of record }
loc :== student(studentname,save);
get(command);
get(studentname);
{ determine location of record }
loc := student(studentname,save);
{ call appropriate procedure to process command }
if command = ’insertion|’
then insertion(loc,studentname,save)
else if command = ’deletion|’
then deletion(loc,studentname,save)
else if command =.’update|’
then update(loc,studentname)
else if command = ’output]’
then out(loc,studentname)
else begin
writeln;
writeln(’***ERROR*** INVALID COMMAND ’
command:length(command));
writeln(’/ENTRY IGNORED’);
readin
end
end
end.

THE FOLLOWING DATA GENERATED THE FOLLOWING RESULTS:

insertion |.witkowicz arts 812156


insertion d.manegre commerce 813827
insertion k.manson arts 802572
insertion s.mcdonald arts 802000
insertion c.letilley commerce 801427

4-47
update l.witkowicz 1 85
update k.manson 1 80
update s.mcdonald 1 49
update d.manegre 1 99
update c.letilley 1 85
_ update l.witkowicz 2 88
update k.manson 2 75
update c.letilley 2 89
update d.manegre 2 98
update s.mcdonald2 25
output s.mcdonald
deletion s.mcdonald
insertion k.manson commerce 813695
deletion f.flintstone
update b.rubble 1 65
output m.mouse
delete d.duck
output all

RESULTS:

NAME: s.mcdonald
COLLEGE: arts
ID: 802000
MARKS: 49 25 0 0 0 0 0 0 0 0
GRADE: 104

*#**ERROR*** ATTEMPTED INSERTION OF STUDENT RECORD ASSOCIATED WITH k.manson


DISALLOWED BECAUSE OF MULTIPLE INSERTION

***ERROR*** ATTEMPTED DELETION OF STUDENT RECORD ASSOCIATED WITH f.flintstone


DISALLOWED BECAUSE OF MISSING INSERTION

#*##ERROR*** ATTEMPTED UPDATE OF STUDENT RECORD ASSOCIATED WITH b.rubble


DISALLOWED BECAUSE OF MISSING INSERTION.

***ERROR*** ATTEMPTED OUTPUT OF STUDENT RECORD ASSOCIATED WITH m.mouse


DISALLOWED BECAUSE OF MISSING INSERTION

***#ERROR*** INVALID COMMAND delete


ENTRY IGNORED

NAME: k.manson
COLLEGE: arts
ID: © 802572
MARKS: 80 75 0 0 0 0 0 0 0 0
GRADE: 155

NAME: c.letilley
COLLEGE: commerce
ID: 801427
MARKS: 85 89 0 0 0 0 0 0 0 0
GRADE: 174
NAME: l.witkowicz
COLLEGE: arts
ID: 812156
MARKS: 85
GRADE: 173

NAME: d.manegre
COLLEGE: commerce
ID: 813827
MARKS: 99 98
GRADE: 197

4-49
CHAPTER 5

NONLINEAR DATA STRUCTURES


EXERCISES SECTION 5-1.1 PAGE 237

Proof by induction: If we know the rule holds for a digraph of n nodes, and
we can show that it also holds for » + 1 nodes, then we have proved the rule
holds for a digraph with n or n + 1, or n + 2 or... nodes. If the number of
nodes n == 1, the rule holds because the indegree = 0, the outdegree = 0, and
the number of edges = 0. Now assume that for a graph of n nodes the sum of
indegrees of all the nodes equals the sum of outdegrees of all the nodes and
the number of edges of the graph.

CASE 1: Appending a new leaf node P to an existing node X.


When node P is appended to node X, the outdegree of X is increased by 1.
Similarly, since a path between node X and node P is created, the number of
edges of the graph is increased by 1. Also, node P has its indegree increased
by 1. Thus for a digraph of n + 1 nodes, the sum of the outdegrees of all the
nodes is equal to the sum of the indegrees of all the nodes and the number of
edges in the digraph.

CASE 2: Inserting a new node P between nodes X and Y.


The edge from X to Y is changed to an edge from X to P. This increases the
indegree of P by 1. An edge is constructed from P to Y, thereby increasing
the number of edges by 1. This also increases the outdegree of P by 1. The
indegree of Y has not changed because one incoming edge has been deleted
and one has been added. Thus for a digraph of n + 1 nodes, the sum of the
outdegrees of all the nodes is equal to the sum of indegrees of all the nodes
and the number of edges in the digraph.

0: ©) 1:

O ©

I>
Pe
> > oS
pole. ag
Vi, V4, V3

Vis V2 3

Wap 27 Mavs

The shortest distance is a path of length 2.


There is a cycle in the graph: vy, v3, V4

INDEGREE | OUTDEGREE

The elementary cycles are:


Vy, Va, V4, V1
Vi, Ya, V3, Vay V1

acyclic digraph:

NODE | NODES REACHABLE FROM NODE


Vi V1, Va, V3, V4, V5
Vo Vi, V2, Va, V4, Vo
V3 V1, V2, V3, V4, V5
V4 Vi, V2, V3, V4, V5
V5

B=2
5)

O
6) With 3 nodes, you can have two directed trees or three ordered trees.

8) Proof by Induction: If we know that the rule holds for a tree with n, terminal
nodes and we can show that it also holds for n, + 1 terminal nodes, then we
have proved the rule holds for a tree with ny or ny + 1 or ny + 2 or ... nodes.
For ny = 1 (ie. a single node in the tree) then 2(n,- 1) = 0 equals the
number of edges as expected. Now assume that for some nm, we have the
number of edges equal to 2(i¢ — 1).

CASE 1: Appending a node P to a terminal node X.


Since we want to keep the tree a complete binary tree, we must add another
node Q to X. This will increase the number of terminal nodes by 1 because

oon
we added two new terminal nodes and removed X as a terminal node. If
before we had for nz terminal nodes, 2(n, — 1) edges, we now have for ny + 1
terminal nodes, 2(n, — 1) + 2 = 2((m_ + 1) — 1) edges.

CASE 2: Inserting node P between node X and node Y.


If node Y becomes the subtree of P, we must append another node Q to P to
keep the tree as a complete binary tree. Node Q will be a terminal node, so we
have increased the number of terminal nodes by 1. We have also added 2 new
edges, one from P to Y, and one from P to Q. The number of edges from X
and Y remains the same. Before insertion we had 2(ny— 1) edges for ny
terminal nodes. For m+ 1 terminal nodes, we have 2(n,-1) + 2 =
2((n_ + 1) - 1) edges.

corresponds to Figure 61.15

5-4
corresponds to Figure 6-1.16

EXERCISES SECTION 5-1.3 PAGE 360

Proof by induction: If we can show that for some number of nodes n that
there are n + 1 null links, and from this show that for n + 1 nodes there are
(n + 1) + 1 =n + 2 null links, this then proves that the rule holds for n or n
+ lorn+2or... nodes. For n = 1, this is clear since a tree of one node has
n + 1 = 2 null links. Now assume for some tree consisting of n nodes that
there are n + I null links.

CASE 1: Appending a node P as left/right subtree of node X.


Appending node P will increase the number of nodes by 1 ton + 1. One null
link is removed from X to provide a pointer P and 2 null links are added by
node P. Therefore, we have increased the number of null links by 1 to (n + 1)
+ 1. Thus for n + 1 nodes, we now kave (n + 1) + 1 = n + 2 null links.

pep
CASE 2: Inserting node P between nodes X and Y.
The insertion of node P increases the number of nodes by 1 to n + 1. The
pointer from X to Y is changed to a poiater from X to P, and a pointer from
P to Y is created. This means that the number of null links of X and Y
remains the same, bat one null link is added to the tree from node P,
increasing the number of null links from n + 1 to (n + 1) + 1. Thus for a
tree of n + i nodes, there are (n + 1) + 1 =n + 2 nuli links.

Procedure INORDER(T). Given the root node, T, of a binary tree with


the usual node structure, this procedure iteratively traverses the tree in
inorder. A stack, S, is used and TOP is the index of the top element of S.
The function EMPTY returns true if the given stack is empty; false otherwise.

1. [Initializations]
P— T
TOP + 0
to [Engage loop to traverse tree]
Repeat thru step 4 while -EMPTY(S) or P 4 NULL
3. [Stack nodes of !eft chain]
Repeat while P 54 NULL
PUSH(S,P,TOP)
P + LPTR(P)
4. [Process node]
P + POP(S,TOP)
Write(INFO(P))
P + RPTR(P)
5. [Finished]
Return

STACK CONTENTS P VISIT P OUTPUT STRING


NA
NA NB
NA NB NC
NA NB NC NULL
NA NB -NC NULL
NA NB —NC
NA NB NC C Cc
NA —NB NULL
NA —NB
NA NB B CB
—NA ND
—-NA ND NE
—-NA ND NE NULL
—NA ND —-NE NF

b=6
—-NA ND -NE NF
—-NA ND -NE -NF NULL
-NA ND -NE -NF
—-NA ND -NE NF F CBF
-NA ND -NE
-~NA ND NE E CBFE
—-NA ND
—~NA -ND NG NULL
-NA —-ND NG
-NA -ND -NG NULL
~NA -ND -NG
—-NA -ND NG G CBFEG
-NA -ND
—-NA ND D CBFEGD
-NA
NA A CBFEGDA

INORDER 125 240 244 246 467 517 725 790 800 822 837 848 885 991

POSTORDER = 240 125 244 467 246 517 822 848 837 855 800 790 991 725

PREORDER 725 517 246 244 125 240 467 991 790 800 855 837 822 848

CONVERSE 991 855 848 837 822 800 790 725 517 467 246 244 240 125
INORDER

CONVERSE 848 822 837 855 800 790 991 467 240 125 244 246 517 725
POSTORDER

CONVERSE 725 991 790 800 855 837 848 822 517 246 467 244 125 240
PREORDER

Function SWAP(P). Given a pointer to the root of a tree, P, this function


swaps the tree as specified in the exercise and returns a pointer to the new
tree.

1. [Check for null pointer]


If P = NULL
then Return(NULL)
2. [Save left pointer]
SAVE + LPTR(P)
3. [Recursive calls to swap subtrees]
LPTR(P) + SWAP(RPTR(P))
RPTR(P) + SWAP(SAVE)
Day
4. [Finished]
Return(P)

Procedure RIGHT(X,DATA). Given the address of a designated node, X,


in an inorder threaded binary tree, and the information associated with a new
node, DATA, this procedure inserts a new node to the right of the designated
node. P is a temporary pointer variable.

1. [Create new node]


P <—="NODE
INFO(P) — DATA
2. [Adjust pointer fields|
RPTR(P) — RPTR(X)
RPTR(X) — P
LPTR(P) — -
3. [Reset successor thread if required]
If RPTR(P) > 0
then LPTR(INS(P)) — —-P
4. [Finished]
Return

Function PRES(X). Given X, the address of a node in a binary tree


threaded for preorder traversal, this function returns the address of the
preorder successor of X.

1. [Check for thread]


If LPTR(X) > 0
then Return(LPTR(X))
else Return(|RPTR(X)])

Function PREP(X). Given X, the address of a node in a binary tree


threaded for preorder traversal, this function returns the address of the
preorder predecessor of X. Function PRES, as given above, is invoked.

1. [Check for thread]


If LPTR(X) < 0
then Return(-LPTR(X))
2. [Search for predecessor]
P + HEAD
Repeat while PRES(P) X
P — PRES(P)
Return(P)

5=8
8) Function POSP(X). Given
threaded for postorder traversal,
X, the address of a node in a binary tree
this function returns the address of the
postorder predecessor of X.

1. [Check for thread or head node]


If LPTR(X) < 0 or X = HEAD
then Return(|LPTR(X)|)
2. [Check for right subtree]
If RPTR(X) < 0
then Return(LPTR(X))
else Return(RPTR(X))

Function POSS(X). Given X, the address of 2 node in a binary tree


threaded for postorder traversal, this function returns the address of the
postorder successor of X. Function POSP, as given above, is invoked.

1. [Check for thread]


If RPTR(X) <0
then Return(—RPTR(X))
2. [Search for successor]
P «+ HEAD
Repeat while POSP(P) 54 X
P — POSP(P)
Return(P)

Function COPY(T). Given a tree with head node T, this function creates
an equivalent tree, and returns a pointer to its head node. Stack S is used to
stack right branches of the original tree; stack COPYS is used to stack right
branches in the new tree. TOP is an index to S$; COPYTOP is an index to
COPYS. X, P, and Q are temporary pointer variables. The function EMPTY
returns true if the given stack is empty; false otherwise.

1. [Check for null pointer]


If. f = NULL
then Return(NULL)
2. [Initializations]
TOP «+ COPYTOP + 0
X <= NODE
RPTR(X) — X
INFO(X) — ‘HEAD!
If LPTR(T) = NULL
then LPTR(X) + NULL
Return(X)

eo
else Q <= NODE
LPTR(X) — Q
P + LPTR(T)
3. [Engage loop to traverse tree}
Repeat thru step 5 while P 54 NULL or -EMPTY(S)
4. [Descend left chain]
Repeat while P 54 NULL
INFO(Q) — INFO(P)
If LPTR(P) 4 NULL
then Y <= NODE
LPTR(Q) + Y
else LPTR(Q) — NULL
If RPTR(P) 4 NULL
then Y <= NODE
RPTR(Q) + Y
PUSH(S,RPTR(P),
TOP)
PUSH(COPYS,RPTR(Q), COPYTOP)
else RPTR(Q) — NULL
If -EMPTY(S)
then P + LPTR(P)
Q + LPTR(Q)
5. [Get right branch]
P + POP(S,TOP)
Q « POP(COPYS,TOP)
6. [Finished]
Return(X)

10) Function IPRES(X). This function returns the preorder successor of a


traversal.
given node, X, in a binary tree threaded for incrder

1. [Check for structural! left link]


If LPTR(X) > 0
then Return(LPTR(X))
2. [Search for successor|
P«-X
Repeat while RPTR(P) < 0
Pp + |RPTR(P)|
Return(RPTR(P))

5-10
Function IPREP(X). This function returns the preorder predecessor of a
given node, X, in a binary tree threaded for inorder traversal.

1. {Find node which may have X as left subtree]


ee
Repeat while P > 0
P — RPTR(P)
P + |P|
If LPTR(P) = X
then Return(P)
2. [Follow left chain until thread found]
PX
Repeat while P > 0
P — LPTR(P)
P + |P|
3. [Traverse left subtree in preorder]
Repeat while LPTR(P) > 0
P — LPTR(P)
Repeat while RPTR(P) > 0
P + RPTR(P)
Return(P)

Functicn IPOSTP(X). This function returns the postorder predecessor of


a given node X, in a binary tree threaded for inorder traversal.

1. [Check for structural right link]


If RPTR(X) > 0
then Return(RPTR(X))
2. [Search for predecessor}
Repeat while LPTR(X) < 0
X + |LPTR(X)|
Return(LPTR(X))

Function IPOSTS(X). This function returns the postorder successor of a


given node X, in a binary tree threaded for inorder traversal.

1. [Find node which may have X as right subtree]


K+ X
Repeat while K > 0
K «+ LPTR(K)
Ks Rie
If RPTR(K) = X

a7 hs
then Return{K)
2. [Follow right chain until thread found]
Ko X
Repeat while kK > 0
K ~ RPTR(K)
K + |K|
If RPTR(K) < 0
then Return(K)
else K — RPTR(K)
Repeat while (LPTR(K) > 0) or (RPTR(K) > 0)
If LPTR(K) > 0
then K ~— LPTR(K)
‘else K + RPTR(K)
Return(K)

12) Function SIMILAR(P,Q). Given two binary trees, whose roct nodes are
reference by P and Q, this function returns true if it finds the trees to be
similar; false otherwise.

1. [Check for null pointers]


If P = NULL and Q = NULL
then Return(true)
If P = NULL or Q = NULL
then Return(false)
2. [Recursive calls with subtrees]
If SIMILAR(LPTR(P),LPTR(Q))
then Return(SIMILAR(RPTR(P),RPTR(Q)))
else Return(false)
13) Every binary tree is uniquely defined by its inorder and preorder traversals.
To see this, first consider an example. Supposed we have a preorder list
ABCDEFGH and an inorder list CBDAFEGH. Now, according to the
definition of preorder traversal, A must be the root of the tree, and according
to the definition of inorder traversal, anything preceding A must be in its left
subtree, and anything following it must be in its right subtree. So we have:

The next root indicated by the preorder list is B, and according to the inorder
list, C is its left subtree and Dis its right. We now have:

S212
This can be continued until we have:

SS ee
More formally, we can give a inductive proof. First note that a tree of 0 or 1
nodes is clearly defined by its preorder and inorder traversals. Now we can
hypothesize that if, for a given binary tree, the preorder and inorder traversals
uniquely define the root node and the nodes in the left and right subtrees of
the root, then the preorder and inorder traversals uniquely define any binary
tree. Finally we want to show that the traversals define the root node, and
the traversals indicate which nodes are in each of the left and right subtrees.
To show that the traversals define the root node, we note that according
to the definition of a preorder traversal, the first node in the preorder list
must be the root of the tree.
To show that the traversals indicate which nodes are in each of the left
and right subtrees, note that the definition of inorder traversal indicates that
the nodes in the left subtree are listed to the left of the root node, and
similarly for the nodes in the right subtree.
Therefore, every binary tree is uniquely defined by its preorder and
inorder traversals.
It can be shown in a similar manner that every binary tree is uniquely
defined by its postorder and inorder traversals, the only difference being that

SNS
the root node of the tree will be given by the last node in the postorder
traversal.
On the other hand, preorder and postorder traversal orders do not
uniquely define a binary tree. Consider the preorder traversal ABC and

7
postorder traversal CBA. The following trees all correspond to those orders:

Function BUILDTREE(INORDER,POSTORDER). Given the inorder


and postorder traversal orders of a binary tree, this procedure recursively
creates the tree and returns a pointer to it.

1. [Check for null string]


If INORDER = "
then Write(/INVALID DATA ENTRY’)
Return
2. [Allocate and initialize node]
T <— NODE
INFO(T) — SUB(POSTORDER,LENGTH(POSTORDER),1)
3. [Find location of root node in INORDER string]
J — INDEX(INORDER, INFO(T))
4. [Isolate inorder and postorder traversals of subtrees]
LEFT_IN — SUB(INORDER,1,J - 1)
RIGHT_IN «+ SUB(INORDER,1,J + 1)
LEFT POST + SUB(POSTORDER,1,J — 1)
RIGHT_POST <— SUB(POSTORDER, J, LENGTH(POSTORDER) — J)
5. [Continue to build recursively|
If LEFT IN =
then LPTR(T) — NULL
eee LETR(T)— BUILDTREE(LEFT_IN,LEFT_POST)
If RIGHT_IN ="
then RPTR(T) NULL
else RPTR(T) BUILDTREE(RIGHT_IN,RIGHT_POST)
6. [Finished]
Return(T)

5-14
14) Function COUNT(T). Given a pointer to the head node of a threaded
binary tree, T, this function counts the number of leaf nodes in that tree.

1. [Check for thread]


lite<2 0
then Return(0)
2. [Check for leaf node]
If LPTR(T) < 0 and RPTR(T) < 0
then Return(1)
3. [Descend tree recursively]
Return(COUNT(LPTR(T)) + COUNT(RPTR(T)))

15) Function KTH_PRE(T,K). This function returns a pointer to the Kth


element in the preorder traversal of the binary tree given by TT. Sub-
algorithms PUSH and POP as given in the text are used. Note that this is
merely a modification of the iterative preorder traversal procedure. EMPTY
is a function that returns true if the given stack is empty; false otherwise.

1. [Check for empty tree]


fiete—— ENOleg
then Write(‘INVALID TREE’)
Return(NULL)
2. [Check for valid K]
Ivica
then Write(‘INVALID K TOO SMALL: ' K)
Return(NULL)
oO? [Initializations]
I+ TOP + 0
Call PUSH(S,TOP,T)
4. [Process each stacked branch address|
Repeat thru step 5 while 7EMPTY(S)
5. [Get address and descend left chain]
P — POP(S,TOP)
Repeat while P 54 NULL
I+I+1
lfr—Kk
then Return(P)
If RPTR(P) 54 NULL
then Call PUSH(S, TOP,RPTR(P))
P — LPTR(P)
6. [KX was too large]
Write(INVALID K TOO LARGE: |,K)
Return(NULL)
16) Algorithm TREES. This algorithm constructs and traverses a lexically
ordered binary tree for inorder traversal. The node structure from the text is
assumed. Two sub-algorithms are invoked: INSERT inserts a node into the
tree, and INSUCC returns the inorder successor of a given node.

1, [Initializations]
HEAD <— NODE
LPTR(HEAD) — -HEAD
RPTR(HEAD) — HEAD
2. [Construct the tree]
Repeat while there remains input data
Read(NAME)
Call INSERT(HEAD,NAME)
3. [Traverse the tree]
P — LPTR(HEAD)
Repeat while P 4 HEAD
Write(INFO(P))
P — INSUCC(P)
4. [Finished]
Exit

Function INSUCC(X). This function returns a pointer to the inorder


successor of node X.

1. [Check for thread]


If RPTR(X) < 0
then Return(-RPTR(X))
2. [Branch repeatedly until left thread]
P + RPTR(X)
Repeat while LPTR(X) > 0
P + LPTR(P)
3. [Return address of successor]
Return(P)

Procedure INSERT(HEAD,DATA). This procedure inserts a new node


with information field DATA into the lexically ordered, inorder threaded
binary tree given by HEAD.

1. [Check left subtree]


If DATA < INFO(HEAD)
then (attempt insertion)
If LPTR(HEAD) < 0
then NEW <— NODE

Bale
INFO(NEW) — DATA
LPTR(NEW) — LPTR(HEAD)
RPTR(NEW) — -HEAD
LPTR(HEAD) + NEW
else Call INSERT(LPTR(HEAD),DATA)
Return
[Check right subtree]
If DATA > INFO(HEAD)
then (attempt insertion)
If RPTR(HEAD) < 0
then NEW <= NODE
INFO(NEW) «— DATA
LPTR(NEW) + — HEAD
RPTR(NEW) — RPTR(HEAD)
RPTR(HEAD) — NEW
else Call INSERT(RPTR(HEAD),DATA)
Return
[Multiple insertion attempted]
Write(/INSERTION DISALLOWED: NODE ALREADY EXISTS’)
Return

17) Procedure DIAMETER(ROOT). Given the root node of a binary tree,


this procedure computes and prints the diameter of the tree and a path of that
length. Procedure LONGST is invoked to determine the longest path. It is
assumed that the nodes have information fields of one character.

i [Initializations]
PATH
2 [Call procedure to find longest path]
Call LONGST(ROOT,PATH)
[Output result]
Write(‘DIAMETER = ',LENGTH(PATH))
Write(/PATH OF THAT LENGTH: ',PATH)
[Finished]
Return

Procedure LONGST(ROOT,PATH). Given the root node of a binary


tree, ROOT, the procedure recursively determines a longest path in the tree
and returns that path through the parameter PATH. It is assumed that the
nodes have information fields of one character.

1. [Check for null pointer]


If ROOT = NULL
then Return
2. [Determine longest paths of subtrees]
PATH ~ PATH2 — PATH © INFO(ROOT)
Call LONGST(LPTR(ROOT),PATHI)
Call LONGST(RPTR(ROOT),PATH2)
3. [Isolate longest path]
If LENGTH(PATH1) > LENGTH(PATH2)
then PATH «+ PATHI
else PATH «+ PATH2
4. [Finished]
Return

18) The tree is threaded in postorder.

ze
ean|=
r
mS

19) Function RECDEL(T,DATA). This function recursively deletes the node


with information field DATA from the lexically ordered binary
tree pointed at
by T, and returns a pointer to the new tree.

1. [Check for null pointer]


If T = NULL
then Write(/NODE NOT FOUND’)

5-16
Return(T)
2. [Has node been found]
If INFO(T) = DATA
then (empty left subtree?)
If LPTR(T) = NULL
then Return(RPTR(T))
else (empty right subtree?)
If RPTR(T) = NULL
then Return({LPTR(T))
else (both subtrees exist)
SUCC + RPTR(T)
PRED + T
(find inorder successor)
Repeat while LPTR(SUCC) +4 NULL
PRED «+ SUCC
SUCC + LPTR(SUCC)
(replace node with inorder successor)
If PRED = T
then RPTR(PRED) + RPTR(SUCC)
else LPTR(PRED) + RPTR(SUCC)
LPTR(SUCC) + LPTR(T)
RPTR(SUCC) + RPTR(T)
Return(SUCC)
3. [Branch right or left]
If DATA < INFO(T)
then LPTR(T) ~ RECDEL(LPTR(T),DATA)
else RPTR(T) — RECDEL(RPTR(T),DATA)
4, [Finished]
Return(T)

20) Procedure INSERT(ROOT,X). This procedure iteratively inserts a new


node with information field X into the lexically ordered binary tree with root
node ROOT.

1. [Check for empty tree]


If ROOT = NULL
then NEW <— NODE
INFO(NEW) + X
LPTR(NEW) «+ RPTR(NEW) «+ NULL
ROOT «+ NEW
Return
2. [Engage loop to find appropriate leaf node]
P + ROOT
If X < INFO(P)
then PTR + LPTR(P)

Bato
else PTR + RPTR(P)
Repeat while PTR 54 NULL
P+ PTR ’
If X < INFO(P)
then PTR + LPTR(P)
else If X > INFO(P)
then PTR + RPTR(P)
else Write(/DUPLICATE ENTRY’)
Return
3. [Insert node]
NEW <= NODE
INF O(NEW) + X
LPTR(NEW) + RPTR(NEW) + NULL
If X < INFO(P)
then LPTR(P) + NEW
else RPTR(P) — NEW
4. [Finished]
Return

21) Procedure RECINS(RCOT,X). This procedure recursively inserts a new


node with information field X into the lexically ordered binary tree with root
node ROOT.

1. [Check for null pointer]


If ROOT = NULL
then NEW <= NODE
LPTR(NEW) — RPTR(NEW} ~— NULL
INFO(NEW) «— X
ROOT «— NEW
Return
2. [Recursive call with appropriate subtree]
If X < INFO(ROOT)
then Call RECINS(LPTR(ROOT),X)
else If X > INFO(ROOT)
then Call RECINS(RPTR(ROOT),X)
else Write(/DUPLICATE ENTRY’)
Return
Return

Procedure CONPRE(T). This procedure recursively traverses the binary


tree given by T in converse preorder.

1. [Check for null pointer]


If T = NULL
then Return

5-20
2. [Process node}
Write(INFO(T))
3. [Traverse right subtree]
Call CONPRE(RPTR(T))
4, [Traverse left subtree]
Call CONPRE(LPTR(T))
5. [Finished]
Return

Procedure CONPOST(T). This procedure recursively traverses the


binary tree given by T in converse postorder.

1. [Check for null pointer]


if T= NULL
then Return
2. [Traverse right subtree]
Call CONPOST(RPTR(T))
3. [Traverse left subtree]
Call CONPOST(LPTR(T))
4. [Process node|
Write(INFO(T))
5. [Finisked]
Return

Procedure CONIN(T). This procedure recursively traverses the binary


tree given by T in converse inorder.

1. [Check for null pointers]


If T = NULL
then Return
2. [Traverse right subtree]
Call CONIN(RPTR(T))
3. [Process node]
Write(INTO(T))
4. [Traverse left subtree]
Call CONIN(LPTR(T))
5. [Finished]
Return

pre
EXERCISES SECTION 5-1.4 PAGE 366

1) CURRENT
INPUT STAR LEVEL
PRED LPTR
<X LEVEL LOC (PRED_LOC ) rep foe )
0 0 L
la, ONT 1Na 1 Na NT Nee NUE
2b ONT 1Na 2Nb 2 Nb 1 Na Nb NULL
3d ONT 1Na 2Nb 3Nd_ 3 Nd 2 Nb Nd ' NULL
2c 2 Ne 3 Nd
ONT 1Na 2Nb 2 Nb Ne
3e ONT 1Na2Nb 3Ne 3 Ne 2 Ne Ne NULL
3f ONT 1Na2Nb 3Nf 3 Nf 3 Ne NULL Nf
4 1 Ng 3 Nf
2 Nb
1 Na Ng
2h ONT 1Ng 2Nh 2 Nh 1 Ng Nh NULL
3j ONT 1Ng 2Nh 3Nj 3 INj eee: Nh Nj NULL
3k ONT 1Ng 2Nh 3Nk 3 Nk 3 Nj NULL Nk
2i 2 Ni 3 Nk
2 Nh Ni
31 ONT 1Ng 2Nh 3NI 3 Nit <2 Ni Nl NULL
Be a eee

Function RCONVERT(PRED_LEVEL,PRED_NAME). Given a


forest of trees whose input is in the sarne form as that required for algorithm
CONVERT, this function converts the forest into an equivalent binary tree
and returns a pointer to the tree. PRED_LEVEL is the level of the node to be
created and PRED_NAME is the name of the node to be created. The
function should initially be called with a level of 0 and name of ‘HEAD’. A
dummy set of data with level number equal to —1 is required to terminate the
function.

1. [Initialize node]
P < NODE
INFO(P) — PRED_NAME
LPTR(P) — NULL
If PRED. NAME = '/HEAD‘
then RPTR(P) + P
else RPTR(P) — NULL
2. [Read data for next node]
Read(LEVEL,NAME)
If LEVEL = -1
then Return(P)
3. [Compare level]
If LEVEL > PRED_LEVEL
then LPTR(P) — RCONVERT(LEVEL,NAME)
else If LEVEL = PRED_LEVEL
then RPTR(P) ~ RCONVERT(LEVEL,NAME)
poe
If LEVEL > PRED_LEVEL
then Write(/ MIXED LEVEL NUMBERS’)
: Return(NULL)
else PRED_LEVEL «+ LEVEL
PRED_NAME «+ NAME
4, [Return pointer to tree]
Return(P)

Procedure INSERT(N,],T). This procedure inserts the tree pointed at by


T as the Ith subtree of the node N in a binary tree equivalent of a general
tree. P is a temporary pointer and J is a counter variable.

1. [Check for valid input]


If N = NULL
then Write(/ERROR: INVALID INPUT’)
Return
2. [New tree to be Ist subtree?
Iffl=1
then RPTR(T) — LPTR(N)
LPTR(N) — T
Return
3. [Initialize with 1st subtree]
P + LPTR(N)
4. [Find (I — 1)st subtree of N]
Repeat for J = 2, 3, ..., 1=1 while P A NULL
P + RPTR(P)
5. [Subtree not found?|
If P = NULL
then Write(/ERROR: NOT ENOUGH SUBTREES')
Return
6. [Insert subtree]
RPTR(T) — RPTR(P)
RPTR(P) + T
= [Finished]
Return

Procedure DELETE(N,I). This procedure deletes the Ith subtree of a


node N in a binary tree equivalent of a general tree.

1. [Check for valid input]


If N = NULL
then Write('/ERROR: INVALID INPUT’)
Return

oe3
[Delete first subtree?]
ifl=1
then If LPTR(N) 4 NULL
then LPTR(N) — RPTR(LPTR(N))
else Write(/ERROR: SUBTREE DOES NOT EXIST’)
Return
[Initialize with first subtree]
P — LPTR(N)
[Find (I — 1)st subtree]
Repeat for J = 2, 3, ..., 1- 1 while RPTR(P) 44 NULL
P + RPTR(P)
[Check if subtree exists]
If RPTR(P) = NULL
then Write(/ERROR: SUBTREE DOES NOT EXIST’)
Return
[Delete subtree]
RPTR(P) + RPTR(RPTR(P))
[Finished]
Return

Procedure M_ARY_PREORDER(T,LEVEL). Given a binary tree with


root node, T, and its corresponding level number, LEVEL, this procedure
traverses the tree in m-ary preorder. The procedure should initially be called
with a level of 1.

1. [Check for null pointer]


If T = NULL
then Return
[Process node]
Write(LEVEL,INFO(T))
[Traverse left subtree]
Call M_ARY_PREORDER(LPTR(T),LEVEL + 1)
[Traverse right subtree]
Call M_LARY_PREORDER(RPTR(T),LEVEL)
[Finished]
Return

5-24
EXERCISES SECTION 5-1.5 PAGE 371

1) Procedure SEQ INORD(POS). Given the vector position of the root


node of a complete binary tree represented by a sequential structure, this
procedure traverses the tree in inorder. MAX is the last index position in the
vector.

1. [Check for invalid position]


If POS > MAX
then Return
2. [Traverse left subtree]
Call SEQ_INORD(2 * POS)
3. [Process node]
Write(INFO|[POS])
4. [Traverse right subtree]
Call SEQ_INORD(2 * POS + 1)
5. [Finished]
Return

2) Procedure SEQ _POST(POS). Given the vector position of the root node
of a preorder sequentially stored binary tree, this procedure traverses the tree
in postorder.

1. [Check for invalid position]


If POS < 1 or PCS > MAX
then Return
2. [Traverse left subtree]
If -TAG[POS]
then Call SEQ_POST(POS + 1)
3. [Traverse right subtree]
If RPTRIPOS] 4 0
then Call SEQ_POST(RPTR[POS})
4. [Process node]
Write(INFO[POS])
5. [Finished]
Return

3) Procedure PATH(X,Y). Given a FATHER vector representation of a


binary tree, and X and Y, the indices of two nodes in the tree, this procedure
finds a path (direct or indirect) from node X to node Y. It is assumed that
there are N nodes in the tree, and that an entry of zero in the vector denctes
the root of the tree. Two stacks are used: SX, indexed by TOPX, and SY,
indexed by TOPY.

Dr 2D
[Check for valid nodes]
If (0 <X < Nand0 <Y <N)
then Write(/ILLEGAL NODE INDEX’)
Return
[Stack path from X to Y or HEAD]
TOPX + 1
SX[TOPX] — X
Repeat while SX[TOPX] 0 and SX[TOPX] 4 Y
TOPX + TOPX + 1
SX[TOPX] — FATHER|SX[TOPX -1]]
[If required, stack path from Y to X or HEAD]
TOPY = 1
SY[TOPY] + Y
Repeat while SY[TOPY] 0 and SY[TOPY] 4 X
TOPY — TOPY +1
SY[TOPY] — FATHER[SY[TOPY — 1]]
[Delete redundant paths]
If SY[TOPY] = X
then TOPX+1
else If TOPX ~ 1 and TOPY 41
then Repeat while SX[TOPX - 1] = SY[TOPY - 1]
TOPX
+ TOPX - 1
LORY = TOPY 1
[Print path from X to Y|
Repeat for l=) 2 a TOPK = 1
Write(SX{]])
Repeationl=—TOPY.tOPy 1.4
Write(SY[I])
o3 [Finished]
Return

Note that it is possible to use a single array and fill it from both directions
rather than using two arrays. This would lower memory requirements.

EXERCISES SECTION 5-2.1 PAGE 384

ALL OPERATIONS:
If both operands are constants, then a new constant node representing
the result of the constant expression should be created.

5=26
'_I- If the second operand is zero, then result is evaluated to yield the first
operand only. If the first operand is zero, then the result is evaluated to yield
the second operand, as a subtree of the unary minus.

's'. If either of the operands is zero, then the result is evaluated to a


constant node equal to zero. If one of the operands is one, then the result is
evaluated as the other operand only.

‘/': Tf the first operand is zero, then the result is evaluated to a constant
node equal to zero. If the second operand is zero, then an error condition
should be raised. It the second operand is one, then result is evaluated as the
first operand only.

't'; If both operands are zero, then an error condition should be raised. If
the second operand is zero then the result is evaluated to a constant node
equal to one. If the second operand is one or the first operand is zero or one,
then the result is evaluated as the first operand only.

'g!: If the operand is a constant, then the negative of the constant should be
stored in the symbol table and the unary minus operator removed.

2) The following modifications are necessary to handle differentiation with


respect to the exponentiation operator: In step 5 add the following case

Case 7: (exponentiation) °
TEMP1 + CREATE2(MAKE_NODE('~'),RPTR(ROOT),
MAKE_NODE('1'))
TEMP2 + CREATE2(MAKE_NODE('{!),LPTR(ROOT), TEMP1)
TEMP3 — CREATE2(MAKE_NODE('*!), RPTR(ROOT), TEMP2)
TEMP4 «+ CREATE2(MAKE_NODE('*'),OPERAND1,TEMP3)
TEMP5 + CREATE1(MAKE_NODE('LN’),LPTR(ROOT))
TEMP6 + CREATE2(MAKE_NODE('*'), TEMP5,OPERAND2)
TEMP7 — CREATE2(MAKE_NODE('t!), LPTR(ROOT),
RPTR(ROOT))
TEMP8 «+ CREATE2(MAKE_NODE('*'), TEMP6,TEMP7)
Return(CREATE2(MAKE_NODE('+!),
TEMP4, TEMP8))
3) The following modifications are necessary to include the trigonometric
functions sin, cos and tan in function DIFFER: Add the following cases to
step 5 assuming the given symbol table:
TYPE MEANING
constant
variable
+ (addition)
— (subtraction)
* (multiplication)
/ (division)
t (exponentiation)
9 (unary minus)
LN (logarithm)
SIN
COS
AON TAN
OoPCMNABMA
Se

Case 10: (sin)


TEMP1 + CREATE1(MAKE_NODE('COS'), RPTR(ROOT))
Return(CREATE2(MAKE_NODE('*!), OPERAND2,TEMP1))
Case 11: (cos)
TEMP1 + CREATE1(MAKE_NODE('SIN’),RPTR(ROOT))
TEMP2 «+ CREATE1(MAKE_NODE('6'),
TEMP1)
Return(CREATE2(MAKE_NODE('*'), OPERAND2,TEMP2)
Case 12: (tan)
TEMP1 + CREATE1(MAKE_NODE('COS'),RPTR(ROOT))
TEMP2 + CREATE2(MAKE_NODE('t!), TEMP1,2)
TEMP3 «+ CREATE2(MAKE_NODE(’ /'),1,TEMP2)
Return(CREATE2(MAKE_NODE('*'), OPERAND2,TEMP3)
Procedure OP TIMIZE(E). This recursive procedure simplifies the
unoptimized expressions given by E. EVAL is a function which returns the
numerical result obtained after symbollically evaluating a given expression.
Simplification rules are given in the following table.

__ SIMPLIFICATIONS
O+x—-x x+0—-x
0-x— 6x x-O—-+x
0*x—0 x*0—-0
1*x—-x x*¥1—41
0/x-0 xf/1l—+x
xfo—-l 0Otjx—-0
xfl—-x lftx-1l
0x+ -x

5-28,
1. [Check for empty tree or leaf node]
If E = NULL
then Return
If TYPE(E) = 0
then Return
2. [Breakdown problem|
Call OPTIMIZE(LPTR(E))
Call OPTIMIZE(RPTR(E))
3. [Check for unary /binary operators]
If LPTR(E) 54 NULL and RPTR(E) 4 NULL
then (check for two constants)
If TYPE(LPTR(E)) = 0 and TYPE(RPTR(E)) = 0
then Select case (TYPE(E))
Case '+’:
RESULT — VALUE(RPTR(LPTR(E))) +
VALUE(RPTR(RPTR(E)))
Case !—!:
RESULT — VALUE(RPTR(LPTR(E))) -
VALUE(RPTR(RPTR(E)))
Case '*!:
RESULT — VALUE(RPTR(LPTR(E))) *
VALUE(RPTR(RPTR(E)))
Case !/':
RESULT + VALUE(RPTR(LPTR(E))) /
VALUE(RPTR(RPTR(E)))
Case? feo
RESULT — VALUE(RPTR(LPTR(E))) t
VALUE(RPTR(RPTR(E)))
TYPE(E) + 0
VALUE(RPTR(E)) + RESULT
else Select case (TYPE(E))
Case '+!:
If EVAL(LPTR(E)) = 0
then E+ RPTR(E)
else If EVAL(RPTR(E)) = 0
then E+ LPTR(E)
Case '—':
If EVAL(LPTR(E)) = 0
then TYPE(E) +- 6
LPTR(E) — NULL
else If EVAL(RPTR(E)) = 0
then E+ LPTR(E)
Case '+!:
If EVAL(LPTR(E)) = 0 or EVAL(RPTR(E)) = 0
then TYPE(E) + 0

pee
VALUE(RPTR(E) < 0
else If EVAL(LPTR(E)) = 1
_then E+ RPTR(E)
else If EVAL(RPTR(E)) = 1
then E+ LPTR(E)
Case ' /':
If EVAL(RPTR(E)) = 0
then Write(/ERROR: DIVISION BY ZERO’)
E + NULL
else If EVAL(LPTR(E)) = 0
then TYPE(E) — 0
VALUE(RPTR(E)) — 0
else If EVAL(RPTR(E)) = 1
then E+ LPTR(E)
Case 'f!:
If EVAL(LPTR(E))=0 and EVAL(RPTR(E))=0
then Write(/ERROR: INVALID EXPONENT’)
E «+ NULL
else If EVAL(RPTR(E)) = 1
then E+ LPTR(E)
else IfEVAL(LPTR(E)) =
EVAL(RPTR (E)) = 0
then TYPE(E) < 0
VALUE(RPTR(E)) < 1
else (handle unary operators)
If TYPE(RPTR(E)) = 0
then RESULT + -VALUE(RPTR(E))
TYPE(E) + 0
VALUE(RPTR(E)) — RESULT
4. [Finished]
Return
The algorithm for symbolic integration cannot be based on simple methods
and rules as set out in a formalized manner as in the case of symbolic
differentiation. Integration of + and — is trivial since the answer is just the
sum or difference of the integrals of the operands. For the other operators, it
would be best to try different methods of integration with some intuition as to
which one to use, until a method is found which works. This would also entail
a method of deciding when one particular method has failed. The result
would have to be checked to see if it is valid, since the result may not always
be defined. Even if we can’t find the integral, we cannot say that the
expression is non-integrable, since there are integrable expressions which
cannot be integrated symbolically.

3-30
Procedure MIN_PAREN(T,PRED_PREC). Given T, the address of a
tree expression, and PRED_PREC, the precedence of the previous operator,
this procedure prints the equivalent infix notation of that expression such that
it contains 2 minimum number of parentheses. The procedure should initially
be called with PRED_PREC = 0. This procedure assumes 2 node structure
with fields LPTR, TYPE, PRECEDENCE, and RPTR. It is also assumed
that an OPERATOR vector containing the string representations of the
operators exists, and may be indexed by operator types. Given below is a
table of the operators and their respective precedence levels.

TYPE PRECEDENCE MEANING


0 constant /variable
+ (addition)
— (subtraction)
* (multiplication)
/ (division)
t (exponentiation)
kr
an
WH ON
ee
em
Wh
he § {unary minus)

1. [Check for null pointer]


lice Nin
then Write(/INVALID EXPRES SION’)
Return :
2. [Check for constant or variable]
If TYPE(T) = 0
then Write(SYMBOL(RPTR(T})
Return
3. [Print opening bracket if necessary]
If PRECEDENCE(T) < PRED_PREC
then Write('(')
4. [Traverse left subtree]
Call MIN_PAREN(LPTR(T),PRECEDENCE(T))
5. [Process node]
Write(OPERATOR[TYPE(T)])
6. [Traverse right subtree]
Call MIN_PAREN(RPTR(T),PRECEDENCE(T))
7. [Print closing bracket if necessary]
If PRECEDENCE(T) < PRED_PREC
then Write(‘)')
8. [Finished]
Return

Sto
EXERCISES SECTION 5-2.2 PAGE 392

1) Assume that FLAG = true, N = 1, and SYMBOLS(HEAD[1]) = '2Z2ZZZ2!'.


This information portion of the head node is such that any new name which is
inserted into the tree will always be inserted to the left of the list head.

NAME ak P
DO NZZ2ZZ22Z NDO
ELSE NZZZZZZ
NDO NELSE
GET NZZZZZZ
NDO
NELSE NGET
PUT NZZZZZZ
NDO
NELSE
NGET NPUT
THEN NZZZZZZ
NDO
NELSE
NGET
NPUT NTHEN
DECLARE NZZZZZZ
NDO NDECLARE
FIXED NZZZZZZ
NDO
NELSE
NGET NFIXED
FLOAT NZZZZZZ
NDO
NELSE
NGET
NFIXED NFLOAT
BINARY NZZZZZZ
NDO
NDECLARE NBINARY
CHARACTER NZZZZ2ZZ
NDO
NDECLARE
NBINARY NCHARACTER
BASED NZZZZZZ
NDO
NDECLARE
NBINARY NBASED
POINTER NZZZZ2ZZ
NDO
NELSE
NGET
NPUT NPOINTER

The resulting tree is:

HEAD([1]

INIAAAAAES

program symtab(input,output);

{ This program is designed to implement algorithm table given in the text. It


reads the block level, flag, name, and data fields. head[{n] is initialized and the
proper operation is performed by calling the procedure table. The tree is
traversed in inorder to check program validity. }

type string = packed array[1..80] of char;


ptr = fnode;
node = record
Iptr:ptr;
sy mbols:string;
info:string;
rptr:ptr
end;
header = array0..9] of ptr;

ooo
var n:integer;
flag:boolean;
data,name:string;
head:header;

FEBS HESS EA CBEOBE EAE B EA EE CHESS Ha boi der beiadildiinaiictocics }

#include ‘length.i';
DOBBS ESSE Sn ma Ha ado a OBESE EB EB Eo rbbibonbek bic |

procedure get(var text:string);

{ This procedure reads data from the current line in the input data until a
blank or eoln is reached, and returns the data through the parameter text. }

var ch:char;
1,J:integer;

begin
{ read data until eoin or blank is detected }
eles 2)
ele
while (ch <> ' ‘) and (i < 80) and (not eoln) do
begin
read(ch);
textfi] :== ch;
i:=i+1
end;
{ adjust cursor for blank }
ifch = !!
then i := 1-1;
{ set delimiter }
text[i] :-= ‘|’;
{ pad with blanks }
forj := i+ 1 to 80 do
text (j)o==0'!
end;

GER E ESSEC ESE E EERIE EE ICES IA EIA A HIE HEE SATIS IA EES HE 4 & }

function create:ptr;

{ This function sets up a head node for a new block level and returns a
pointer to the head node. }

var p:ptr;

5-34
begin
new(p);
pt-symbols := 'ZZZZZ2Z|';
pt.info := 'HEAD|';
pf.Iptr := nil;
pft.rptr := nil;
create := p
end;

Sadedcinedcinciacincihiiaiatacninadaincadilntadiadetidetiedicietiaetiataeedatiatita ated did caec

function table(n:integer;insert:boolean;name:string;var data:string):boolean;

{ This procedure inserts or searches for name in the symbol table according to
the value of the boolean variable insert. }

var parent,t,p:ptr;

begin
{ initializations }
t := head[n];
{ search for name }
while t <> nil do
begin
{ compare given item with node }
if name < tf.symbols
then begin
parent := t;
t:== tf.Iptr;
if t = nil
then if insert
then begin
{ create leaf node and insert it }
new(p);
pt.symbols := name;
pt.info := data;
pft.Iptr := nil;
pt.rptr := nil;
parentf.Iptr := p;
table := true
end
else table := false
end
else if name > tf.symbols
then begin

5735
parent := t;
t :=t]irptr;
if t = nil
then if insert
then begin
new(p);
pt.symbols := name;
pt.info := data;
pt.lptr := nil;
pt.rptr := nil;
parent{.rptr := p;
table := true
end
else table := false
end
else begin
if insert
then table := false
else begin
table := true;
data := tf.info
end;
t := nil
end
end
end;

FEE E EEE SEES EESSE ES SOE ERIE TES EE EEE IEE EE EE)

procedure inord(t:ptr);

{ This procedure recursively traverses the tree in inorder. }

begin
{ check for null pointer }
if t <> nil
then begin
{ traverse left subtree }
inord(tf.Iptr);
{ print contents of node }
writeln(/ NODE: ':7,tt.symbols:length(tt.symbols),! ':2,
tt.info:length(tt .info));
{ traverse right subtree }
inord(tt.rptr)
end
end;
Br 36
SESE OSE EEEEEE GEESE EAI A SATIS}
GeO EEE E REED EERE SEEDEE

begin
{ process all data }
while not eof do
begin
{ read data }
get(name);
get(data);
readin(n, flag);
{ initialize head node if necessary }
if head[n] = nil
then head[n] := create;
{ handle insertion/search }
if flag .
then if table(n,flag,name,data)
then begin
writeln;
writeln(‘INSERTION SUCCESSFUL’);
writeln(/ NAME = ‘,name:length(name));
writeln(/DATA = ' data:length(data))
end
else begin
writeln;
writeln(/ MULTIPLE INSERTION UNSUCCESSFUL’);
writeln(/NAME = ' name:length(name));
writeln('DATA = ' data:length(data))
end
else if table(n,flag,name,data)
then begin
writeln;
writeln(/'SEARCH SUCCESSFUL’};
writeln(/ NAME = ‘ name:length(name));
writeln(’DATA = 'data:length(data))
end
else begin
writeln;
writeln(/SEARCH UNSUCCESSFUL’);
writeln(/NAME = ' name:length(name))
end
end;
{ traverse tree in inorder to assure program correctness }
writeln;
writeln;
writeln(/INORDER TRAVERSAL! );
inord(head{1])
end.

THE FOLLOWING DATA PRODUCED THE FOLLOWING RESULTS:

DO KEYWORD 1 true
ELSE KEYWORD 1 true
GET KEYWORD 1 true
PUT KEYWORD 1true
THEN KEYWORD 1 true
DO KEYWORD 1 true
DECLARE KEYWORD 1 true
FIXED KEYWORD 1true
FLOAT KEYWORD 1 true
BINARY KEYWORD 1true
CHARACTER KEYWORD 1true
BASED KEYWORD 1true
DO KEYWORD 1 false
POINTER KEYWORD 1true
IF KEYWORD 1false
RESULTS:

INSERTION SUCCESSFUL
NAME = DO
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = ELSE
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = GET
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = PUT
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = THEN
DATA = KEYWORD

5-38
MULTIPLE INSERTION UNSUCCESSFUL
NAME = DO
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = DECLARE
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = FIXED
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = FLOAT
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = BINARY
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = CHARACTER
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = BASED
DATA = KEYWORD

SEARCH SUCCESSFUL
NAME = DO
DATA = KEYWORD

INSERTION SUCCESSFUL
NAME = POINTER
DATA = KEYWORD

SEARCH UNSUCCESSFUL
NAME = IF

INORDER TRAVERSAL
NODE: BASED KEYWORD
NODE: BINARY KEYWORD
NODE: CHARACTER KEYWORD
NODE: DECLARE KEYWORD

Dg
NODE: DO KEYWORD
NODE: ELSE KEYWORD
NODE: FIXED KEYWORD
NODE: FLOAT KEYWORD
NODE: GET KEYWORD
NODE: POINTER KEYWORD
NODE: PUT KEYWORD
NODE: THEN KEYWORD
NODE: ZZZZZZ HEAD

Function LOOK_UP(HEAD,N,INSERT,NAME,DATA). Given the


parameters as described in function TABLE, this function performs the
required operation: insertion or look-up, on the tree structured symbol table
local and global to block level N. The function returns true if the operation is
successful; false otherwise.

1. [Requested operation is insertion?]


If INSERT
then Return(TABLE(HEAD,N,INSERT,NAME,DATA))
2. [Perform look-up]
FOUND + false
Repeat while (N > 0) and (7FOUND)
FOUND + TABLE(HEAD, Rene NAME,DATA)
If -FOUND
then N+N-1
Return(FOUND)

EXERCISES SECTION 5-2.3 PAGE 399

<e> —— <e> + <e>


Ce eC rt ae
=> i+ <e> + <e>
=—>iti+<e>
=—>itit+i

<e> => <e>


+ <e>
=> <e> + <e> + <e>
=—>i+ <e>+<e>
=>i+i+ <e>
=—>itit+i

5-40
<Ob> tO | eC
oe Corer aC ee
=> i+ <e>* <e>
=>i+i* <e>
—>iti*i

<C> SG a KO
<6 > 1c * eS
le <6 > ee
i+ti* <e>
Vddyd
i+i*1

BE Sse => 1 ahaa


<e> <e>

So
<e> ms <e> <e> ~

<eCe> * <e> <e> + <e> 1

1 i i i

2a) CURSOR ACTIVITY


Perform Main
Call EXPR
Call TERM
Call FACTOR
check for #. No.
check for (. No.
check for i. Yes. CURSOR + 2.
Return true from FACTOR..
check for *. No.
ee
eS
Be
Be
KS Return true from TERM.
DOWD

5-41
check for +. Yes. CURSOR ~ 3
check for #. No.
Call EXPR
Call TERM
Call FACTOR
check for #. No.
check for (. No.
check for i. Yes. CURSOR < 4.
Return true from FACTOR.
check for *. Yes. CURSOR + 5.
check for #. No.
Call TERM
Call FACTOR
check for #. No.
check for (. No.
check for 1. Yes. CURSOR + 6.
Return true from FACTOR.
Check for *. No.
Return true from TERM.
Return true from TERM.
Check for +. No.
Return true from EXPR.
Return true from EXPR.
Check for #. Yes. CURSOR + 7.
WWWWWwW
RW Return VALID from Main.
TRADPDNADAAAMMAANAANANA
WP

b) CURSOR ACTIVITY
Perform Main
Call EXPR
Call TERM
Call FACTOR
check for #. No.
check for (. No.
check for i. Yes. CURSOR + 2.
Return true from FACTOR.
Check for *. No.
Return true from TERM.
Check for +. Yes. CURSOR + 3.
Check for #. No.
Call EXPR
Call TERM
Call FACTOR
check for #. No.
eS
Bee
B&B
SB
&
HDHD
WWwWwwWWWWNHNH check for (. Yes. CURSOR + 4.

5-42
check for #. No.
Call EXPR
Call TERM
Call FACTOR
check for #. No.
check for (. No.
check for i. Yes. CURSOR + 5.
Return true from FACTOR.
check for *. No.
Return true from TERM.
check for +. Yes. CURSOR + 6.
check for #. No.
Call EXPR
Call TERM
Call FACTOR
check for #. No.
check for (. No.
check for i. Yes. CURSOR + 7.
Return true from FACTOR.
check for *. No.
Return true from TERM.
Check for +. No.
Return true from EXPR.
Check for +. No.
Return true from EXPR.
Check for ). Yes. CURSOR + 8.
Return true from FACTOR.
Check for *. No.
Return true from TERM.
Check for +. No.
Return true from EXPR.
Return true from EXPR.
Check for #. Yes. CURSOR + 9
RRR
HH
BRK
ANAM
AMAAAMAA
MAA Return VALID from Main.
OWWWWMmMAANANNNNTWNTWN

Se NS ON sgaed aide geesiSk, ORR Ce eee


¢) CURSOR ACTIVITY
1 Perform Main
1 Call EXPR
1 Call TERM
1 Call FACTOR
1 check for #. No.
1 check for (. No.
1 check for i. Yes. CURSOR «+ 2.
2 Return true from FACTOR.

5-43
check for *. Yes. CURSOR + 3.
check for #. No.
Call TERM .
Call FACTOR
check for #. No.
check for (. Yes. CURSOR + 4.
check for #. No.
Call EXPR
Call TERM
Call FACTOR
check for #. No.
check for (. No.
check for i. Yes. CURSOR + 5.
Return true from FACTOR.
check for *. No.
Return true from TERM.
check for +. Yes. CURSOR + 6.
check for #. No.
Call EXPR
Call TERM
Call FACTOR
check for #. No.
check for (. No.
check for i. Yes. CURSOR + 7.
Return true from FACTOR.
check for *. No.
Return true from TERM.
check for +. No.
Return true from EXPR.
Return true from EXPR.
check for ). Yes. CURSOR + 8.
Return true from FACTOR.
check for *. No.
Return true from TERM.
Return true from TERM.
check for +. No.
Return true from EXPR.
check for #. Yes. CURSOR + 9
Sy
eel
AY
SK
AR
BONN
D008
00:00
PB
Pep
Gh
onli
Chey.
Misi
CATES
On
SSee
ea
ae Return VALID from Main.
ee

3) < expr > u= < term > + < expr > | < term > - < expr >|< term >
< term > u== < factor > * < term > | < factor > / < term> |
< factor >
< factor > = @ < major > | < major >

5- hh
< major > < minor > t < major > | < minor > | @ < major >
< minor > ::= (< expr >) |i

program recdsnt(input,output);

{ This program is similar to the algorithm of the same name from the text,
except that two extra recursive procedures are required to handle the extra
operators. The variables are the same as those used in the text. Note that %
is used to denote exponentiation and that @ is used for the unary minus. }

type string = packed array(1..80] of char;

var cursor: integer;


indat: string;
next: char;

facdadacadaaa danced dace dint deeded deed adelaide

#include ‘getline.i';
#include ‘length.i’;
GABE ESSE SAHA EE EE SE EGC E EASE A CIA IIE HEE AS }

procedure scan;

{ This procedure gets the next input character from the indat string, and
updates relevant global variables. }

begin
next := indat[cursor];
cursor := cursor + 1
end;

[ABBE EEE OBESE E ESAS EAHA AES ECEES OSOBOE AOE EEE}
function expr:boolean; forward;
ABBE BAHAB SES SSOHnoHa Had HrdHbd bn badHEobrdor bndbnlblibicbiiicr}

function minor:boolean;

{ This function checks for (expr) or i. }

begin
if next = ‘7’
then minor := false
else if next = ‘('
then begin ‘
scan;

5-45
if not expr
then minor := false
else if next <> ')!
then minor := false
else begin
scan;
minor := true
end
end
else if next <> 'i!
then minor := false
else begin
scan;
minor := true
end
end;

FEBS SESE dG SSA EE GE onion naida aajbijiaidaiiciiok acs}

functicn major:boolean;

{ This function checks for minor, OF


%major, or @major. }

begin
if next = '@!
then begin
scan;
if next = '#!
then major := false
else if not major
then major := false
else major := true
end
else if minor
then if next = '%!
then begin
scan;
if mext qi #!
then major := false
else if not major
then major := false
else major := true
end
else major := true
else major := false
end;
5-46
FEB CHEEBE HEEB EAHA EOE ESSE EASES ECCS EEE EE EES EA EAE }

function factor:boolean;

{ This function checks for major or @major. }

begin
if next = 'Q!
then scan;
if next = '#!
then factor := false
else if not major
then factor := false
else factor := true
end;

acetate tatiana iach heat |

function term:boolean;

{ This function checks for factor or factor*term or factor/term and returns


false if the input is neither of these. }

begin
if not factor
then term := false
else if (next = '*’) or (next = '/')
then begin
scan;
if next = '#!
then term := false
else if not term
then term := false
else term := true
end
else term := true
end;

DEBE B EBB B
BREE EERE BHO E SABE BEEE ECG E CBSO E ESSERE EE bee}

function expr;

{ This function checks for term +/— expr and returns false if it is neither of
these. }

5-47
begin
if not term
then expr := false
else if (next = ‘+‘) or (next = ‘~')
then begin
scan;
if next = '#!
then expr := false
else if not expr
then expr := false
else expr := true
end
else expr := true
end;

Salada

begin
{ engage loop to process all input }
while not eof do
begin
- getline(indat);
cursor := 1;
scan;
if (expr) and (next = '#')
then writeln('VALID = ‘:10,indat:length(indat))
else writeln(/INVALID ':10,indat:length(indat))
end
end.

VALID i+1*i#f
INVALID i+#¢
VALID i*(i*i)#
VALID i/(i+i-i*i)#
VALID ((i+i))#
INVALID __ (((i+i)/i)#
INVALID _ #i/(i+i)#
VALID (@i+i)% (i-i)*(i+i*i)#
VALID i+(i+i)#
VALID @i#

5-48
4) Modifications to function EXPR to include the subtraction operator:

1. [<expr> = <term> + <expr> | <term> - <expr> | <term>]


If - TERM
then Return(false)
If NEXT = '+! or '—
then

Modifications to function TERM to include the division operator:

1. [<term> ::= <factor> * <term> | <factor> / <term> | <factor>|


If -FACTOR
then Return(false)
If NEXT = '*! or '/!
then

5) Algorithm PARSE. This algorithm performs a top-down recursive parse


on strings for the grammar described in the exercise. It is assumed that there
are no blanks in the input string. This main algorithm calls a series of
recursive sub-algorithms to perform the actual parsing.

1. [Process all input]


Repeat thru step 4 while there remains input
2. [Read line of data]
Read(INPUT)
oe [Initializations]
CURSOR + 1
Call SCAN
If STR_ASSIGN
then Write('VALID’)
else Write(/‘INVALID’)
o [Finished]
Exit

Procedure STR_ASSIGN. This procedure checks for a valid string


assignment.

1. [<string assign> ::= I ~— <substr expr>]


If NEXT I
then Return(false)
Call SCAN
If NEXT 4 '+!

5-49
then Return(false)
Return(SUB_EXP)

Procedure SUB_EXP. This procedure checks for a valid substring


expression.

1. [<substr expr> ::= <concat expr> ! <position> : < position


>]
If s>CONCAT
then Return(false)
If NEXT: 34 1!
then Return(false)
If sPOSITION
then Return(false)
Call SCAN
If NEXT St
then Return(false)
Return(true)

Procedure CONCAT. This procedure checks the validity of a


concatenation expression.

1. [<concat expr> = S|I| S||<concat expr> | I||<concat expr>]


Call SCAN
IC NEXT 5 (Sand NEXT = '!
then Return(false)
Call SCAN
If NEXT = "|!
then Call SCAN
If NEXT = "|!
then Return(CONCAT)
else Return(false}
else Return(true)

Procedure POSITION. This procedure checks the validity of position


expressions.

1. [<position> ::= <length expr> | <substr expr> ? <substr expr>|


If LENGTH_EXP
then Return(true)
else If SUB_EXP
then Call SCAN
If NEXT = /?
then Return(SUB_EXP)
else Return(false)
else Return(false)

Frocedure LENGTH_EXP. This procedure checks the validity of length


expressions.

1. [<length expr> := T | @<substr expr>]


Call SCAN
If NEXT: =('T!
then Return(true)
else If NEXT = ‘@!
then If SUB_LEXP
then Return(true)
2. [Place char back on input string and return false]
Call UNSCAN
Return(false}

Procedure SCAN. This procedure places the next character of INPUT into
NEXT. If CURSOR ever goes beyond the length of INPUT, and error has
occurred.

1. [Remove character]
NEXT + SUB(INPUT,CURSOR,1)
CURSOR + CURSOR + 1
2. [Check for error] \
If CURSOR > LENGTH(INPUT)
then Write("ERROR: CURSOR PAST LENGTH OF STRING’)
Exit
else Return

Procedure UNSCAN. This procedure places a character back on the input


string.

1. [Return character]
CURSOR + CURSOR - 1
NEXT + SUB(INPUT,CURSOR - 1,1)
Return

cg
EXERCISES SECTION 5-3.1 PAGE 411

1) M=6,R= 10,5=9
STEP| I J K | T |CROW|I] |AMAX|BMAX |SUM| C/T] |COLUMN |CCOL|T
eae O
3 ;
1 1 0 0
3 3
a 6
8
7 to 4
8
7 9
8
9
5 1
8
9
10 |2
3 5 0 0
fi 4
6 11
8 11
9
5 7
8
5 8
8
5 4
8
9
10 |3
3 9 0 0
8 4
5 10
8 10
9
10 |4
3 10 0 0
9 ts
7 6
8 10
6 19
8 11 19
9
5 8
8 12
DAeAHAaS
Kon

RESULTING STRUCTURES:

CROW CCOL

10
13 ud 11
15

10
10 10
ot 1] 19
12 12
13 13 20
14 14
15 15
16 16
17 17

ae
program matadd(input,output);

{ This program is designed to implement algorithm MATRIX_A


DDITION
from the text. All variable names are the same as in the
text. The
dimensions of the arrays are assigned as constants to facilitate easy
changes. .

const m = 4;
r= 8;
s = 10;
q = 18;

var arow,brow,crow: array[1..m] of integer;


a,acol:array|1..r] of integer;
b,beol:array[1..s] of integer;
c,ccol:array([1..qlof integer;
sum,column,amax,bmax,i,j,k,t,p:integer;

begin
{ read in arrays a and b }
for i :-= 1 to m do
readIn(arow{i] ,brow[{i]);
for i:= 1tordo
~ readIn(acolfi,
a[i]);
for i:=1tosdo
readIn(bcol[i],b[i]);
{ initializations }
Less 1:
t := 0;
{ scan each row }
while i <= mdo
begin
{ obtain row indices and starting position of next rows }
j := arow|il;
k := brow|il;
crow|i] := t + 1;
amax := 0;
bmax:= 0;
ifi<m
then begin
p:=i+1;
while (amax = 0) and (p <= m) do
begin
amax := arow(p];
p:=p+l
end;
p:=i1+ 1;

5-54
while (bmax = 0) and (p <= m) do
begin
bmax := brow|p];
p:=pt+1
end
end;
if amax = 0
then amax := r+ 1;
if bmax = 0
then bmax :=s + 1;
{ scan columns of this row }
while (j <> 0) and (k <> 0) do
begin
{ elements in same column? }
if acol[j] = bcol[k]
then begin
sum := alj] + blk];
column := acol{j];
j:=jt+)
k:=k-+1
end
else if acol{j] < bcol[k]
then begin
sum := aj];
column := acollj];
j:=jt+l
end
else begin
sum := b|k];
column := bcol|k];
k:=k+1
end;
{ add new elements to sum of matrices }
ifsum <> 0
then begin
<==t+1;
c[t] := sum;
ccol{t] := column
end;
{ end of either row? }
if) = amax
then j := 0;
ifk = bmax
then k := 0;
end;

ohne
{ add remaining elements of row }
if (j = 0) and (k <> 0)
then while k < bmax do
begin
t:=t+15
c(t] <== blk];
ecollt] := bcol|k];
k:=k+1
end
else if (k = 0) and (j <> 0)
then whilej < amax do
begin
t:=t4+1;
c[t] := alj];
ccol{t] := acollj];
J:=j+1
end;
{ adjust index to matrix C and increment row index }
ift < crow|i]
then crow[i] := 0;
1:=1+ 1;
end;
{ verification }
writeln;
writeln(’ AROW VECTOR'’:19);
for 1 := 1 tom
do
writeln(i:4,arow(i]:11);
writeln;
writeln(' ACOL VECTOR A!:28);
for i:= 1 tordo
writeln(i:4,acol[i]:11,a[i]:13);
writeln;
writeln(' BROW VECTOR':19);
for i:=
1 to mdo
writeln(i:4,brow[i]:11);
writeln;
writeln(' BCOL VECTOR B!:28);
for i:= 1 tos do
writeln(i:4,bcol[i}:11,b[i}:13);
writeln;
writeln(’ == CROW VECTOR’:19);
for i := 1 to m do
writeln(i:4,crow(i]:11);
writeln;
writeln(' CCOL VECTOR C’:28);

5-56
for
i := 1 to
q do
writeln(i:4,ccol|i]:11,c[i]:13)
end.

AROW VECTOR
1

AaAnkr
WD w
oHown

ACOL VECTOR >


3


a

NA
SOMNHA
WHE
_ he
A
NPRWORN
AWNnNOoORONNOOD

BROW VECTOR

Dm
Wh
ne re
ow
ork

BCOL VECTOR

KE
WD
OSOOntnanFF
Re
PWN
ane
NP

Sea]
CROW VECTOR
1 1
2 5
3 9
4 10
‘8 13
6 15

CCOL VECTOR C
1 3 6
Z 4 4
3 5 9
4 L 1
5 1 11
6 4 ¢
7 5 8
8 7 4
9 1 10
10 Z 6
11 3 19
12 4 8
13 I 20
14 rf 2
15 4 3
16 5 1
ug 7 5
18 0 0
19 0 0

program conmat(input,output);

{ This program is designed to implement algorithm CONSTRUCT_MATRIX


from the text. All variable names remain as in the text. }

const m = 10;
n 10;
type ptr = {matel;
matel = record
left:ptr;
up:ptr;
v:integer;
r:integer;
c:integer
end;

br 56
var row,column,value:integer;
arow:array([1..m] of ptr;
acol:array[1..n] of ptr;
p,q,temp:ptr;
i:integer;

begin
{ initialize matrix structure }
for i := 1 to mdo
begin
new(p);
pft.c := 0;
pt.left := p;
arow|i] := p
end;
for i:= 1tondo
begin
new(p);
pft.r := 0;
pt.up := p;
acolli] := p
end;
{ obtain information for matrix elements and insert them }
while not eof do
begin
readIn(row,column,value);
{ allocate and initialize node }
new(p);
p{.t := row;
pft.c := column;
pt.v := value;
{ find new node's position in row list }
q := arow(pt.rl;
temp := qf.left;
while pf.c < tempf.c do
begin
q := qf.left;
temp := qf.left
end;
pt.left := temp;
qt.left := p;
{ find new node's position in column list }
q := acoll[pt.c];
temp := qf.up;

§2oa
while pf.r < temp{.r do
begin
q := qt.up;
temp := qf.up
end;
pf.up := temp;
qf.up := q
end
end.

A B
Ve tbe tee: Bane. PRODUCT
Sipe. Ss Sete ot 0
20 Oe ed { 180
Ora th2S Gera ee

ie Sa?
Grieg dF 33
0

Oe tee es at3
LOetcne haucs
0

5-60
20
AN 20
180

N
rt
N

~~
iD
lo)

x
<x

ft
co NN 56
4 64

16
Orn

NNN

18
rote
ws ComN

NANNN

etc.

. 61
Algorithm MATRIX_MULTIPLICATION. Given sparse matrices A
and B represented by vectors A and B with row and column indices AROW
and ACOL, BROW and BCOL respectively, this algorithm forms the matrix
product C = A X B. A has dimensions M X T and B has dimensions
SX
N, therefore C will have dimensions M x N. A has R non-zero elements
and
B/has S non-zero elements.

1. [Initializations]
L+0O
2. [Scan all rows of A]
Repeat thru step 5 for] = 1, 2, ..., M
3. [Determine beginning of rows.]
CROW[L] —L +1
P + AROWII]
AMAX «+ O
Repeat for Z = 1+ 1,1 + 2, ..., M while AMAX = 0
AMAX ~— AROW(Z]
If AMAX = 0
then AMAX+R+1
4. [Scan all columns of B]
IfP 340
‘then’ Repeat for J = 1, 2, ..., T
PRODUCT + 0
(Scan thru all row/column entries)
Repeat for K = P, P + 1, .... AMAX - 1
COL + ACOLIK]
Q + BROW|COL]
BMAX + 0
Repeat for Z = COL + 1, COL + 2, ..., T while BMAX = 0
BMAX + BROW|Z]
If BMAX = 0
then BMAX +S+1
O40
then Repeat while Q < BMAX and BCOL[Q] < J
Q<-Q+1
If BCOL[Q] = J
then PRODUCT — PRODUCT + A{J] * B[Q]
If PRODUCT + 0
then L+L+1
C[L] — PRODUCT
CCOLIL] + J
5. [Adjust row vector if necessary]
If T < CROW|]]
then CROWJ|I] — 0
6. [Finished]
Exit
5>62
5) Algorithm MATRIX_ADDITION. Given pointer arrays AROW, ACOL,
BROW, and BCOL pointing to multi-linked representations of sparse matrices
A and B with dimension M X N, this algor!:hm forms the representation of
the sum matrix C = A + B. Pointer arrays CROW and CCOL are used to
point to rows and columns of matrix C which also has dimension M XN.

1. [Set up head nodes for row lists]


Repeat for I = 1, 2, ....M
CROW|]] <= MATRIX. ELEMENT
C(CROW|]]) — 0
LEFT(CROW|I]) — CROW[]]
2. [Set up head nodes for column lists]
Repeat for J = 1, 2, ...,N
CCOL|J] <= MATRIX_ELEMENT
R(CCOLIJ}) + 0
UP(CCOLIJ]) — CCOLIJ]
3. [Scan each row]
Repeat thru step 4 for I = 1, 2, ....M
4. [Scan each column entry]
P + LEFT(AROW|I])
Q + LEFT(BROW|I])
A — CROW|I]
Repeat while R(P) 4 0 or R(Q) #0
If C(P) > C(Q)
then RESULT + V(P)
INDEX + C(P)
P + LEFT(P)
else If C(P) < C(Q)
then RESULT + V(Q)
INDEX + C(Q)
Q + LEFT(Q)
else RESULT + V(P) + V(Q)
INDEX + C(P)
P + LEFT(P)
Q + LEFT(Q)
NEW <= MATRIX_ELEMENT
R(NEW) + I
C(NEW) + INDEX
V(NEW)+ RESULT
LEFT(NEW) + CROWII]
LEFT(A) + NEW
UP(NEW) + UP(CCOL[INDEX])
UP(CCOL|INDEX]) + NEW
A + NEW
5. [Finished]
Exit
6) Algorithm MATRIX_TRANSPOSE. Given pointer array ACOL and
AROW pointing to a multi-linked representation of sparse matrix A with
dimensions M X N, this algorithm forms the representation of B = AT.
Pointer arrays BROW and BCOL are used to point to rows and columns of
matrix B.

1. [Set up head nodes for row lists]


Repeat for b="1/2,5..4, N
BROW(I] <= MATRIX_ELEMENT
C(BROWII]) — 0
LEFT(BROW|I]) — BROW|]]
2. [Set up head nodes for column lists]
Repeat for J = 1, 2, ....M_
BCOL|J] <=} MATRIX_ELEMENT
R(BCOL|J]) — 0
UP(BCOL|J]) — BCOL|J]
3. [Scan all rows]
Repeat thru step 4 for I = 1, 2, ...,M
4, [Scan each column entry]
P + LEFT(AROW|I})
Q + BCOL|I]
Repeat while R(P) 0
NEW <= MATRIX_ELEMENT
R(NEW) «< C(P)
C(NEW) « R(P)
V(NEW) « V(P)
LEFT(NEW) + LEFT(BROW[C(P)])
LEFT(BROW|C(P)]) — NEW
UP(NEW) + BCOL|R(P)]
UP(Q) — NEW
P + LEFT(P)
Q «-— NEW
5. [Finished]
Exit

5-64
EXERCISES SECTION 5-3.2 PAGE 421

1) Procedure RANGE_PAGING(PAGES). This procedure is similar to


procedure PAGING, with the exception that this algorithm will handle ranges
of pages as well as individual pages. Besides the link field, PAGENODE now
consists of two fields, one for the first number in the range, the other for the
last number in the range. These fields are denoted PGNO1 and PGNO2. A
single page is represented when PGNO1 = PGNO2. Note that algorithm
ALLOCATE_PG must be modified slightly.

ls [Process all page numbers]


Repeat thru step 5 while PAGES A "!
2. [Obtain a page number]
P + INDEX(PAGES,'@’)
If P =0
then PAGE + PAGES
PAGES + "!
else PAGE + SUB(PAGES,1,P-1)
PAGES + SUB(PAGES,P+1)
[Obtain two separate page numbers]
P + INDEX(PAGE,’-’)
ifr =0
then TEMP1 +«< TEMP2 «+ PAGE
else TEMP1 + SUB(PAGE,1,P-1)
TEMP2 + SUB(PAGE,P+1)
[Find new node's position]
Q + NULL
R.— PAGEPTR
FOUND + false
Repeat while R 54 NULL and -FOUND
If PGN02(R) > TEMP1
then FOUND <+ true
else Q+R
R + PGLINK(R)
[Insert into list]
If R = NULL
then T +«- ALLOCATE_PG(TEMP1,TEMP2)
If, Qi54, NULE
then PGLINK(Q) — T
else PAGEPTR «+ T
PGLINK(T) — R
else If PGNOi1(R) > TEMP2
then T + ALLOCATE_PG(TEMP1,TEMP
2)
If Q 4 NULL

5-65
then PGLINK(Q) + T
else PAGEPTR + T
PGLINK(T) — R
else If TEMP1 < PGNO1(R)
then PGNO1(P) + TEMP1
else If TEMP2 > PGNO2(R)
then Q + PGLINK(R)
eit
FOUND + false
Repeat while Q 4 NULL and ~FOUND
If PGNO1(Q) > TEMP2
then FOUND < true
else T+ Q

If Q = NULL or TEMP2 > PGNO2(T)


then PGNO2(R) + TEMP2
else PGNO2(R) + PGNO2(T)
PGLINK(R) + Q
6. [Finished]
Exit

Function PAGE_STRING_RANGE(PAGEPTR). This function is


similar to function PAGE_STRING, with the exception that this function
handles two or more consecutive numbers as a range of numbers. The same
node structure as in RANGE_PAGING is assumed.

1. [Initializations]
PAGE +"!
SAVE + PAGEPTR
2. [Scan linear list]
Repeat thru step 5 while SAVE of NULL
3. [Add first page number to string.|
TEMP «+ PGNO1(SAVE)
KEEP «+ PGNO2(SAVE)
PAGES + PAGES 0 ',! 0 TEMP
4. [Search for range of numbers]
SAVE + PGLINK(SAVE)
FOUND + false
Repeat while SAVE NULL and -FOUND
If PGNO1(SAVE) 4 KEEP + 1
then FOUND < true
else KEEP «+ PGNO2(SAVE)
SAVE + PGLINK(SAVE)

5-66
5. [Add range if there is one]
If FOUND
then PAGES + PAGES 0 '-! 0 KEEP
6. [Finished]
Return(PAGES)

2) Algorithm CONSTRUCT_INDEX_TREE. This algorithm is similar to


algorithm CONSTRUCT_INDEX, with the exception that the major terms are
stored as a lexically ordered binary tree. Note that the subterms and pages
are still represented as linked linear lists.

1. [Initializations]
FIRSTMJ + NULL
2. [Loop until input is exhausted]
Repeat thru step 8 until input is exhausted
3. [Input next input term string]
Read(STRING)
4. {Locate special symbols]
A + INDEX(STRING,’'#')
B + INDEX(STRING,'%')
C + INDEX(STRING,'@’)
5. [Obtain page numbers]
fc +0
then PAGES + SUB(STRING,C+1)
STRING + SUB(STRING,1,B-1)
else PAGES + /
6. [Obtain the sub2term]
IfB 0
then SUB2TERM + SUB(STRING,B+1)
STRING — SUB(STRING,1,B-1)
else SUBTERM + ”!
7. [Obtain the subterm]
IA 20
then SUBTERM + SUB(STRING,A+1)
STRING + SUB(1,A-1)
else SUBTERM + "
8. [Obtain major term]
If STRING 4"
then MAJORTERM + STRING
T + FIRSTMJ
it = "NOLe
then FIRSTMJ «+ SAVE + ALLOCATE_MJ(MAJORTERM)
else FOUND + false |
Repeat while AFOUND

5-67
If MAJORTERM < TERM(T)
then If LPTR(T) = NULL
then LPTR(T) + SAVE +
ALLOCATE_MJ(MAJORTERM)
FOUND + true
else“ "T' = EPTR(T)":
else If MAJORTERM > TERM(T)
then If RPTR(T) = NULL
then RPTR(T) + SAVE
FOUND + true
else R + RPTR(T)
else SAVE + T
FOUND + true
(update subterm and page number lists)
If SUBTERM + "'
then Call INSERT(SUBLIST(SAVE),SUBTERM,PAGES)
else Call PAGING(MJPAGE(SAVE),PAGES)
9. [Finished]
Exit

Procedure RPRINT INDEX(FIRSTMJ). Given FIRSTMJ, a pointer to


a binary tree representing an index, this procedure recursively prints the terms
of the tree in alphabetic order.

1. [Traverse left subtree]


If LPTR(FIRSTMJ) 44 NULL
then Call RPTRIN_INDEX(LPTR(FIRSTMJ))
2. [Print major terms|
Write(TERM(FIRSTMJ) © PAGESTRING(MJPAGE(FIRSTMJ}))
3. [Print subterms and sub2terms]
SAVE + SUBLIST(FIRSTMJ)
Repeat while SAVE a NULL
else Write(' BPH! 0 SUBTM(SAVE) © PAGESTRING(SUBPAGE(SAVE)))
SAVE2 + SUB2LIST(SAVE)
Repeat while SAVE2 me NULL
Write(’ KBBBBBEBBH’ © SUBSTM(SAVE2) ©
PAGESTRING(SUB2PAGE(SAVE2)))
SAVE2 + SUB2LINK(SAVE2)
SAVE « SUBLINK(SAVE)
4. [Traverse right subtree]
If RPTR(FIRSTMJ) 54 NULL
then Call RPRINT_INDEX(RPTR(FIRSTMJ))
5. [Finished]
Return
5-68
3) If ranges of page numbers are accepted in algorithm PAGING, there should be
a check to make sure that the first number given in the range is less than the
second number. There should also be a test for valid page numbers (i.e.
between 1 and n) since negative page numbers or those higher than n are
obviously mistakes. The data should be checked to ensure that a term occurs
before 2 page number, or the algorithm could be modified so that a lone page
number as an input item would be from the last subterm of the last major
term encountered. If the last major term did not contain a subterm, then the
page number could apply directly to the major term. Thus an error should be
generated only if a page number is the first input item. The first input item
should also be checked to make sure that it doesn't start with a ‘#! since
there can be no subterms until a majorterm has been input. The same applies
to sub2terms.

EXERCISES SECTION 5-4.1 PAGE 439

1)

Ee
Oe=©
oo
locoo [ee
ee
|

Paths of length 1 from vy v4: (1,4) °


Paths of length 2 from v, v,: (1,2) (2,4)

AZ=evhOuhs Vio leet Mao Or gt 2


OES 2 0-1 Or 2
Oro l jelous Out a
On O>ctlaacal Cac? Onna

Afaet FiOS Sins ee


Ae 8
Ores east aa
0. hee

2) (I+ AJA(I+A)=(IAI
+ (IAA) + (AAD +(AAA)=I4A4 A
(since A+ A = A.)
Assume (I+ A)» eat TSE AS es A
Then ([+A) = (I + A)® (14 A)
=(I+A--- ae + A)
=I+A+::: Af ee + AM
=I+A+4+--- +A

5-69
3) P=I1+A+A@4 --- 4A
= (14
Maj
4) A= Oo culses 0) 0oo00
0-0. OF 10
SOs SOON CO
Ot Ok
Gro ch “O26

Ae OI Yh QT any.
Oe TQ tat Of
fea ONE My Mele]
OPO ey rey
Ona ts nO? weds cy

d = Gow oh
oo 0 1 1
SONS yOu es A
Sone 2, 0

At=A+A®+4
A® + AM

dy = 1iff <Vi,Vj> € E
dj; = oo if v; is not reachable from vy,

Algorithm MINPATHS. Given B, and n X n adjacency matrix in which


zero elements are replaced by oo (even n” is large enough) this algorithm
determines all the minimum paths between each pair of nodes and stores the
result in the matrix PATH. The digraph is labeled, with the values given in
matrix L, so the paths will be referenced by label with the following format:
e.g., (a(b,c)d,efg,h(ij,kl,mn))
Each single letter represents a label; adjacent letters imply no choice,
whereas round brackets surrounding a group of letters delimited by ',’
implies the selection of one element. Therefore, the above sample of the
PATH matrix entry means each of the following are minimal paths:
abd, acd, efg, hij, hkl, hmn.
Algorithm MINPATHS invokes function CONVERTCHAR and subalgorithm
PATHSTRING. C and P are temporary arrays and i, j, and k are temporary
integers. Entry Py of matrix P refers to nodes k (stored i character form and
delimited by ‘+/) such that both paths from i to k and from k to j are
minimal paths.

1. [Initializations]
C+B
PATH+ P+”

2-70
to [Perform a pass|
Repeat thru step 5 fork = 1, 2,..., N
3. [Process rows|
Repeat thru step 5 fori = 1, 2,..., N
4. [Process columns]
Repeat thru step 5 forj = 1, 2, ..., N
5. [Save first branch of minimal paths]
If Ci, ap Cy <i Cy
then Cy -— Cy + Cy
Py - CONVERTCHAR(K) © i!
else If Cy + Cy = Cy
then Py + Py © CONVERTCHAR(K) © '+!
6. [Creat array of all minimal paths]
Repeat for i = 1, 2,..., N
Repeat forj = 1, 2, ...,N
Write(PATHSTRING(C,P,,i,j))
et [Finished]
Exit.

Function PATHSTRING(C,P,i,j). Given the matrices C and P as


discussed algorithm MINPATHS, and the subscripts i and j,this function
creates entry PATH) which gives all the minimal paths from node i to node j
in the format previsusly described. The Cy entry of matrix C is set to N ft 2
to signify the presence of the. correct value in PATH). Since the function is
recursive, it is a byproduct that several other PATH entries may be created at
the same time.

1. [Paths previously determined? ]

then Return(PATH,))
2. [Path between adjacent nodes?]
If Cj = 1
then Cy + Nf 2
PATHy + Ly
Return(PATHy i)
3. [One branch in minimal path?
T + INDEX(P;;,'+')
k — CONVERTNUM(SUB(P;;,1,T — 1))
PATH; + Se 0 PATHSTRING(k,j)
If T = "LENGTH(Py)
then Return(PATH,))
4. [Several branches]
Repeat while T A LENGTH(P,)
Py; — SUB(P,;,T + 1)
T + INDEX(P,;,’+’)

STi
k — CONVERTNUM(SUB(,,1,t 1))
PATH, + PATH, © ',’ © PATHSTRING(i,k) © PATHSTRING(k,j)
Return('(' © PATH, © ')!)

6) program minpaths(input,output);

{ Given a digraph with all its edges labeled, this program displays all
minimum paths between all pairs of nodes. The input is an adjacency matrix
and corresponding label matrix. The output is a path matrix where each
entry contains all minimum paths for a pair of nodes. }

const n = 7;

type string = packed array[1..80] of char;

var b,c:array(1..n,1..n] of integer;


p,l,path:array[1..n,1..n] of string;
i,},k: integer;
result,temp:string;

FE EEE AEA BEEBE AEE OEE ASAE BIO AEE S444 64 44}

#include ‘length.i’;
#include 'index.i’;
#include 'sub.i’;
#include ‘concat.i';
(OBES Baar onddcicianiaa Hiei iidenniiddibiiniieineiaiiiocccionr)

function cnum(str:string):integer;

{ Given a character string of digits, this function returns a positive integer


which represents the same value. }

var n,c,l:integer;
temp:string;

begin
n := 0;
c:= 1;
] := length(str);
while (c <= 1) do
begin
sub(str,c,1,temp);
n := 10 * n + index('0123456789|'
temp) — 1;
ci=c+#A
end;

oe
chum :=n
end;

GABE B BEES SEE EEE SESE ESBS AROSE EEE ESB OBB B AB SABE EE EE EE}

function cchar(int:integer):string;

{ Given a positive integer, this function returns a character string of digits


which represents the save value. }

var i,r,d:integer;
c,temp:string;

begin
re — sl:
if int > 0
then d := int
else d := 0;
while d <> 0do
begin
r:= d mod 10;
d'=— a div 10:
sub('0123456789' ,r+1,1,temp);
ci] := temp[]];
i:=i+1
end;
{ add string delimiter }
Clile== IV;
cchar :=c
end;

[ABBE RBBB EEE BSB BEEBE EEE AHO SSEES SSH BSS EBEBE oes)

function pathstring(i,j:integer):string;

{ Given two nodes, the previously described temporary matrices, and the label
matrix, this function calculates all minimum paths between the nodes and
stores them in character type in the path matrix. A string of one blank
implies no path exists. }
var t,k:integer;
temp,temp1,temp2:string;

begin
{ check for previously determined path }
if c[i,j] = n*n

ato
then pathstring := pathii,j]
else { check for path between adjacent nodes }
if cli,j] = 1 |
then begin
c[i,j] := u*n;
path[i,j] := i,j];
pathstring := patb[i,}]
end
else begin
{ check for one branch in minimal path }
cfi,j] := n*n;
t := index(pji,j],’+|’);
sub(pli,j],1,t-1,temp);
k := cnum(temp);
concat({pathstring(i,k),pathstring(k,j),path{i,j]);
if t = length(pli,j])
then pathstring := pathii,j]
else begin
{ several branches }
while (t <> length(p|i,j])) do
begin
sub(p[i,j],t+1,length(p[i,j])+,
p[i,i]);
t := index(pli,j],’+|’);
sub(p|i,j],1,t-1,temp);
k := cnum(temp);
concat(path|i,j],’,|',temp1);
concat(pathstring(i,k),pathstring(k,j),temp2);
concat(temp1,temp2,path|i,j})
end;
concat('(|' path[i,j],path{i,j]);
concat(path{i,j],’)|',path{i,j]);
pathstring := pathii,j]
end
end
end;

FEB EEEESAE OEE BSBA BCE EEE CEIEEE AE ETA TITTIES }

begin
{ read adjacency and label matrices }
for i:= 1 tondo
begin
for j := 1 ton do
begin
read(b[i,j]);

5-74
if bli,j] = 0
then b[i,j] := n*n
else begin
read(temp[1));
temp[2] := '|';
[i,j] := temp
end
end;
readin
end;
{ compute minimum paths }
Crp:
for k := 1 tondo
begin
for i:= 1 to n-do
begin
for j}:= 1tondo
begin
if cli,k] + clk,j] < c[i,j]
then begin
c{i,j] := c[i,k] + c[k,j];
concat(cchar(k),’+|',p[i,j])
end
else if c{i,k] + c[k,j] = c[i,j]
then begin
concat(p[i,j],cchar(k),temp);
concat(temp,’
+| ,p[i,j])
end
end
end
end;
{ output results }
for i := 1 tondo
begin
forj := 1tondo
begin
result := pathstring(i,j);
writeln(/ MINPATH(':8,i:1,!,/:1,j:1,') = ':4,result:length(result))
end
end
end.

or]
0 la 1lbO0000
000 le 00 0
00 1k 1d 000
1 770.020 leoit.0
0 0 0 0 1
0 0 0 0 1
00 aost
oe - 00
a O° 0a
©=

MINPATH(1,1)
MINPATH(1,2)
MINPATH(1,3)
MINPATH(1,4)
MINPATH(1,5)
MINPATH(1,6)
MINPATH(1,7) ((ac,bd)eg,(ac,bd)fh)
MINPATH(2,1) cj
MINPATH(2,2) cja
MINPATH(2,3) cjb
MINPATH(2,4) c
MINPATH(2,5) ce
MINPATH(2,6) | cf
MINPATH(2,7) (ceg,cfh)
MINPATH(3,1 ) dj
MINPATH(3,2 ) dja
MINPATH(3,3 ) k

5-7/6
d
I de
df
(deg, dfh)
I J
ja
I jb 7
(jac,jbd,(eg,fh)i)
e
I f
(eg,fh)
gi)
gia
gijb
gi
gie
gif
g
hij
hija
hijb
hi
hie
hif
h
iJ
I ija
ijb
i
!| le
if
I (ieg,ifh)
EXERCISES SECTION 5-4.2 PAGE 444

3) Function EQ(A,B). Given A and B, two atoms of a list structure, this


function returns the truth value of their equality.

1. [Valid arguments?]
If A = NULL or B = NULL
then Write(/ERROR: NULL ARGUMENT(S)')
Return(false)
2. [Determine equality]
If DPTR(A) = DPTR(B)
then Return(true)
else Return(false)

5-78
4) Function UNION(X,Y). Given X and Y, head nodes pointing to two list
structures, this function returns the address of the head node of the list which
is the union of X and Y. Algorithms HEAD, TAIL, CONSTRUCT and
MEMBER are used in this recursive function.

1. [Valid lists?]
If X = NULL or Y = NULL
then Write(/ERROR: NULL ARGUMENT(S)')
Return(NULL)
2. [Trivial case?
If RPTR(X) = NULL
then Return(Y)
else If RPTR(Y) = NULL
then Return(X)
3. [Recursive calls]
If MEMBER(HEAD(X),Y)
then Return(UNION(TAIL(X),Y))
else Return(CONSTRUCT(HEAD(X),UNION(TAIL(X),Y)))

Function INTER(X,Y). Given X and: Y, pointer to head nodes of two list,


this recursive algorithm returns the address of the head node of the list which
is the intersection of X and Y. Algorithms HEAD, TAIL, CONSTRUCT, and
MEMBER are used in this function.

1. [Valid lists?]
If X = NULL or Y = NULL
then Write(/ERROR: NULL ARGUMENT(S)’)
Return(NULL)
2. [Trivial case?]
If RPTR(X) = NULL
then Return(X)
else If RPTR(Y) = NULL
then Return(Y)
3. [Recursive calls]
If MEMBER(HEAD(X),Y)
then Return(CONSTRUCT(HEAD(X),INTER(TAIL(X),Y)))
else Return(INTER(TAIL(X),Y))
ee
ee

Function MEMBER(A,B). Given A and B, pointers to two list, this


recursive function returns true if A is a member of list B (top level element)
and returns false otherwise. Algorithms HEAD, TAIL and EQUAL are used in
this function. ;

1.’ [Is B and atom?]


If ATOM(B) = 1
then RETURN(EQUAL({A,B))
2. [A in B?]
If EQUAL(A,HEAD(B))
then Return(true)
else Return(MEMBER(A,TAIL(B)))

Function EQUAL(A,B). Given A and B, pointers to two list, this


recursive function returns true if A and B are equal and false otherwise.
Algorithms HEAD, TAIL, ATOM and EO are used in this function.

1. [A and/or B atoms?|
If ATOM(A) = 1
then RETURN(EQ(A,B))
else If ATOM(B) = 1
then Return(false)
2. [Neither are atoms]
If EQUAL(HEAD(A), HEAD(B))
then Return(EQUAL(TAIL(A),TAIL(B)))

Function REVERSE(A). Given A, a pointer to a list structure, this


function returns the address of the list which is the reverse of A. Algorithms
CONS, CDR, and CAR are used in this function.

1. [Initializations]
P — NULL
2. [Add successive elements of A to front of new list]
Repeat while A 4 NULL
P + CONS(REVERSE(CAR(A)),P)
A + CDR(A)
3. [Finished]
Return(P)

6) Function LEVEL(P,Q). Given P, a pointer to a list header node, and Q, a


pointer to a specific node in the list structure, this function returns the depth
of Q.

5-80
1. [Check for valid entries.
If P = NULL or Q’'= NULL
then Return(0)
2. [Check for empty list]
If RPTR(P) = NULL and DPTR(P) = NULL
then Return(0)
3. [Traverse to right of list]
A + RPTR(P)
FOUND + false
Repeat while A 54 NULL and -FOUND
If ATOM(A) = 1
then Ao
then FOUND + true
POSS — 0
else If DPTR(A) 4 NULL
then POSS + LEVEL(DPTR(A),Q)
IEOSs 0
then FOUND + true
A + RPTR(A) .
4. [Check if node found]
If FOUND
then Return(POSS + 1)
else Return(0)

7) Function COPY(P). Given P, a pointer to an existing list structure, this


function returns a pointer to a duplicate copy of the list. In building the
copy, the original list is not destroyed.

1. [Check for null pointer]


If P = NULL
then Return(NULL)
2. [Initialize new node]
NEW <= NODE
ATOM(NEW) + ATOM(P)
3. [Copy list]
If ATOM(P) = 1
then DPTR(NEW) + DPTR(P)
else DPTR(NEW) — COPY(DPTR(P))
RPTR(NEW) + COPY(RPTR(P))
4. [Finished]
Return(NEW)

5-6
8) Procedure PRINTOUT(L). Given L, a pointer to a list header node, this
procedure invokes a procedure PRINT to print out the parenthesized
expression corresponding to the list, structure.

1. [Check for empty list]


If DPTR(L) = NULL and RPTR(L) = NULL
then Write(/EMPTY LIST’)
else Call PRINT(L)
2. [Finished]
Return

Procedure PRINT(L). Given L, a pointer to a list structure head node,


this recursive procedure prints the corresponding parenthesized expression.

1. [Check for null pointer]


If L = NULL
then Return
2. [Check for empty list]
If DPTR(L) = NULL and RPTR(L) == NULL
then Return
3. [Print expression]
Write('(')
Repeat while (RPTR(L) 4 NULL)
Le RPTRID)
If ATOM(L) = 1
then Write(VALUE(DPTR(L)))
else Call PRINT(DPTR(L))
If RPTR(L) 4 NULL
then Write(’,’)
Write(’)')
4. [Finished] 5
Return

9) Function DEPTH(S). Given S, a pointer to a list structure, this function


returns the maximum level or depth of all sublists.

1. [Initializations]
MAX + 0
2. [Check for null pointer}
Iv Se== NULL
then Return(MAX)
3. [Scan through list to the right]
P+S

5-82
Repeat while P 4 NULL
If ATOM(P) = 1
then ANS <0
else ANS «+ DEPTH(DPTR(P))
If ANS > MAX
then MAX + ANS
P + RPTR(P)
4, [Add this level]
MAX + MAX + 1
5. [Finished]
Return(MAX)

10) Function EQUAL(S,T). Given S and T, pointers to two list structures,


this function returns true if it finds the lists to be equal in structure and data
fields; false otherwise.

ie [Initializations]
ANS + false
De [Check for null pointers]
If S = NULL and T = NULL
then Return(true)
[Compare lists]
If S 4 NULL and T 4 NULL
then If ATOM(S) = ATOM(T)
then If ATOM(S)= 1
then If VALUE(DPTR(S)) = VALUE(DPTR(T))
then ANS + true
else ANS + EQUAL(DPTR(S),DPTR(T))
If ANS
then ANS + EQUAL(RPTR(S),RPTR(T))
[Finished]
Return(ANS)
EXERCISES SECTION 5-4.3 PAGE 448

[2| 14 |
Septal eeee
Pu Ale oa
UE eae

5-84
Algcrithm CONSTRUCT_LIST. This algorithm reads pairs of directed
edges representing a graph, thus creating an adjacency list structure. The node
structure from the text is assumed.

L, [Initialize structure]
Repeat for l= 1, 2; ..., N
LINK{I]
— NULL
[Engage loop to process all data]
Repeat thru step 5 while there remains data
[Read next pair of edges]
Read(X,Y)
[Allocate and initialize new node]
Q — NODE
DESTIN(Q)—Y
EDGEPTR(Q)
— NULL
[Insert node into appropriate list]
PRED + NULL
SUCC
+ LINK[X]
FOUND + false
Repeat while SUCC 4 NULL and -FOUND
If DESTIN(SUCC) > Y
then FOUND + true
else PRED «+ SUCC
SUCC + EDGEPTR(SUCC)
EDGEPTR(Q)
—SUCC °
If PRED. => NULL
then LINK[X]
—Q
else EDGEPTR(PRED)
«Q
6. [Finished]
Exit

Algorithm TRANSFORM. Given A, the adjacency matrix representation


of a graph, this algorithm creates an equivalent adjacency list.

i. [Initialize list structure]


Repeat for I =-1, 2, ...N
LINK[N] — NULL
bo [Scan all rows of the adjacency matrix]
Repeat thru step 4 fori = 1, 2,...,N
[Scan all columns of the adjacency matrix]
Repeat thru step 4 forj = 1, 2, ..., N
[Add node to list if necessary]
If Ay = 1
then Q <= NODE

5295
DESTIN(Q) + j
EDGEPTR(Q) + NULL
PRED «+ NULL ~
SUCC + LINK{i] —
FOUND ~+ false
Repeat while SUCC $4 NULL and 7 FOUND
If DESTIN(SUCC) > j
then FOUND < true
else PRED «+ SUCC
SUCC + EDGEPTR(SUCC)
EDGEPTR(Q) + SUCC
If PRED = NULL
then LINK[{i] — Q
else EDGEPTR(PRED) + Q
5.

EXERCISES SECTION 5-4.4 PAGE 452

1) Assuming the diagram is labelled in the following manner:

3 4

Pee Le
REACH | NODE NO | DATA | DIST | LISTPTR

een er
eases
pee
as ate VY

ence or
2 IFA TOY,
ee ee ey
Pern Sea" | ETHER-ED
3) Function CONNECTED. This function is the same as procedure BFS in
the text, with the exception that a check is made to determine if the graph is
connected or not. The function returns true is the graph is connected; false
otherwise.

1. [Initialize the first node's DIST number and place node in queue]
REACH{INDEX] + true
DIST{INDEX] + 0
Call QINSERT(QUEUE,INDEX)
2. [Repeat until all nodes have been examined]
Repeat thru step 5 while queue is not empty
3. [Remove current node to be examined from queue]
Call QDELETE(QUEUE, INDEX)
4. [Find all unlabeled nodes adjacent to current node]
LINK «— LISTPTR[INDEX]
Repeat step 5 while LINK 4 NULL
5. [If this is an unvisited node, label it and add it to the queue]
If -REACH|DESTIN(LINK)]
then DIST|DEST(LINK)] — DIST[INDEX] + 1
REACH[DEST(LINK)] + true
Call QINSERT(QUEUE, DESTIN(LINK))
LINK +- EDGEPTR(LINK) (Move down edge list)
6. [Determine if graph is connected]
CONNECT + true
Repeat for I = 1, 2, ..., N while CONNECT
If DIST{I] = 0
then CONNECT + false
7. [Finished]
Return(CONNECT)
EXERCISES SECTION 5-4.5

1) Assuming the graph is labeled in the following manne


r:

CUTVERTICES: A, B, and F; or numbers 1, 2, and 6

NODENO DATA LOWPOINT


1 A 1
2 B 1
3 Cc 1
4 D 1
5 E ]
6 F 4
7 G 5

REACH | NODENO]| DATA LISTPTR

Seer eee
Pe teal aceon
fpedrme:| oesepeatmiesee
ivetly conan |
pites|Sea)
bre

5-88
Procedure LOW_MAIN(N). This procedure is the top-level procedure for
determining the cutvertices and lowpoints of an N-node graph. Most of the
work is done by the procedure LOW_COMPUTE. The graph is represented
using the node and edge structures described in the text. COUNT keeps track
of the DFN numbers. There are a number of N-element arrays: DIN holds
node’s DFN number; REACH keeps track of whether the node has been
visited; LOW holds a node’s lowpoint number; PARENT contains a node’s
parent in the constructed tree; CUTVERT indicates whether a node is a
cutpoint. The desired results are contained in LOW and CUTVERT upon
return.

1. [Initializations]
Repeat for J = 17.235.4'N
REACH|I] < false
CUTVERT|I] + false
2. [Comput lowpoiuts and cutvertices]
COUNT + 0
Call LOW_COMPUTE(COUNT)
3. [Finished]
Return

Procedure LOW_COMPUTE(INDEX). This recursive procedure is as


described in LOW_MAIN. INDEX holds the number of the node currently
being processed, and LINK is a pointer to an edge node.

1. [Mark node] :
COUNT «+ COUNT + 1
DFN{INDEX] + COUNT
LOW(INDEX] + DFN|INDEX]
REACH|INDEX] + true
2. [Perform DFS on each connected node]
LINK + LISPTR|INDEX]
Repeat step 3 while LINK af NULL
3. [If node has not been reached, continue DFS]
if -REACH[DEST(LINK)}
then PARENT|DESTIN(LINK)] — INDEX
Call LOW_COMPUTE(DESTIN(LINK))
LOW[INDEX] + MIN(LOW{INDEX],LOW|DESTIN(LINK)])
If LOW|DESTIN(LINK)] > DFN[INDEX]
then CUTVERT|INDEX] + true
else If DFN[DESTIN(LINK)] <<DFN[INDEX] and PARENT{INDEX]
DESTIN(LINK) and DFN[DESTIN(LINK)] <LOW{INDE}
then LOW[INDEX] <— DFN[DESTIN(LINK)]
4. [Finished]
Return

S00
EXERCISES SECTION 5-4.6 PAGE 458

1) Procedure BFS_SPAN(INDEX). Given the structures described later,


and the queue handling procedures QINSERT and QDELETE, this procedure
generates a spanning tree using a breadth first search. INDEX denotes the
current node being processed and LINK points th the edge being examined. It
is assumed that the REACH field has been set to false wwhen the structure
was created. The node structure is assumed to have three fields: REACH,
NODENO and LISTPTR; the edge structure is assumed to have 3 fields:
DESTIN, EDGEPTR, and FLAG, where FLAG indicates whether the edge is
included in the spanning tree.

1. [Place the first node in the queue]


REACH[INDEX] «+ true
Call QINSERT(QUEUE, INDEX)
2. [Examine all nodes]
Repeat thru step 5 while QUEUE is not empty
3. [Remove current node to be examined from queue]
Call QDELETE(QUEUE, INDEX)
4. [Find all unlabeled nodes adjacent to the current node]
LINK + LISTPTR[INDEX] °
Repeat step 5 while LINK 34 NULL
5. [If node is unvisited, label it, add to queue, and include in spanning tree]
If s7REACH[DEST(LINK)|
then REACH[DESTIN(LINK)] « true
FLAG(LINK) « true
Call QINSERT(QUEUE,DESTIN(LINK))
LINK + EDGEPTR(LINK)
es [Finished]
Return

Procedure DFS_SPAN(INDEX). Given the structures as described in the


previous algorithm, this recursive procedure constructs a spanning tree for a
graph. INDEX is the current index into the node table directory table.

1. [Mark current node]


REACH{[INDEX] + true
2. [Set up loop to examine each neighbor of current node]
LINK + LISTPTR[INDEX]
Repeat step 3 while LINK ~~ NULL

5-90
3. [If node has not been reached, make recursive call]
If -REACH|DESTIN(LINK)]
then FLAG(LINK) + true
Call DFS_SPAN(DESTIN(LINk))
LINK + EDGEPTR(LINK)
4. [Finished]
Return

Procedure READ_LIST(HEAD). This procedure reads in a number of


edges and creates a linked-list representation sorted by increasing order of
weight, with HEAD being a pointer to the first element of the list. NEW,
PTR and PAR are pointer variables. Function READ_EDGE is assumed to
exist; it reads in the information about an edge, creates and initializes an edge
structure, and returns a pointer the new structure.

1. [Read in the first edge]


HEAD + READ_EDGE
2. [Read in all the rest of the edges]
Repeat thru step 4 until all edges are read in
3. [Read next edge]
NEW + READ_EDGE
4, [Insert into correct position in list]
If WEIGHT(HEAD) > WEIGHT(NEW)
then LINK(NEW) — HEAD
HEAD -— NEW
else PTR + LINK(HEAD)
PAR «— HEAD
Repeat while (PTR +4 NULL)
If WEIGHT(PTR) > WEIGTH(NEW)
then Exitloop
else PAR+ PTR
PTR + LINK(PTR)
LINK(NEW) — PTR
LINK(PAR) — NEW
5. [Finished]
Return

3) Procedure MAT_SPAN(A,N). This procedure creates a minimum-cost


spanning tree for the graph represented by the N X N adjacency matrix A. If
an edge exists between nodes i and j, the value of Ay is the weight of that
edge, otherwise Ay equals zero. Upon returning from the procedure, if an edge
is included in the tree, its adjacency matrix entry will be negative. Note that
this procedure assumes all weights are greater than zero. i and j are indices
into the array. LOW_I and LOW_J contain the indices of the current least
cost edge, and LOW_VALUE contains its cost.

5-91
1. [The tree will have N — 1 edges]
Repeat thru step 6 for] = 1, 2, ...N
2. [Initialize indices]
LOW_I+ LOW_J+0 |
LOW_VALUE < oo
3. [Scan through matrix rows]
Repeat thru step 5 fori = 1, 2,... N
4. [Scan through matrix columns]
Repeat thru step 5 for j = 1, 2, ...N
5. [Is this edge less expensive?|
If Ali,j] > 0 and Afi,j] < LOW_VALUE
then LOW_VALUE + Aji,j]
LOW_I +i
LOW.I <j
6. [Insert this edge into the tree]
A[LOW_I,LOW_J] + A[LOW_J,LOW_I] — -A[LOW_LLOW_J]
7. [Finished]
Return

EXERCISES SECTION 5-5.1 PAGE 469

1) Step 1 initializes all the elements of arrays TE and POINTER to 0, the


elements of array DATA to null, the variables NOLEDGES and NO_NODES
to 0, and the elements of array TL to infinity. Step 2 then reads in ORIGIN,
INFO, WEIGHT, and END.

NODE NO. | DATA TE TL POINTER | TIME DEST


"

HD
We
WD
= oooocco 888888
So:
Oo
O'S

NO_EDGES = 0
NO_NODES = 0
ORIGIN = 1
INFO = vl
WEIGHT = 3
END = 2

In step 4, DATA[ORIGIN] is set to INFO, and since ORIGIN is greater than

o792
NO_NODES, NO_NODES is incremented by 1. POINTER[NO_NODES] is
set to NO_NODES + 1, NO_EDGES is incremented by 1, TIME[NO_EDGES]
is set to WEIGHT, and DEST[NO_EDGES] is set to END. Step 5 then reads
in ORIGIN, INFO, WEIGHT, and END.

NODE NO. | DATA --TE TL POINTER”) TIME- DEST


1 vl 0 CO 1 Ss 2
2 a 0 oO 0
3 os 0 CO 0
4 i 0 CO 0
5 i 0 oo 0
6 i 0 oo 0

NO_EDGES =
NO_NODES = 1
ORIGIN = 1
INFO ="!
WEIGHii—s2
END ==3

In step 4, since ORIGIN = NO_NODES and END > 0, NO_EDGES is


incremented by 1, TIME[NO_EDGES] is set to WEIGHT, and
DEST[NO_EDGES] is set to END. Step 5 then reads in ORIGIN, INFO,
WEIGHT, and END.

NODE NO. | DATA: TE Ths ROINTERS| TIME. «DEST:


1 vl 0 co 0 3 2,
2 o 0 oO 0 2 3
3 bf 0 oo 0
4 dt 0 oo 0
5 a 0 oo 0
6 H 0 oO 0

NO_EDGES = 2
NO_NODES = 1
ORIGIN = 2
INFO = v2
WEIGHT = 2
ENDi= 4

In step 4, DATA[ORIGIN] is set to INFO, and since ORIGIN > NO_NODES,


NO_NODES is incremented by 1, POINTER[NO_NODES] is set to
NO_EDGES + 1, NO_EDGES is incremented by 1, TIME[NO_EDGES] is set
to WEIGHT, and DEST|NO_EDGES] is set to END. Step 5 then reads in
ORIGIN, INFO, WEIGHT, and END.

35>95
NODE NO. | DATA TE TL POINTER | TIME DEST
1 vl 0 co 1 3 a
Oy v2 0 co 3 oy, 3
3 A 0 oO 0 2 4
4 ae 0 oo 0
5 g 0 0 0
6 4 0 oO 0

NO_EDGES = 3
NO_NODES = 2
ORIGIN = 2
INO = '!
WEIGHT = 3
END =—5

In step 4, since ORIGIN = NO_NODES and END > 0, NO_EDGES is


incremented, TIME[NO_EDGES] is set to WEIGHT, and DEST[NO_EDGES]
is set to END. Step 5 then reads in ORIGIN, INFO, WEIGHT, and END.

NODE NO. | DATA . TE.. TL POINTER | TIME DEST


1 vl 0 co 1 3 2
2 v2 0 co 3 yy 3
3 iy 0 co 0 z 4
4 i 0 CO 0 3 5
5 if 0 oO 0
6 Y 0 oo 0

NO_EDGES = 4
NO_NODES = 2
ORIGIN = 3
INFO = v3
WEIGHT = 4
END = 4

In step 4, DATA[ORIGIN] is set to INFO and since ORIGIN > NO_NODES,


NO_NODES is incremented by 1, POINTER[NO_NODES] is set to
NO_EDGES + 1, TIME|NO_EDGES] is set to WEIGHT and
DEST{[NO_EDGES] is set to END. Step 5 then reads in ORIGIN, INFO,
WEIGHT, and END.
NODE NO. | DATA TE TL POINTER | TIME DEST
1 vl 0 oo 1 fos 2
2 v2 0 co 3 2 3
3 v3 0 oo 0 2 4
4 - 0 oO 0 3 5
5 i 0 co 0 4 4
6 At 0 oO 0

NO_EDGES = 4
NO_NODES = 2
ORIGIN = 3
INFO = v3
WEIGHT = 4
END = 4

In step 4, since ORIGIN > NO_NODES and END > 0, NO_EDGES is


incremented by 1, TIME[NO_EDGES] is set to WEIGHT, and
DEST|[NO_EDGES] is set to END. Step 5 then reads in ORIGIN, INFO,
WEIGHT, and END.

NODE NO. | DATA TE TL POINTER | TIME DEST


1 vl 0 CO ir 3 2
2 v2 0 oO . o 2 3
3 v3 0 ©O 5 2 4
4 iy 0 oo 0 3 5
5 e 0 oo 0 4 4
6 Se 0 co 0 S 6

NO_EDGES = 6
NO_NODES = 3
ORIGIN = 4
INFO = v4
WEIGHT = 2
END = 6

In step 4, DATA[ORIGIN] is set to INFO, and since ORIGIN > NO_NODES,


NO_NODES is incremented by 1, POINTER|[NO_NODES] is set to
NO_EDGES + 1, NO_EDGES is incremented by 1, TIME[NO_EDGES] is set
to WEIGHT, and DEST[NO_EDGES] is set to END. Step 5 then read in
ORIGIN, WEIGHT and END.

ante
NODE NO. | DATA TE TL POINTER | TIME DEST
1 vl 0 oO 1 3 2
2 v2 0 oo 2 3
3 v3 0 fore) 5 2 4
4 v4 0 co a os 5
5 dk 0 oo 0 4 4
6 i 0 oO 0 3 6
2 6

NO_EDGES = 7
NO_NODES = 4
ORIGIN = 5
INFO = v5 _
WEIGHT = 1
END = 6

In step 4, DATA[ORIGIN] is set to INFO, and since ORIGIN > NO_NODES,


NO_NODES is incremented by 1, POINTER|NO_NODES] is set to
NO_NODES + 1, NO_EDGES is incremented by 1, TIME[NO_EDGES] is set
to WEIGHT, and DEST[NO_EDGES] is set to END. Step 5 then reads in
ORIGIN, INFO, WEIGHT, and END.

NODE NO. DATA TE TL POINTER | TIME DEST


1 vl 0 co 1 3 2
2 v2 0 co 3 Y
3 v3 0 oO 5 2 4
4 v4 0 oo t 3 5
5 v5 0 co 8 4 4
6 i 0 co 0 3 6
2 6
1 6

NO_EDGES = 8
NO_NODES = 5
ORIGIN = 6
INFO = v6
WEIGHT = 0
END = 0

In step 4, DATA[ORIGIN] is set to INFO, and since ORIGIN > NO_NODES,


NO_NODES is incremented by 1, POINTER[NO_NODES] is set to
NO_EDGES + 1, and since END = 0, the algorithm terminates.

5=96
NODE NO. | DATA ©TE°> TL ROINTER | TIME. DES?
1 vl 0 oo 1 3 2
2 v2 0 CO 3 i, 3
3 v3 0 co 5 2 4
4 v4 0 oO 7 3 5
5 vo 0 co 8 4 4
6 v6 0 oO 9 5 6
2 6
1 6

NO_EDGES = 8
NO_NODES = 6
ORIGIN = 6
INFO = v6
WEIGHT = 0
END = 0

Trace of Algorithm PROCESS:

EDGE# | TE[DEST|EDGE¥]] | TLINODE¥] | OUTPUT


1 1

Sat
6
3
5
5
2
4
2
4
3
4
2
1
0
1
0
0
0 .

5 Wey lvl
ay

3 3 v3
4 4v4
5
6 6 v4

The final arrays for TE abnd TL are as follows:

NODE NO. TE TL
1 0 0
2 3 4
3 2 2
4 6 6
5 6 i
6 8 8

to Algcrithm LCREATE. This algorithm will set up the linked structures


discussed at the end
that reflect the relationships existing in a PERT graph as
to be handled, it is
of section 5-5.1. Note that when a new originating node is
first node must be
assumed that it already exists in the structure, therefore the
edge originates, END is
set up in step 1. ORIGIN is the node from which an
is the weight assigned
the node at which the edge terminates, and WEIGHT
smallest ORIGIN to
to the edge. The edges must be read in order from the
representation.
the largest. P is a pointer that will point to the linked

1. [Initializations]
Read( WEIGHT,ORIGIN,END)
P < NNODE
TEMP + P
DATA(P) + ORIGIN
TE(P) + 0
TL(P) + 00
5-98
IN(P) + OUT(P) + LINK(P) + NULL
NO_NODES +- 1
END_FLAG +¢- false
Ze [Process remaining data]
Repeat thru step 9 while ~END_FLAG
3. [Check for error on input]
If ORIGIN > NO_NODES
then Write(/DATA OUT OF SEQUENCE’)
Exit
If ORIGIN = NO_NODES and END < 0
then Write(/NONSINK NODE HAS AN EDGE WITH INVALID
DESTINATION’)
Exit
4. [New originating node?]
If ORIGIN > NO_NODES
then If LINK(TEMP) 4 NULL
then TEMP + LINK(TEMP)
If DATA(TEMP) 54 ORIGIN
then Write(/BAD SOURCE OR SINK’)
Exit
NO_NODES «+ NO_NODES + 1
If END < 0
then Exit
5. [Is END node in the list?]
SAVE «+ TEMP
X + LINK(TEMP)
FOUND ~< false
Repeat while X 54 NULL and ~FOUND
If DATA(X) < END
then FOUND < true
else SAVE + X
X + LINK(X)
If X = NULL
then Y <= NNODE
DATA(Y) + END
TE(Y) + 0
TL(Y) — oo
IN(Y) + OUT(Y) — NULL
LINK(SAVE) — Y
LINK(Y) + X
NEY,
else If DATA(X) +4 END
then Y <= NNODE
DATA(Y) + END
TE(Y) + 0

ara
TL(Y) + o0
IN(Y) + OUT(Y) — NULL
LINK(SAVE) + Y
LINK(Y) — X
x ey:
6. [Set up edge node]
Y +«- ENODE
OUTL(Y) + INL(Y) — NULL
SOURCE(Y) + TEMP
TIME(Y) + WEIGHT
DEST(Y) + X
7. [Insert edge into OUT list of TEMP]
If OUT(TEMP) 4 NULL
then SAVE «+ OUT(TEMP)
Repeat while OUTL(SAVE) +4 NULL
SAVE + OUTL(SAVE)
OUTL(SAVE) + Y
else OUT(TEMP) — Y
8. [Insert edge into IN list of X]
If IN(X) 54 NULL
then SAVE + IN(X)
Repeat while INL(SAVE) 54 NULL
SAVE + INL(SAVE)
INL(SAVE) — Y
else IN(X)+ Y
9. [Get next edge]
If there remains input data
then Read(WEIGHT,ORIGIN,END)
else END_FLAG + true
10. [Finished]
Exit

3) Algorithm LPROCESS. Given P, a pointer to a linked representation of


nodes and edges in a PERT graph, this algorithm computes and stores the TE
and TL values for each node and then prints those nodes which lie on the
critical path. NODE# nad EDGE# indicate which node and which edge are
currently being examined. Note that a stack S is used to go back up the list
of event nodes.

1. [Initialize to compute TE values]


NODE# + P
EDGE# «+ OUT(NODE#)
TOP +0
2. [Compute TE value for each node]
Repeat while LINK(NODE#) 4 NULL

5-100
Repeat while EDGE# 4 NULL
TEMP « DEST(EDGE#)
TE(TEMP) + MAX(TE(TEMP),TE(NODE#)+TIME(EDGE#))
EDGE# «+ OUTL(EDGE#)
TOP + TOP +1
S[TOP] + NODE#
NODE# «+ LINK(NODE#)
EDGE# + OUT(NODE#)
3. [Initialize to compute TL values]
TL(NODE#) + TE(NODE¥#)
4. [Compute TL values for each node]
Repeat while TOP > 1
NODE# + S[TOP]
TOP — TOP - 1
EDGE# + OUT(NODE#)
Repeat while EDGE# +4 NULL
TEMP «+ DEST(EDGE#)
TL(NODE#) — MIN(TL(NODE#),TL(TEMP) — TIME(EDGE#))
EDGE# + OUTL(EDGE#
5. [Output the nodes on the critical path]
Repeat while NODE# + NULL
If TE(NODE#) = TL(NODE#)
then Write(DATA(NODE#))
NODE# + LINK(NODE#)
6. [Finished]
Exit

The storage required to represent the PERT graphs is directly related to the
number of edges and nodes in the graph. Obviously, the array representation
is much more efficient than the linked representation when considering storage
use.
Execution time required for small PERT graphs does not differ
significantly between the two representations. For larger graphs, the array
representation takes a significantly longer time to execute than the linked
represenation. This may not be the case for extremely large graphs since the
linked method requires chaining through linked lists to find certain elements
and the array method does not require any searching.

prograrn pert(input,output);

{ This program will form the array structures for a pert diagram as in the
algorithm CREATE. After this is done, the TE and TL values are computed
as in algorithm PROCESS. The nodes on the critical path are then printed
out. }

b=.
const n = 10;
e = 15;

var te,tl,pointer: array[1..n| of integer;


data: array[1..n] of char;
, time,dest: array[1..e] of integer;
Origin, Weight,End:integer;
Info: char;
i,nonodes,noedges:integer;
errorfig,endflg:boolean;

fcacahacach tanta ninialnciacintnchaciacdichacececiedettdiadectaathtlecidiededadidachn taeitcheaitidaiiadiieeietniaiaeiaedhieceiniedl |

procedure aprocess,

{ This procedure will compute the TE and TL values for all nodes in the
graph and then print the critical path. }

var nodenum,edgenum: integer;

begin
{ initialize to compute TE values }
nodenum := 1;
edgenum := 1;
{ compute TE value for each node }
while nodenum < nonodes do
begin
while edgenum < pointer[nodenum + 1] do
begin
if te[dest[edgenum]| < te{nodenum] + time[edgenum]
then te[dest{edgenum]] := te[nodenum] + time[edgenum];
edgenum := edgenum + 1
end;
nodenum := nodenum + 1
end;
{ initialize to compute TL values }
t![nodenurn] := te[nodenum];
nodenum := nonodes — 1;
edgenurn := noedges;
{ compute TL value for each node }
while nodenaum >= 1 do
begin
while edgenum >= pointer[nodenum] do
begin
if tl[nodenum] > tl[dest/edgenum]] - time[edgenum]

5-102
then tl[nodenum] := tl[dest[edgenum]] — time[edgenum];
edgenum := edgenum - 1
end;
nodenum := nodenum - 1
end;
{ print nodes on the critical path }
writeln; writeln;
writeln('CRITICAL PATH’);
writeln;
writeln(' NODE# DATA’ :17);
for nodenum := 1 to nonodes do
if te[nodenum] = tl[nodenum]
then writeln(nodenum:5,data{ncodenum]:12);
end;

(ERA ESA BG dora oo ididdaaagai iol iciddbidaabagagiea agg oii iaok

begin
{ initializations }
nonodes := 0;
noedges := 0;
for i:= 1 tondo
te[i] := 0;
for i:=
1 ton do
tllij-:-== 32767;
endflg := false;
{ read data until end of input }
while (not cof) and (not endflg) do
begin
readIn(Origin,
Info, Weight,End);
if Origin < nonodes
then begin
writeln(/DATA OUT OF SEQUENCE’);
errorflg := true;
endflg := true
end
else begin
if Info <> /?!
then data[Origin] := Info;
{ check for new originating node }
if Origin > nonodes
then begin
nonodes := nonodes + 1;
pointer[nonodes] := noedges + 1;
{ check for sink node }

2-103
if End <= 0
then endflg := true
else begin
noedges :== noedges + 1;
time[noedges] := Weight;
dest[noedges] :== End
end
end
else { same originating node as before }
i? End <= 0
then begin
writeln(/ NONSINK NODE HAS EDGE WITH
INVALID DESTINATION’);
errorflg := true;
endfig := true
end
else begin
noedges := noedges + 1;
time[noedges] := Weight;
dest[noedges] := End
end
end
end;
{ print critical path if no errors encountered }
if (not errorfig)
then aprocess
end.

THE FOLLOWING DATA CORRESPONDING TO FIGURE 5-5.1


GENERATED THE FOLLOWING RESULTS:
age ee?
1? QE S
aie ee
Ra ae ea
3c 4 4
Boe ot O
Ad=-12 6
5e t 2x6
6f5 0:9

5-104
CRITICAL PATH
NODE# DATA
1 a
3 c
4 d
6 f

prograrn Ipert(input,output);

{ This program will set up the linked structures that reflect the relationships
existing in a pert graph as discussed at the end of section 5-5.1. After this is
done, the TE and TL values are computed for each node and the critical path
is printed out. }

{ Note that when a new origination node is to be processed, it is >ssumed that


it already exists in the structure. The edges must be read in order starting
with the smallest origin and going to the largest. }

const max = 20;

type nptr = fnnode;


eptr = fenode;
nnode = record
out:eptr;
data:integer;
te:integer;
tl:integer;
inp:eptr;
link:nptr
end;
enode = record
outl:eptr;
source:nptr;
time:integer;
dest:nptr;
inl:eptr;
end;

var temp,p,save,y,x:nptr;
Weight, Origin ,End:integer;
nonodes:integer;
esave,z:eptr;
errorflg,endfig,
found: boolean;

(HHen aoeneneconnen aon anoneanoanioainieannadinionacreries senes)

SOS
procedure Iprocess;

{ This procedure computes and stores te TE and TL values for each node and
then prints those nodes which lie on the critical path. Note that a stack is
used to go back up the list of event nodes. }

var top:integer;
nodenum,temp:nptr;
edgenum:eptr;
s:array|1..max]| of nptr;

begin
{ initializations }
nodenum := p;
edgenum := nodenumf.out;
top := 0;
{ compute TE values }
while nodenumf.link <> nil dc
begin
while edgenum <> nil do
begin
temp := edgenumf].dest;
if tempt.te < nodenumf].te + edgenumf.time
then tempf{.te := nodenumf.te + edgenumf.time;
edgenum := edgenumf.outl
end;
top := top + 1;
s|top] := nodenum;
nodenum := nodenumf.link;
edgenum := nodenumf.out
end;
{ initializations }
nodenumf.tl := nodenumf.te;
{ compute TL values }
while top <> 0do
begin
nodenum := s[top];
top := top - 1;
edgenum := nodenumf.out;
while edgenum <> nildo
begin
temp := edgenumf.dest;
if nodenum}.tl > tempf.ti — edgenumf.time
then nodenumf.t! := tempf.tl — edgenumft.time;
edgenum := edgenumf.outl
end
5-106
end;
{ output nodes on critical path }
writeln; writeln;
writeln('CRITICAL PATH’);
while nodenum <> nil do
begin
if nodenum{.te = nodenumf.tl
then writeln(nodenumf.data);
nodenum := nodenumf.link
end
end;

ABABA BAB EAB ESAS EAE BOAO EEE E OE SASHES HEHE HEE E+ +}

begin
{ initializations }
nonodes := 0;
readIn(Origin, Weight,End);
new(p);
pt.data := Origin;
Di.tec== 0:
p [stl :==-32767;
pft-inp := nil;
pf.out := nil;
pf.link := nil;
temp := p;
endfig := false;
errorflg := false;
{ process remaining data }
while not endflg do
begin
{ error on input? }
if (Origin < nonodes) or ((Origin = nonodes) and (End <= 0))
then begin
writeln(/DATA OUT OF SEQUENCE OR INVALID
DESTINATION’);
errorfig := true;
endflg := true
end
else begin
{ new originating node? }
if Origin > nonodes
then begin
if tempf.link <> nil
then temp := tempf.link;

2-107
if (temp{.data <> Origin)
then begin
. writeln(/EXTRA SOURCE OR SINK
NODE ENCOUNTERED’);
errorflg := true;
endfig := true
end
else begin
nonodes := nonodes + 1;
if End <=0
then endflg := true
end
end;
if not endflg
then begin
{ is end node in the list? }
save := temp;
x := tempf.link;
found := false;
while (x <> nil) and (not found) do
begin
if xt.data = End
then found := true
else begin
save := x;
x := xf.link
end
end;
if x = nil
then begin
new(y);
y{.data := End;
yt.te := 0;
yt.tl := 32767;
yf.out := nil;
yf.inp := nil;
savef.link := y;
yf.link := x;
xi=y
end
else if xf.data <> End
then begin
new(y);
y{.data := End;
yf.te := 0;

5-108
yf{.tl := 32767;
yt.out := nil;
yft.inp := nil;
savef.link := y;
yf-link := x;
X i= y
end;
{ set up edge node }
new(z);
zt.outl := nil;
zf.inl := nil;
z{.source := temp;
z{.time := Weight;.
z{.dest := x;
{ insert edge into out list of temp }
if tempf.out <> nil
then begin
esave := tempf.out;
while esavef.out! <> nil do
esave := esavef.outl;
esavef.outl := z
end
else tempt.out := z;
{ insert edge into list of x }
if xt.inp <> nil
then begin
esave := xf.inp;
while esavef.inl <> nil do
esave := esavef.ial;
esavef.inl] := z
end
else xf.inp := 2;
{ get next input }
if cof
then endflg := true
else readIn(Origin, Weight,End)
end
end
end;
{ Print out critical path if no errors encountered }
if not errorfig
then Iprocess
end.

9-109
THE FOLLOWING DATA CORRESPONDING TO FIGURE 5-5.1
GENERATED THE FOLLOWING RESULTS:
1

WLW
HD
WH
OrFnNnwr
Ankh
DH
wWWH LO
W
LP
—&
COoAAD

CRITICAL PATH
1
3
4
6

EXERCISES SECTION 5-5.2 PAGE 488

1) Procedure POINTDELETE(HEAD). Given HEAD, the pointer to the


master node, and x, and y;, the coordinates of a point, this procedure finds the
node corresponding to the point and uses the PDELETE function to delete the
node representing the point and deletes all lines of which the point is an
endpoint.

1. [Initializations]
P + PLINK(HEAD)
2. [Test point against arguments|
Repeat while P ge HEAD
If X(p) == x, and Y(P) = y,
then Call PDELETE(HEAD,P)
Return
else P «+ RLINK(P)
3. [Point not found]
Write(/ERROR: NO POINT MATCH’)
Return

2) Procedure ENTITYDELETE(ENT,TRANS,HEAD). Given ENT, the


master node of a substructure, TRANS, a transformation matrix, and HEAD,
a pointer that points to the master node of the structure, this procedure finds
the ENTITY that references ENS and has TMATRIX = TRANS, and deletes
this node.
5-110
1. [Initializations]
P + ELINK(HEAD)
2. [Test entity against arguments]
Repeat while P 54 HEAD
If MLINK(P) = ENT and TMATRIX(P) = TRANS
then Call ENTDELETE(ENT,P)
Return
else P + RLINK(P)
3. [Entity not found]
Write(/ERROR: NO ENTITY MATCH’)

3) Procedure PDELETE(HEAD,P). Given HEAD, the pointer to a master


node, and P, the pointer to the point node to be deleted, this procedure
deletes the point referenced and all lines of which the point is an endpoint.

1. [Remove referenced lines]


Repeat while LINK1(P) 44 NULL
Call LINEDELETE(LINK 1(P))
2. [Change links]
If RLINK(P) 4 HEAD
then LLINK(RLINK(P)) — LLINK(P)
If LLINK(P) = HEAD
then PLINK(HEAD) + RLINK(P)
else RLINK(LLINK(P)) + RLINK(P)
3. [Delete point node] :
AVAIL — P
Return

Procedure ENTDELETE(HEAD,P). Given HEAD, a poititer that points


to the master node of the structure, and P, a pointer
to the ENTITY node to
be deleted, this procedure removes the ENTITY node from
the ring.

1. {Change link fields]


If RLINK(P) 5 HEAD
then LLINK(RLINK(P)) — LLINK(P)
If LLINK(P) = HEAD
then ELINK(HEAD) — RLINK(P)
else RLINK(LLINK(P)) — RLINK(P)
2. [Delete the ENTITY node]
AVAIL + P
Return

5- ia
EXERCISES SECTION 5-5.3 PAGE 498

1) 4217536 4721536 7421536 7534216


4271536 4725136 7425136 7534261
4275136 4725316 7425316 7542136
4275316 4725361 7425361 7542316
4275361 4752136 7452136 7542361
4752316 7452316 7543216
4752361 7452361 7543261
4753216 7453216
4753261 7453261

K? QUEUE °-Q
4 4
7 4-7
4 ts Z
12 NULL
7 2 5
225 NULL
Z 5 1-6
o-1 6
NULL
5 1 3-6
1-3 6
NULL
prog NULL —

NULL 6 3

6 NULL
6 NULL NULL
wn ave
FILE

TRANSACTION

Trace of CONSTRUCT:

N ~PRED SUC ted


0 FIELD KEY
1 i
2 1

RECORD FIELD
3 5
7
RECORD KEY
5
1
RECORD — FILE
5

8
4
RECORD TRANSACTION
5
5 3
FILE TRANSACTION
8
3
FIELD RECORD

qn

STS
RESULTING STRUCTURE:

Be eee eenag 1 iget eee SUCLIST


| tp DOSES ie
GOONS ee ees ee (Pea | eee
er ren ed ID
RECORD 4———Oe re sh
| ee
PED pee kG Se aE
FLE ¢—— eae eee
Saori i a
Topological Sort: no action is performed because the condition of
PREDCOUNT = 0 & DESPTR ea NULL is never true.

Trace of DETECT_CYCLE:

IP J. K PRINT
lee NLD
2
3. NULL
4
5, 88 tT
6
Doe tl
8
gu 53
1
5
7
5 0
7 Sie 0
5 7.5 RECORD
7 FIELD
5 RECORD
Structure after execution of step 4:

DESPTR ee
ee lee
Structure after execution of step 5:

Procedure TOPOLOGICAL_SORT could completely order the set of


descriptors if 2 pairs of descriptors read by procedure CONSTRUCT were
duplicates. Procedure CONSTRUCT will insert the descriptors into the table
only once, even if they are read in twice. However, the PREDCOUNT of the
successor is incremented twice instead of once, and the SUCLIST of the
predecessor will have the successor node appearing twice. In procedure
TOPOLOGICAL_SORT, when the SUCLIST of the predecessor is being
traversed, the PREDCOUNT of the successor will be decremented twice,
which removes the error generated by reading in the pair of descriptors twice.

EXERCISES SECTION 5-6 PAGE 530

la) If we know the address of a block (i.e. the memory location of its first word)
and if we also know the size of the block, then the address of its buddy can be
easily SOtCOR HEL First, observe that the address of a block of size 2! is a
multiple of 2', ie. the address in binary notation has at least i zeros at the
right. Therefore, a block of size, say 32, has an address of the form xx ...
x00000; if it is split, the newly formed buddy blocks have address xx ...
x100000 and xx ... x110000.
In general, then, the address of the buddy of the block of size 2! whose
address is x can be given by:

buddy(x) = x + 2'ifx mod 2'+! = 0


x — Qhif
x mod-ait! ==-9%
Function ALLOCATE_BIN_BUDDY(N). This function receives a
request for a block of size N, and returns a pointer, P, set to the address of a
block of size 2', which is the smallest size larger than or equal to N. It is
assumed that the size of memory available for memory requests is 2™.

Det
1. [Determine block size]
IfN>2tm
then Return (NULL)
else I+ 0
Repeat while 2fI<N
I+I+1
2. [Find first available block]
J+1
Repeat while SUC(AVAIL[J]) = AVAIL[J]
Je J+1
IffJ>m
then Return(NULL)
P + SUC(AVAIL{J})
Call DELETE(P)
3. [Split as required until correct size is reached]
Repeat while J > I and J > K
Q.— P +2 f (J - 1)
Call INSERT(Q,J — 1)
J SIZE(P) 2s 1
4. [Allocate block P]
FREE(P) < 1
- Return(P)

Procedure FREE_BIN_BUDDY{(P). Given a block beginning at address


P, this procedure inserts it (or merges it with appropriate buddies) onto the
proper free list. :

1. [Perform all possible mergers]


Repeat thru step 2 while SIZE(P) < m
2. [Merge blocks?|
If P mod (2 f (SIZE(P) + 1)) =0
then Q+P +2 SIZE(P)
else Q+P-2 ft SIZE(P)
If FREE(P) and SIZE(Q) = SIZE(P)
then Call DELETE(Q)
iQ <P
then P+Q
SIZE(P) < SIZE(P) + 1
else Call INSERT(P,SIZE(P))
Return
3. [We get here only if P is maximal block]
Call INSERT(P,m)
Return

5-116
Fo =5
F, =8
F, = 13

F, = 21
F,= 214+5=26
F, = 26+ 8 = 34
F, = 34+ 13 = 47
F, = 47 + 21 = 68
Fz = 68 + 26 = 94

SS
NANG
rm
“ONISSHOOUdMAVIVAAYE
LNIWOOAUALAINOOVLYGdYaLNINOO' “WOO
f 1VYV
as €T TS
eeea
a
“ '"VLVGdAHYaLAdWNOOAYTLAANOO
'§ 1OYV

5-118
“vy EVaGddyaLAdWOOdHULNdIWNOOd
%
1OYV
“ -@<yaLAdWOO
:[T J9dJV
tAyetuy—(¢
a0
ao
nw
“* "@866-LdWNO- “WOO
CY

Sahhg
GAYA LNAINOOANALNAIN OO” “WOO
at -@832-LdWODNISSAOOUdAVLV
9 1OyJV
'* "@8tS-LAdNWOONISSAOOUdAVLVGAHTLNINOOAYALNIWOOVLILVGANALNdIWNOO? “WOO
1g YV
:§ 1EYV
~— “@-LdNG&soo-LdWod
“"

WOO

nnn
mon
on
LoYV
6

“GNGAAHLZ-
'" LdWa8t3-LdWo-

‘WOO

5-920
4a) Algorithm COMPACT_STRING. This algorithm compacts the allocated
strings into one contiguous section at the low-order end of string space. The
allocated string descriptors are assumed to be represented in a vector of
structures, with fields LEN, giving the length of the string, and LOC, giving
the location of the string. NO_ALLOC is a global variable holding the
number of allocated string descriptors.

1. [Engage loop to scan through string space vector]


FREESPOT + 1
Repeat step 2 for I = 1, 2, .... NO_ALLOC
2. [Check for available space]
LENGTH + ALLOC[]].LEN
X + ALLOC|I].LOC
If X > FREESPOT
then STOP + X + LENGTH
Repeat, for: N\=="X; Xo-f17..., SLOP
STRING_SPACE[FREESPOT] ~— STRING_SPACE|N]
Repeat while ALLOC[I]|.LOC = N
ALLOC[I].LOC + FREESPOT
I+I+1
If ALLOC[].LOC + ALLOC[I].LEN > STOP
then STOP + ALLOC[I].LOC + ALLOC[I].LEN
else FREESPOT + FREESPOT + LENGTH
3. [Finished]
Exit

b) The string space in the following question would be changed as follows:

COMCMPT-228BMPT-2THES$END .

5) Algorithm GARBAGE COLLECTOR. This garbage


algorithm would be invoked by a list-manipulating subsystem when the
collection

number of storage cells on the availability list has shrunk to size MIN. This
algorithm does not check for such a condition. It is assumed all of the nodes
have the following fields: DPTR, INFO, RPTR, and GARBAGE_MARK: a bit
indicating whether or not the node is accessed by a program variable. M is a
global constant holding the size of one node in memory. MEM_AREA is a
global pointer to the first cell in this area of memory on which the algorithm
is to operate. END_MEM_AREA isa global pointer to the last memory area.
AVAIL is a global pointer to the first cell on the availability list.
VAR_NAME_LIST is a global vector containing J variable names. It is
assumed that all nodes originally have GARBAGE MARK set to false. A
stack S, indexed by TOP, is used in marking the nodes.

5-124
1. [Follow the lists of each variable name, marking nodes}
Repeat thru step 4 forI = 1, 2, ... J
2. [Initializations]
P — VAR_NAME_LISTII] -
GARBAGE_MARK(P) + 1
P — RPTR(P)
TOP+1
SITOP] — NULL
3. [Scan thru variable’s list]
Repeat step 4 while P 54 NULL
4. [Has node been marked?|
If GARBAGE_MARK(P)
then P + S(TOP)
TOP
+ TOP -1
else GARBAGE_MARK(P) + true
If RPTR(P) 54 NULL
then TOP + TOP +1
SITOP] — RPTR(P)
If DPTR(P) 4 NULL
then P + DPTR(P)
else P+ S[TOP]
TOP
— TOP -1
5. [Mark all elements on the availability list]
P + AVAIL
Repeat while (P +4 NULL)
GARBAGE_MARK(P) + true
P + RPTR(P)
6. [Place all non-marked nodes on availability list]
P + MEM_AREA
Repeat while (P < END_MEM_AREA)
If GARBAGE_MARK(P) > true
then RPTR(P) + AVAIL
DPTR{(P) — NULL
AVAIL +P
else (prepare for next invocation)
GARBAGE_MARK(P) + false
P-—P+M
7. [Finished]
Exit

Bate2
6) It is assumed that MIN = 10.

Initially

RequestB

jes |] fe YY
RequestC

[es | [fo
RequestB

par fe
Vi
RequestA

w Ys Ve VY
Release B1

Eau AE
Bs Ae We
RequestA

Release Cl

|549 rH [15 | [24 Y fio WA [24 WA

Request A

Request B

Release A2

SOE DEVE
AE Deye

bes
CHAPTER 6

SORTING AND SEARCHING


EXERCISES SECTION 6-1 PAGE 568

1) Procedure BUBBLE(K,N). Given a vector K, of N elements, this


procedure rearranges them in ascending order using a bubble sort that ignores
all records below and including the last one to be exchanged, since these
records must be in the correct order. TEMP, I, and J are index variables.

1. [Loop on pass index]


I+N-1
Repeat thru step 3 while I > 1
2. [Initialize interchange marker]
FLAG + 0
3. [Make pass]
Repeat for J = 1, 2, ..., I
If K[J + 1] < K{J]
then FLAG + 1
RiJ] <> RiJ + 1)
TEMP + J |
If FLAG = 0
then Return
else I+ TEMP -1
4. [Finished]
Return

i)— Procedure TWO_WAY_BUBBLE(K,N). This algorithm performs a


bubble sort on vector K with N elements such that alternate passes go in
opposite directions, i.e., passes are performed moving upward and downward.
Variables I, J and M are used as indices.

1. [Perform a double pass]


M —0
Repeat thru step 4 for 1 = 1, 2, ..., [N/2|
2. [Initialize interchange marker]
FLAG +0
3. [Make a pass down the table]
Repeat for J=M+1,M+2,...,N-I
If K[J + 1] < K{J]
then FLAG ~ 1
K[J] <> K[J + 1]
J+N-I
If FLAG = 0
then Return
4. |Make a pass up the table]
FLAG + 0
Repeat for M = J- 1, I= Ds tea)
If K[M + 1] < K[M]
then FLAG <— 1
K[M!] <-> K[M + 1]
M+ I
If FLAG = 0
then Return
5. [Finished]
Return

3) Procedure LINKED _SELECTION(HEAD). This procedure performs a


selection sort on the linked list given by HEAD. X is the position in the
linked list in which we want to place the next smallest record according to its
key. MIN points to the element with the smallest key in the rest of the
elements. PREV is used to find PREVMIN, the element before MIN in the
linked list. PREVM is the element before X in the linked list.

1. [Initializations]
~' PREVM + HEAD
X + LINK(HEAD)
If X = NULL
then Return
2. {Perform sort] ;
Repeat thru step 5 while LINK(X) 54 NULL
3. [Initialize to find smallest of remaining keys]
MIN + TEMP + X
4. [Find’smallest key]
Repeat while LINK(TEMP) 34 NULL
PREV «+ TEMP
TEMP + LINK(TEMP)
If K(TEMP) < K(MIN)
then
MIN «+ TEMP
PREVMIN + PREV
5. [Readjust pointers]
If X +4 MIN
then LINK(PREVM) + MIN
LINK(PREVMIN) + LINK(MIN)
LINK(MIN) + X
PREVM < MIN
else PREVM +- X
X + LINK(X)
6. [Finished]
Return
L A L

L
t-OI> eee T@>rt

20I>99
T+

L d

|&<s8 |9<7
a
L<9

RAE

o> 9e>

s9>%6
It IT
oe=[I

& >Prl
> 39
a> GE> 9>

89
39>
L|
|
L|anat>
L|ran>@H|d4°
a4
i<e
a0
(1M

so=|s]y
1=(0

11=(JM
(U4

11=(elM
jason] 1S¢ [a4°.L|[ebi> aN

BH & HRA HHH


A &,
>a

Tl>

&S> 8>s9 r6>


66> Gh
> Gt
18>th

t6>

99
9
89>
99>

IT
Gh
Gr
Gh

TI>11 99 bL>
66>39 99
ss>

+2=[ah1 wb) 99=|9]M


is=[ot)M|a—{t}4 |or
(ria | aan

se=[el1
|
ge==[Tby] T1==[tbi| so=[sb1)

6 8 ZL 9 9 y © @ I or
6 8 Z 9 9 9
|r

mao
LT<Ol

iL
I<e Jb<E£ L<3
ot} Tt

or; 3
£

or; 9
oe

0
31%

¥
¥
L

L
T

Tt
T
0

IT
z

0
oT

oT

ot
gj

z
T

z
T

Uaddn
kIMOT
|
|d-°
(F
Li@i<an
W=dOL|doL
1
|a@7|
gn

6-3
60I> 2-6

8e>21e8

L
6<8

6<0T
18> 6
L8>FL
rZ=([4)4
zs=(2]M

r6>FL
66
¥6>

re=(6)M
L>01

18 bl>

66>
L8>¥6

66=(oT]1

6
ze=(2)1

FL>¥6
¥6=[zbi] 01

is=(z)1|
8
|

L 8 6 bo

OT<OT 6<3

L<L

or 6
L4<OT
2
[OT]

L J.
2
8) L
L/2

6-4
5) Procedure BINARY_TREE_SORT(K,N). This procedure will perform ~
a binary tree sort on a vector K of N records so that the records are ordered
on ascending keys. P points to the newly created tree. It is assumed that
procedures INSERT and INORDER exist: procedure INSERT inserts the given
key into the binary tree with specified root node; procedure RINORDER
traverses the tree in inorder, printing the keys associated with each node.

1. [Create the tree]


P <— NODE
INFO(P) — K{1]
LPTR(P) — RPTR(P) + NULL
Repeat for I = 2, 3, ..., N
Call INSERT(P, K{l])
2. [Traverse the tree to sort]
Call RINORDER(P)
3. [Finished]
Return

Given table K:

K[l] 42
K[2] 23
K([3] 74
Ra id
K[5] 65
K[6] 58
K[7} 94
K{[3} 3
K{9] 9
K[10] 87

6-5
ge [tly 6

ae

6-6
zs-igiM
ez-iM | or
M@evL fuoly gw»t xmiKx(ly aan ([chi<l+r agtoL O>tr aL Tost ff ADI GAVS Obici
for}s4
|
(ol
(2ba [s!>

vL a 9>8 8 *
[sia (ola

WB
T1<¢e a L 95h r z
feba
19%

(cla

ag<
iL 952 3S Ir II 1) 'olzb
gg

$3
TI<¢9 a
[thi L
[hy

6-7
FL (tha
lor
3 lela [4b 1 J L>¥hI | #1 L
(slo

It
(cha fi

B
le}ss— L 11<89
(o}i

&& GF

w<s9
9£ac
L>9

leba itl
8

F271)
&

L
TI<L

lela
is—|s41

99<FL
(ty L ge zIr
I
8tt

(ici
&
i1{tIy
L>2%
at,

[t4+24
=a-o

[rha<
45L TOSt ¢ ABM BAYS 1 Oly—-MN

B
Ami<[hi don dio, O>tty
eelely
<<
0o-[M
L 9E< SF cE
all
or<89
a0
ss]
i als ge<gg es
fhi-t oa oL Ami<ithi aton [thi<t4ry dL O>ttr Ato. folu-ftiIN ©

I
co>e
se e 1r—[y
(1M ld [UM

iG
a

It<9e €6<
11

9e<
ez

L a

re e>e

LZ d kL a

Scan esr ZS Tso)

|e
Calaere|F CacEe
abe |.)
Se UT

Ir e Tet

I} z ||
{thwlth esti dette

| ge—lehi £2
(21M
capes
se
a +
gees
bi<lG+bi

lOM-aN
xai<ib
fbi
Lost
IaL
GAVS
©ABM
4-2
a-n
O>tr
aon |e eles

6-9
HEAP_SORT creates a heap:

K{1] 99
K[2] 94
Kal. 74
K[4] 65
5.82
K[6] 42
K(7] 58
Ks} ie ad
K[9]} 36
K[10] 23

Klip. “1
Klas 23
K[3] 36
K[4] 42
K[5] 58
K{[6] 65
Kz) hive
Kis] 87
K{[9] 94
K[10] 99
Procedure ADVANTAGE_MERGE(K,N). Given a vector K, with N
elements, this procedure performs a merge sort on the table, taking advantage
of the order already existing within the table. Ordered sections of the table
are found and the procedure SIMPLE_MERGE is used to merge the sections.
Variables I and J mark the end of the first and second ordered sections
respectively.

1. [Initializations]
I~ 1
2. [Find the first ordered segment]
Repeat while I << N
If K[I] < K[I + ]]
then I[+I+1
else Exitloop
3. [Initial table ordered?|
Ir l= N
then Return
4. [Initialize J]
Scrlel
5. [Find end of second segment and merge|
Repeat while J < N
If K[J] > K[J + 1]
then Call SIMPLE_MERGE(K,],J)
I+ J
a
6. [Final merge]
I,J)
Call SIMPLE_MERGE(K
7. [Finished]
Return

Procedure SIMPLE_MERGE(K,!,J). This procedure merges the two


ordered segments whose endpoints are indicated by I and J from vector K
using vector C. This procedure is very similar to the one given in the text.

1. [Initializations]
P+Q+1
R+I+1 be
Repeat while P <ITandR< J >
If K[P] < K[R]
then C[Q] — K[P]
P+P+1
else C[{Q] + K[R]
R+-R+1
Q+Q+1
2. [Copy remaining records]
We
then Repeat forS =R,R+1.,..., J
Cla] — Kis
QQ
else Repeat for S =P, P + 1.,..., I

Repeat for R =.1; 2,..., J


K[R] <= C[R]
3. [Finished]
Return
8) Function LINKED_SIMPLE_MERGE(A,B). Given two ordered linked
lists, with A and B as pointers to the first nodes in each respective list, this
function merges the lists and a pointer to the first node in the new list.

1. [Initializations]
If, A = NULL
then Return(B)
If B = NULL
then Return(A)
If K(A) < K(B)
thenC-—Q+aA
A+B
else C+Q+bB
2. [Compare records and append the smallest]
Repeat while LINK(Q) 4 NULL —
If K(LINK(Q)) < K(A)
then Q + LINK(Q)
else B << LINK(Q)
Q + LINK(Q) + A
A+B
3. [Append remaining unprocessed records]
LINK(Q) + A
Return(C)

Procedure CIRC_RADIX_SORT(K,N). Given a table of N records


arranged as a linked list, this procedure performs a radix sort as given in the
text with the exception that this procedure uses circular queues instead of
linear queues. All variables are the same as in procedure RADIX_SORT.

1. [Perform sort]
Repeat thru step 4 for J = 1, 2, ...,M
2. [Initialize pass]
Repeat for I = 0, 1, ..., 9
T[I] — B[}] — NULL
R + FIRST
3. [Distribute each record in the appropriate pocket]
Repeat while R 54 NULL
D+ by (obtain the Jth digit of the key K{R))
NEXT +- LINK(R)
If T[D] = NULL
then T{D] + BID] —R
LINK(R) «+ R
else LINK(T{[D]) —R
T[D] +R
LINK(R) + B[D]
R + NEXT
6-12
4. [Combine the pockets]
P+0O
Repeat while B[P] == NULL
P-—P+1
FIRST + PIP]
Repeat fort =P 15P 4+)245,9
PREV < T[I - 1]
If T[l] #4 NULL
then LINK(PREV) < Bil]
else T{I] + PREV
LINK(T{9}) — NULL
5. [Finished]
Return

EXERCISES SECTION 6-2.3.1 PAGE 585

1) HEAD

co
7

x
loos 6
Insert 6:

pean]
/e]8 [paral/
Insert 7:

Insert 8:

After
Balancing:

Insert 12:
Insert 15:

After
Balancing:

Insert 17:

After
Balancing:

Hex]
=P
appara
AUBExZIN /pskppatal
/19[2[oatal/ /[e[B]patal)
6-15
Insert 9:

ep
CBee

Insert 10:

After
Balancing:
3) Function BAL_DEL(HEAD,X,PATH,LEVEL,DIRECTION). This is
a recursive procedure which deletes the node with information field X from the
height balanced binary tree pointed to by HEAD. A path of the ancestors of
the node is built up using PATH: a vector of pointers to the path nodes;
DIRECTION: a vector specifying the direction taken at each level; and
LEVEL: an index into the vectors at the current level. This function returns a
pointer to the new balanced tree. Procedure REBAL, given below, is invoked
to carry out the rebalancing if necessary.

i [Check for empty tree]


If HEAD = NULL
then Return(NULL)
[Check for branch left]
If X < DATA(HEAD)
then LEVEL «— LEVEL + 1
PATH|LEVEL] « HEAD
DIRECTION|[LEVEL] + ‘1!
LPTR(HEAD) + BAL_DEL(LPTR(HEAD),X,PATH,LEVEL,
DIRECTION)
Return HEAD
[Check]
If X > DATA(HEAD)
then LEVEL + LEVEL + 1
PATH|LEVEL]+- HEAD
DIRECTION|LEVEL] + ‘R!
RPTR(HEAD) + BAL_DEL{RPTR(HEAD),X,PATH,LEVEL,
DIRECTION)
Return(HEAD)
[Delete node]
If RPTR(HEAD) NULL and LPTR(HEAD) 4 NULL
then (replace node with inorder pred/succ)
If BI(HEAD) = 'L!
then (find inorder pred)
PRED ~ LPTR(HEAD)
Repeat while (RPTR(PRED) +4 NULL)
PRED + RPTR(PRED)
(delete pred)
LEVEL «+LEVEL + 1
PATH|LEVEL] «+ HEAD
DIRECTION|LEVEL] + ‘L!
LPTR(HEAD) + BAL_DEL(LPTR(HEAD),DATA(PRED) ,

PATH,LEVEL,DIRECTION) -
(reset links)
BI(PRED) + BI(HEAD)
LPTR(PRED) + LPTR(HEAD)

6-17
RPTR(PRED} + RPTR(HEAD)
Return(PRED)
else (find inorder succ)
SUCC «+ RPTR(HEAD)
Repeat while (LPTR(SUCC) 4 NULL)
SUCC + LPTR(SUCC)
(delete succ)
LEVEL «+ LEVEL + 1
PATH/LEVEL] + HEAD
DIRECTION[LEVEL] < 'R!
RPTR(HEAD) «+ BAL_DEL(RPTR(HEAD),DATA(SUCC),
PATH,LEVEL,DIRECTION)
(reset links)
BI(SUCC) «- BI(HEAD)
LPTR(SUCC) + LPTR(HEAD)
RPTR(SUCC) + RPTR(HEAD)
Return(SUCC)
else (determine what subtree - if any is not empty)
If LPTR(HEAD) +4 NULL
then REPLACE « LPTR(HEAD)
else REPLACE + RPTR(HEAD)
{rebalance thru path)
Repeat for I = 1, 2, .... LEVEL
PARENT +- PATH]
If DIRECTION[]] = ‘L!
then CHILD ~— LPTR(PARENT)
else CHILD + RPTR(PARENT)
If CHILD = HEAD
then If DIRECTION|I] = BI(PARENT)
then BI(PARENT) <- 'B!
else GRANPAR + PATH|I - }]
Call REBAL(PARENT,GRANPAR,DIRECTIONI]})
else If BI(CHILD) <> 'B!
then If BI(PARENT) = 'B!
then If DIRECTION|I] = ‘LU!
then BI(PARENT) < ‘R!
else BI(PARENT) + 'L!
else If DIRECTION|I] = BI(PARENT)
then BI(PARENT) < ‘B’
elee GRANPAR + PATHII - 1]
Call REBAL(PARENT,GRANPAR,
DIRECTIONII])
else If BI(PARENT) = DIRECTION|]]
then BI(PARENT) + ‘B’
else GRANPAR + PATHII - ]]
6=18
Call REBAL(PARENT,GRANPAR,
DIRECTION|]])
Return(REPLACE)

Procedure REBAL(GR,PAR,DIR). This procedure height balances the


tree pointed to by PAR and links it to its ancestor, GR.

1. {Handle all cases]


if DIR ="R’
then If BI(LPTR(PAR)) 'R!
then SAVE — LPTR(PAR)
LPTR(PAR) — RPTR(SAVE)
RPTR(SAVE) — PAR
else SAVE + RPTR(LPTR(PAR))
RPTR(LPTR(PAR)) — LPTR(SAVE)
LPTR(PAR) — RPTR(SAVE)
RPTR(SAVE) — PAR
else If BI(RPTR(PAR)) 4 'L!
then SAVE + RPTR(PAR)
RPTR(PAR) — LPTR(SAVE)
LPTR(SAVE) ~— PAR
else SAVE + LPTR(RPTR(PAR))
LPTR(RPTR(PAR)) — RPTR(SAVE)
RPTR(PAR) — LPTR(SAVE)
LPTR(SAVE) — PAR
2. [Set ancestor link]
If DATA(PAR) < DATA(GR)
then LPTR(GR) — SAVE
else RPTR(GR) + SAVE
3. [Set balance indicators]
BI(PAR) <— 'B
If BI(SAVE) = 'BY
then BI(SAVE) — DIR
else BI(SAVE) < ‘BY
EXERCISES SECTION 6-2.3.2 PAGE 594

1) Procedure BAL_DELETE(T,KEY). Given T, a pointer to a 2-3 tree and


KEY, the key of a node to be deleted, this procedure deletes the node,
maintaining a balanced tree structure. Function 2_3_DELETE is invoked if
the given tree is found to have height > 1. CHECK is a boolean variable
used to determine if the resulting tree has only one child left.

1. [Check for empty tree]


If T = NULL
then Write(/EMPTY TREE’)
Return
2. [Check for leaf|
If ~>TAG(T)
then If DATA(T) = KEY
then T «— NULL
else Write(/NODE DOES NOT EXIST’)
Return
3. [Invoke function to delete node]
CHECK + 2_3_DELETE(T,KEY)
4. [Only one child left?|
If CHECK
then T+ LPTR(T)
5. [Finished]
Return

Function 2_3_DELETE(T,KEY). This function deletes the node with


key value KEY from the 2-3 tree given by T. The function returns true if,
after performing the deletion, T has only one subtree; false if T still has two
or three subtrees. HEAD is assumed to be a global variable pointing to the
root of the entire structure. MAXVAL is assumed to be a function which
returns the maximum value found in the given subtree.

1. [Are the children of T leaves?


If -TAG(LPTR(T))
then If KEY < LDATA(T)
then (delete left child)
If DATA(LPTR(T)) = KEY
then LPTR(T) — MPTR(T)
MPTR(T) — RPTR(T)
RPTR(T) — NULL
LDATA(T) — DATA(LPTR(T))

6-20
If MPTR(T) = NULL
then Return(true)
else MDATA(T) — DATA(MPTR(T))
Return(false)
else Write(/NODE DOES NOT EXIST’)
Return(false)
If KEY < MDATA(T)
then (delete middle child)
If DATA(MPTR(T)) = KEY
then MPTR(T) — RPTR(T)
RPTR(T) — NULL
If MPTR(T) = NULL
then Return(true)
else MDATA(T) + DATA(MPTR(T))
Return(false)
else Write(/NODE DOES NOT EXIST’)
Return(false)
If RPTR(T) 54 NULL and DATA(RPTR(T)) = KEY
then (delete right child)
RPTR(T) — NULL
TEMP + MDATA(T)
(reset data indicators of ancestors)
Repeat while Q oa 3h
If X < LDATA(Q)
then If X = LDATA(Q)
then LDATA(Q) — TEMP
Q + LPTR(Q)
else IfX < MDATA(Q)
then If X = MDATA(Q)
then MDATA(Q) — TEMP
Q + MPTR(Q)
else Q «+ RPTR(Q)
Return(false)
else Write(/NODE DOES NOT EXIST’)
Return(false)
2. [Recursive call to delete node]
If X < LDATA(T)
then ONLYONE + 2_3 DELETE(LPTR(T),KEY))
else If X < MDATA(T)
then ONLYONE + 2.3 DELETE(MPTR(T),KEY)
else If RPTR(T) 4 NULL
then ONLYONE + 2_3_DELETE(RPTR(T),KEY)
else Write(NODE DOES NOT EXIST’)

6-21
3. [Fix children of node if necessary]
If ONLYONE
then (left subtree unbalanced?)
If KEY < LDATA(T)
then A + LPTR(T)
B + MPTR(T)
(move left child of middle sibling if possible)
If RPTR(B) 4 NULL
then MPTR(A) — LPTR(B)
LPTR(B) — MPTR(B)
MPTR(B) — RPTR(B)
RPTR(B) — NULL
MDATA(A) + LDATA(B)
LDATA(T) + LDATA(B)
MDTA(B) — MDATA(T)
Return(false)
else (move single node into middle sibling subtree)
RPTR(B) + MPTR(B)
MPTR(B) — LPTR(T)
LPTR(B) — LPTR(A)
LPTR(T) — MPTR(T)
MPTR(T) — RPTR(T)
RPTR(T) + NULL
LDATA(T) + MDATA(B)
MDATA(B) — LDATA(B)
LDATA(B) + LDATA(A)
If MPTR(T) = NULL
then Return(true)
else MDATA(T) + MAXVAL(MPTR(T))
Return(false)
(middle subtree unbalanced?)
If KEY < MDATA(T)
then A + MPTR(T)
B + LPTR(T)
(move right child of left sibling if possible)
If RPTR(B) +4 NULL
then MPTR(A) — LPTR(A)
LPTR(A) — RPTR(B)
RPTR(B) + NULL
MDATA(A) + LDATA(A)
MDATA(T) + LDATA(A)
LDATA(A) — LDATA(T)
LDATA(T) + MDATA(B)
Return(false)

6-22
else (move left child of right sibling ifpossible)
C + RPTR(T)
If C 4 NULL and RPTR(C) NULL
then. MPTR(A) — LPTR(C)
LPTR(C) — MPTR(C)
MPTR(C) — RPTR(C)
RPTR(C) —'NULL
MDATA(A) — LDATA(C)
MDATA(T) + LDATA(C)
LDATA(C) + MDATA(C)
MDATA(C) — MAXVAL(MPTR(C))
Return(false)
else (move single node into left sibling tree)
RPTR(B) — LPTR(A)
LDATA(T) — LDATA(A)
MPTR(T) «- RPTR(T)
RPTR(T) + NULL
If MPTR(T) = NULL
then Return(true)
else MDATA(T) + MDATA(C)
Return(false)
(right subtree unbalanced)
A + RPTR(T)
B + MPTR(T)
{move right child of middle sibling if possible)
If RPTR(T) 4 NULL
then MPTR(A) — LPTR(A)
LPTR(A) — RPTR(B)
RPTR(B) — NULL
MDATA(T) — MDATA(B)
MDATA(A) — LDATA(A)
LDATA(A) + MAXVAL(LPTR(A))
Return(false)
else (move single node into middle sibling subtree)
RPTR(B) + LPTR(A)
MDATA(T) + LDATA(A)
RPTR(T) — NULL
Return(false)
(eZ IZ0Id
We ‘(qndqno4ndut)seaij201q30M}

} styl WIeIZOId
st poUsIsep
04 4UaUIE;dUT
YIOq aq} yLasUlpue ojofop SUIYIIOS[S
1oJ E-Z *sa0I} eyeq
sI peal03 UNIOJI0d
YI0q sUOIzJesUI
pue ‘suolajap
pue 24}
voy st payepdn “A[Zurplooze
FY 243 ‘puse& UoONogiiaa
JO SSoU}991I09
SUI}SISUOD
Jo ue yndyno
Jo 94) 013st ‘Waal
{ .

adé4 4y4dopou
= ‘apou|
Ajapoa
od = ‘(yeajuou‘yeal)
opou= piooved
aseo Ajapou:3e}
od go
:Jeo] ‘(1a8aqut:eqep)
:Jeojuou UL-e4ep])
18a}
‘1ydapou:4d]
pw UL2}e 1930}
-I3dapou:14du

6-24
(43dapou:3yda
‘pue
suonesodo
= ‘(aj2[ep41asa1)

Iva -Jjdapou:ptoy
MouAoy -Ja3aqul:
pueww0d SuoI4eiado:

RARE RAEI TUCO


U GIG
EEE
O UU UE AOE
O eGR
Ges

UOTZOUNY ‘1a30}uI:(13dapou:3)feaxeul

} siyy uoKoUNy sumnjad


a4} WNUTIXeUl
anfea punoJ
UI ay} 9a13qnswaatd
Aq °9 {
y oY 4 kq
Ajuo sey 4 ‘UoNejep a4) Surusojied 109je ‘JU ons} SUINjar BOoUN
uonouny stqy }
UaAlZ 9014 E-g aq} Wor ‘Aoy ‘onfea Ady YIM apo 947 $999[9P
‘ueajoog:(s1e8aqut: Loy ‘13.dopou:4)[apyeqar uoyzouny
Ga aU EHEC IAA AAAAAR A EAR IR AAA AAA TAA AA AAAA
‘UvaJOOG: Yooyo IBA

{
‘TL =< y4B10Y & GARY 07 puNo] Jl a1} UIAIS 9} Jl POYOAU! SI [apjeqol Uorjouny
‘QINjonIys a1} paoueyeq & Buluteyureul ‘opou ay} sazojap einpaosoid siyy
‘paqajap aq 0} apou e& Jo Aay ony ‘ay pue aay E-Z & 0} JojUIOd & “4 UaAlH }
((1a8aqut: Aoy‘sydapou:7 1ea)azajapreq aainpasoid

6-25
GBR UBER IEEE OTE E EEE UG GEE ES ISUO EE bE obota tacks as }
:pua
eyep |b =: [eaxeul
{ 4[nsaz uingai }
‘aydur' |b ==: b asta
dr jb =: b uay4
ja <> dr |b Jy
op jeojuou = 3ey |b ayy
{ enjea unurrxeur Joy youvas }
ie" b
{ suoijeziyerqrur }
ujzeq
‘1ydapou:b va
au0 {a014qns
asyey
JI 3 [IVS Sey OM}10 9214} “se01}qQns
peay
st pouunsse
07 oq ©
yeqos afqeiea Surutod07 ayy 4001JO ay} “ainjonsys UOMouNy [EAXVUT
St
payoautl
0} BUIWIa}a
aq} p WNUNXeU
onfea
I punoy
UI 94} WoAIZ -9019qns
{
Ia -1ydapou:b‘o‘q‘e
-Ues[ooq:auo0AJUO9NsaI
dura} :Jasozut:

ulzaq
} are ay} uaIpyIyo
Jo4 {Saaea]
{
H ydt|4
| 3e7 = jea]
uay? ujZeq
} r2[ap932] éPIEq9
{
Jy Aoy =>ly eqyepy
uayy
} fox {punoj
{
a lydiaeqep'
= Aay

6-26
uay} ujZaq
|4 dy=: a9dur]4
]4 dur
==: 19 49d1°
14d1°}4
==: [ta
9 eyepy=: jy lagdy eqep
Jy sydur}4
= [ra
uayp 4[Nsol
=: oni}
asa ujZeq
eyepur|4
=: jagdur'|4
‘eqep’
4Nsol
=: as[ey
pus
pua
osja ujZeaq
UfoqtIM
ACON,)a1e
HLIM3t8AGM GNTVA
= ‘ay';
, SaOd LON (,LSIXA
‘peoy =: b
=:
dulay
‘eqepul'|y
yasar
szoyeorpul
}
{
=:
‘lu
dry
ujZeq way}
=
Jy
a
Aoy
eqep
jaydr
{ ipunoj fox } uayy
ju <> ndr{y yy
{ pitqo 44312 ajajap ysnur } asze
pua
asjey =: y[Nsod
(,LSIXA LON Sao ,‘404
‘, = ANTVA AGM HLIM ACGON,) 819M
UOT
ujBeq as{a

6-27
pue
pue
asjey =: 9[Nsaz
|
‘eqep' jagdur|4 =: eqgepur'
ujZaq as]a
ani) =: 3]hsel usy
pu = dur|3 gy
la =: ydr]4
‘aydi-}y =: sydur|4
uj3aq wey}
kay = eyep'jayydur
|) yy
{ jpunoy fay } uay4
eyepur|) => Aoy Jy
{ éPItq o[pprur aya]ep } asta
pue
as[ej =: 4[Nsol
-duia} =: vyepur |b uayy
‘dulay

‘,
=
eyepul
eqepp

GNTVA ‘,
‘(,LSIXA
=:
eyepy

=
dur |b =: b
|b = Aoy yy

ANIVA
eyepur |b =>

‘(,LSIXA
= {b
eyepy

‘ydr'
AGM
adj|b =: b

LON
yy Aoy
|b
uayy

|b
HLIM AGM
uey? uyZeq

=:
<> op}
Fy Ahoy =>|b

Sao LON
pua

b
asjaagjey AGON,) HLIM
Aay Jy asya

ag[ey
SaOd
pue
bayyn

‘404
=: ACGON,)uyeq
wey}
uyseq

=: as[ey]
UfOplIAn
faq
4Nse1 4Nsel ‘404
=:
Wop
uyZeq pue WNsol

pue
esja uyZaq

Pua
osja

pua

6-28
'
‘eyepy }q =: erepy|)
‘eyepy [q =: eyepurje
qi =: 4d1r}q
‘ydrjq =: ydur}q
‘ydurjq =: 4d,1q
‘dylq =: yndur le
ujZeq ayy
ja <> ndriq sy
{ aqissod Jt Zul[qis e[pplar Jo Pirq wel eaour
}4 =: q
‘yydur'
‘yd]y = 2
uj3eq ueq4
eyep [9 = > ANH
{ jpeoueyequn aai9qns 4J2| } ueyy
auod[uo Jf

6-29
{ Aressooau Jt apou Jo uerpyiyo dn xg }
‘pua
asey ==: euoduo
‘as[ey ==! ypnsed
(,LSIXA LON SHO ,
‘fox, = ANTWA AWM HLIM AGON,)81evM
U[aztIM
ulZaq as{a
(Aay‘s3dr }4)fappeqaz =: euodjuo uayy
ju <> dr] Jy esys
|4)japreqoi =: auodjuo uayy
(Aoy‘a9dur
eyepul'| => Aoy JT esa
(Aox‘19d] |9)japreqor =: euodjuo usy
=>
eyepp
A1H
ly
{ apou azajop 0} []@o aatsinoad }

uj3aq
asja
{ ‘(ajdur
2013
Suyqis |4)peaxeur

prut
‘eqepur as[zj
‘eyepur}q ‘eqepy =:
07 ‘eyepur
‘eqepy end}
14dur{q
apou 13d, -4ydr°
49dur'}4 =:
e7epur'|4
19d]
|y |q fa 4[NsaI
{
ase] je =: gpeoueysqun
=: =: aZuis }q le [tu [4
-aydur
4 =: =
=: =:

aydi-}9
Aydp']4
=: =: 4[Nsel
eyepur|q
eyept =: =: ==: =: dur ujZaq
==: ejyepur|q
aaou dur
ydr}q dur ezepyeyepy
ynsar dy dp
ndr pte
}4 usq? eqepur|y
| esje
== {4

q fq Iq |} ]4 4 {4 lq x
} 0a44qn3
puaujBaq
=
=

pua => ulZoq


ae q oo
esa
ajppyu
Aoy usyq?
J
pua }
asja

6-30
‘ndy je =: ydr|q
{ 4J9] 0} apou aaou }
ujZeq as{e
pue
anjcj ==! 4[Nsez
‘(ajdur9) feaxeul =: evyepur']o
‘eyepur jo =: eyepy fo
‘eqepy Jo =: eqepur}4
feqepy [o =: eqepur fe
qa ==: ydrjo
‘yydrjo =: ydurjo
f‘yydurjo =: dp fo
Jo =: dure
‘aqdp'

6-31
ujZeq ueqy

¢
iu <> dijo Fy ueyy
ju <> oF
{ @Zurqis 34311 Jo pjryo ye] eaour } see
pue
as[ej ==: 4jNsel
‘eqyepur|q =: eyepy{3
‘eqepy [9 =: eyepy le
|}
‘eqepy je =: eyepur
‘eqepy je ==: eyepurle
‘ra =: ydrfq
‘yydr fq =: 4ydy Je
‘yndpje =: ydur fe
uyseq Tey
a <> ndrlq gy
{ afqissod jr Surqis 9J2] JO pyiq> 34311 aout }
‘eqepul|>

as[ej ‘eqyepur}o
=:
‘eyepy and} eyepur'
==:
13d1°
[ra =: age]
4[NSed =:
je 14 [ta
== | { eqepy
Je] end} ejepur’
==:

{ ¢8utjqis prur Jo pyrqo yy3t1 eaour


=: ==: 4[Nsel
ulZeq ydy 9dr
=: sydur'|9
eyepy
1449dur}4 07 [lu 4[Nsor
4dr] je |4 s[iu =! {
uayy pue epouJe = peouvjequn
|9
as[a 4[Nsel 4
=: =: =: ==: sydur'|4
Jy
pus aaour eqepr
ydr{q dur
iydi'}4 pue
wayyy
{3 |4 Jy

ju <> ndrjq gy
}
uUlBaq es{a
ujZaq aamqqns

uyZaq way
pua
asja
yq3t

} 43d2°]4
@ {4
=: q‘aydur
=:

pua

asia
uy3eaq

6-32
ujZeq esa
pua

Upp
(,GqUL ALAN e194

ujZeq

ueyy
Ayduia

yooyo

}3[iu
=
aa13

ulZaq
soy
{
Ges G EEE IGE GEG ISI GOOG GARTER ZG UCE AGE RA EE A}

[epleqas

‘pua
qjnsol

==:

‘pua
pua

6-33
pue
eqepur'|4
ase] =:
4[Nsol

‘eqepy
[tae 19 ae

=:
je
=: je gdp
ydriq

ujSoq
asta
aacu apou0} Zurfqis {
qns e013 }
pua
agjey ==! 4[Nsel
‘eyepur|q =: eyepul' |}
‘equpur |4 =: vyepy le
‘eqepy le =: eyepur' le
‘iu =: ydrfq
‘yydrjq =: dpe
dp je =: ydur fe
} yooyosoy yeay apou
{
137 3e7
= jeg,
usyy
J] ezep'|4
= Aoy
Weqs
[{a\==.
9
asia ujZaq
Ujoqtm
Ua AGON,) HLIM ATM ANTVA
= ‘hex,
, Saod LON (,LSIXG
pus
asta ujZeq

}
{ 7
e2pou

=:
azajap

ayoaut

}
{
‘(404

yooyo
euo
é1J91
Pirqo

Jf
4
YOoqs
07 '9)[opreqar

=:
]9

6-34
Ajuo uayy
worjouny 14d]

pusa

pua

:_pua
aE} oi OOH
a OE S IEE
A OU
B EOI EEO EHUBGece

UOTZoUNY Aay‘14dapou:})z198uYeq
-49dapou:(sa8a3ur:

} sIyy, amnpasoid sziasul


® Ma OpoU qIIM Aay¥ ‘anjea“Aoy OUI 94} €-% 921}
aadfq ‘y Sururequiewu
e& pooueleq
201, “einyonsjs
oY UorouNy suinjel
@
JaqyuIod
03 ay} Mau *3a1} ainpsv01g yyedpuy
st payoaul
07 euTUIIa}0p
949 qyed
04 aq} Mou ‘apou pue einpedoidsUI[Ege!
SI PaYOAU!
07 s[PULY
oY} BSED 9194
Zulouepeqas
st ‘Aressaoou
{

IBA
‘ied

UL:
00]
“4;nsel‘yoo1

11939}
-1)da
ydur'|ind =: Ino asja
ond} =: puno} usyq4
Jeo] = 3e7'lmydur'Jino Jy asja
dr jind =: md ueyy
jiu <> ydrjino Jy esta
dur Jind =: mo wayyy
eqyepur Jind => Aay Jj esja
dj Jano =: mo uayqy
eqyepp lind => Aay Jy
‘ina =: [doy]s
‘T + doy =: doy
ulBeq
op (punoj 40u) pu (jeajuou = 3e4° Jind) afTy
{ 201) aq} puaosep }
‘asjey ==: punoj
== INO

6-35
: { suoneztyerqrat }
; ujZaq
‘UIJOOg: puno}j
‘1y3depou:ind IBA
{ ‘doy Aq paxapul s ‘yor4s
Jeqo[3 oy} Uo 41 BuIAes ‘ToMIesuI IOJ YQed 10}s99Ue 94} SaUIUIEZep sInped0i1d
siqy ‘Kay ‘q1asut aq 0} Aoy MoU 04} pue ‘2014 E-Z 0} JazUIOd & ‘4 UaAID }
{(493aqut: Aay‘1ydapou:3)q;edpug aanpesoid
EIA III TRACT TRACTOR AAA IORIAAA

‘193041:
‘Ijdapou
Aesze:s
Jo doy
[oor
1]
f
pue

‘pua
res TerreTeer
eee rrr
rr seer etter rerteceter
tote
cet etctt ilo Corre

einpesoid ‘red)suteqas 00]/13dapou:apoumou


Gt: ‘(1980

} uaaty‘red ayy ssaippe


Jo a4} “guard ‘epoumeu
oy} ssoippe
Jo aq} MaM ‘@pou
put ‘90, ayy UOTZISOd
Jo By} UOTZIasUI
“QuIodsty3 WotyoUNJ SUIOJied
oq} WOIZJOSUI
pue Buloucjeqa:
Jo oy} 2013 ayy UONUN] suINjel
© JoyUIod
0} 24} MOU 991}
109ye ‘worjiesut
{

rea edb Siydapou:zoc1uS

ulzeq
} ayeoro
e mau Jeajuon Jaqj301q
Joy zed{

6-36
mou ‘(b)
3e4°|b
==: ‘Jeajuou

==:
‘ta
} yds ay} amo uarpyryo uaamyoq
d pueb {
Od eraenhed
|

yda]b
|b Wd] =: Jared -ydur

uayy
ulZeq
|b
jred
‘dr
ydurdr
=: ‘lu
|red =:
fied
Jred
4ady
=: ydur
|red
|b
=: ==:
jared

|b
‘opoumou
‘eqyepur

14d],eyepy

=:
‘(aydur
fied
{red
‘eqepy
eyepur
==:eyepur
|b)jpeaxeur
Jred)jeaxeur

‘(agdur|sed)jeaxeu
(agdy

(4ydui|b)jeaxeur =: eqepur|b

(44dur |b)jeaxew =: vyepur |b


‘(4ydy

‘(4d
jared ajdr

|b)jeaxeur =: eqyepy fb

|b)peaxeur =: eyepy fb
‘aydrjaed =: ydur |b

‘yydi Jared =: 14d]']b

=:
‘(lu =: dr lied

‘lu ==:
=:
eqepy

eyepur
=:
yydur'

dsr fied
aed

ied
|b

‘ydurjred
{b
yd
=: Wdur
lied
‘@poumMeu
=: [ia
fied
yd =:eyepur
{b)jeaxeur
‘(ydur
|b
=: eyepy
=: eqepy
‘eyepur
|red
|b Jsed)jeaxeur
(49d
[red
=: |b
‘apoumou
4d]
=: |b
‘opoumeu
43dur
=:
‘pua :pus

usayy
ujBeq u2aq}
ulZeq uayy
u[Zeq

6-37
{
<eyepdn
eyepur
aqdur ‘eyepur

10932 jied3 |b ied


{ arppiyo =:
b =:
=:
‘eyepul Jo qed eyepur
‘eyepul eyepy
uorjztsod 4dr
ied = ‘p
‘Jeajuou
4dr=! aamy4 | lied3
|ied3 icd3
ied|b =
‘flaqed-b ied oS 00] jiu
=: 41asut dur red3 sey ujZaq|red3
1ydur'
==:
‘b
=: ==: ==: ~ uauy =
{ =: =: eyepur ‘t = %
‘[doq]s 20] yueredpues3
{@pou ‘(joo1u) eyepy
144dur -j0010 - =: jied3 gy
4dr
327° 19d] autuieyap
doy dj dr wey4 pues
asqyagja
|yoo1u =: 00] fied3
yoos |yoo1u
| |40010
40010 | |y0010
jocolu ==: =: Jred3 yy
vou sed3 ayy asja
doj
mau ujZeq 9 } yy } xy J}
0 ulZeq 90[
W3d}
G=
=
ayeaio
:pua doyuey4 pua
asia
}

6-38
ujZaq wey?
eyep'|y > Aoy
‘jig =: 4ydi°}yoo1u
‘Jeojuou =: 2ey°]joolN
‘(joo1m}mou
uj[Zeq u3sy3
Jeo, = 30419 J
{ {20419 Jeo] aj3urs e oyut WoI;JSUI WIoJsad }
ulZeq asa
@poumMol =! 4[Nsel UaYyy
=3H
ju
{ 50014 Aydula 09Ut UoJesul WIOJsed }

‘((apoumou)
‘kay ==: ejep’ |apoumou
‘Jea] =: Sez" |apoumou

Mau

6-39
, { apou jeajy sou ayeoso }
‘0 ==: doy
{joes ozterzrur }

ulseq
(o0j‘b‘1ed3)surpeqos
Ga EE GREE OUR IEICE IAGO OU REO I Ca aa sa}

yuouieye3s

pua
aay
AuuInp
asje
{
}
ydrjred3

pua
==:eyepur
uyZeq eqyepur
jied3
lied
=:

ueyy
-b
GOUT

SF?
£5
pua
eyep jiydy Jared =: ejepy fied
‘eyepy aed =: ejzepur' aed
‘@pOUMIU ==; 193d] |red
==:
Jred
‘adj
yydurjae d
=:
:4adurjred
ydr‘jied
worjsasut
ysouryja]
{
}
uey4y
ujZeq
eyep jued > Aay
{ Wap[tyo omy seq yuoied }
ujZeq useq4
=
Ndr
x
lied
[lu
-‘T
=:
do4
doy
==:
sed
‘[doq]s
(Aoy‘g)qyed pug

6-40
&uorjsesut
peiaued
wsojsed
}
{
ulZeq es]e
pua
pua
==:
y0olU
4[nSol
==:
‘Aoy
eyepul’]y oo1u
‘eyep' |y =: vezep y
|yoo1g
=:
‘apoumou
30010
19duI'|
=:
‘9
0010
Iydy']

eyepul’
uyZaq as]?

pua
e3epy

19dur' =: 4[Nnsol
yoolu
yoolu
‘eyep==:
qooiu
I4d]']40010

|4
‘Aoy

9==: |
‘apoumal

=!

y0010
|
=:
uayy90] =! Z
eqepurjied Aay> asyaJy
WaTq300] ==![
eyepy jued Aay> JI
puedxea
@ jeqal vary
{ waipyiyo
os yuored
sey¢ }
ujZsq asja
pus
9 ==: 4Nsel
:pue
pus
=:
Aoy
wayyy
|iojsooue
eyepur
=>
asyja
Jy
Aay
eyepul|ioysaoue
Aoy =: eqepy |ioyseoue uayy

6-41
eqepl |[iojsooue => Aoy
“[ = do} =: do}
‘[doq]s =: 10ysaoue
uj3aq
Oop 0 <> do} ajyaa
fapoumoau =: 413d4°| sed
ysourzyZzs
uoyzstasuy
}
{
ujZ3q es{a
pue
Aoy =: eyepur red
=:
jied
‘apoumou
43dur
=:
dr‘
fied
‘aydur
Jared
{ worjsasut aypprur }
u2q4
ujZeq
(eqepurjred > fax) gy este
KRKEAKARAEKAAAKRERRASARKREL
(\*
‘(g:eye

pur’
|4
ivjngey
x ‘gt,
{

«
* ,S:eveprla‘sr:,
Aq “4 ul &
jyudrjied
eywp

«
peep
Weald

‘(.0]‘apoumeu‘ied)sureqas «
‘f |y‘g:,
9019

==!
00] *
Aoy >

ERE

Jo 94} g-Z

« jeat
,9:887'13'¢:,
asja {9804
RK
AKER

{ =
acjayy

SyUa_QUOD

Uayy
00]
€=! apom
ERAARARE

Bey
ERR

|9‘¢:,
Jo lagdy|o
adXy «*,)ouIM
4hsed
4=: Jeoy «,)UfoIIIM
{
pue Jayutod auruayap
ujZaqyy
syuIIday}
KARR

= ujZeq
uay4
Bey
amnpsoold
ERE

[[nu |a w9y4
asa
pus }
RR EREKR

s0jf<>
yoaqo
‘uorysey
{

418
KE RE

sq]

q[Rsol
ylesuileq
==:
‘_pua Pp
'Pp }
ulZaq ueyy
uyZeq
}

‘pus {1y4dapou:})jyurd
aanpasoid

6-42
‘[ld ==: peoy
{ aary aztyerrur }
ujZaq
EEE
Gee B OBO GEST OIA
O EI TAC IEOEATER ATA ATR ATORE AEA

‘pua
pua
pua
pua
{(xydy (agdr
‘(agdur

01dutd
4);4);
}4),u1d
| |
‘(g:j« ,‘g:eyepur fayds|9

6-43
- ‘g:eqepy jagds'|a‘¢:, * ,)UpozliM asye
(02:»* [a « ,)UjaM u8y9
pa = 3yd1°3 Jy
| ydur |4‘g:eyepy Jagdui | ‘¢:, * ,
‘(g:e3epur
Jagdy}y‘g:eqepy lagdy ]9‘G:, * Joy
‘g:eqepur
ujZeq asja
pua
(a9da° }3)9 0tad
‘(agdur }9)9 utd
‘(19dy |9)y utd
leeway
‘g:eyep fagdr']4‘TT:, Jeo] « ,)UjazIM asta
(02: [a * Ulam Ueqy
jiu = 4di"}4 Jy
*
Jey
,jagdur|9‘TT:,
(g:egep
‘g:eyep fagdy'}a‘TT:, Jez] « 271A
} a8e3ueadoo]07 sseooid
[je eyep
{
styyou Joo OP
ulBaq
peas
ul pueururos)
mou‘ ‘(Aoy
J pUCUIUIOD
== Z10SUI
ueyy peoy=: (Aaymou‘peay)qsosuijeq
asta (Aoymou‘peag)azazapyeq
‘pua
} asi2AeI3 YSno143
991309 AJit9A $s00}901I09
{
UfOPLIM
UfO9IAA
oo}«,) AdALAGON
* VLIVd
* VLIVGT
+ VLVGW
1

+,
(#

UldT
Uldd

ULdN*

6-44
‘pua
(peoq)jutid
-VLVd
2]0p
06
Wosut OL
aos = CI
j4osul 02
q19sul
c
USUI2s TI
q1oSul af
P. 22° I
osu= 0¢
Aasul Of
esa! CZs
4aosul
= 1%
49sSul OOT
* * oot * Fer] *
ae
* * 06 * Fert *
Fe Re:

og * Fert °
$8.

* +
ee
* os * * Feejuou *
Oot Fee] 06
8

Se
* * v1 « Feel
* * It * fe *
« * 3 * | *

Se88 Se
* g * * Jeaquou +
Ir
«It
* jesquou «
bt
*
Feat
oot * FL
* GdALHCON *
ie
VIVON * WIVYGI * YWIVd

£
*
Uldy
ISIXd LON SHOd = ENTIVA ADI HLIM AGON
LSIXH LON SHOd (ONT = GTI LIM SGON
AGI VA
HLIM HOON
AGI VA

‘SLTASAY
LISixd LON SHOG_ Tt = GNI
GaYL ALG

1@-99919P —ay9]ap

6-45
L
OI 9}9/9P
- 9}2]9P
OG a}2[9p
0€ 92/9P

932]?
ol 9)}9]9p

«999[9P Sr
= 6G
-999]9P

Go
29]9P

Q19SuUl
OIL

v
TI JAoSUI
FI Jiosul
0S qiosul
Consider a 2-3 tree of height h. As a maximum, every node can have three
children (with the exception of the leaf nodes). This ternary tree has 3" leaf
nodes. As a minimum, every node can have two children (with the exception
of the leaf nodes). This binary tree has 2" leaf nodes. Therefore we can
conclude that a 2-3 tree of height h must have between 2" and 3? leaf nodes.

EXERCISES SECTION 6-2.3.3 PAGE 600

1) Function BAL_DELETE(HEAD,X). This is a recursive function with


deletes the node with information contents X from the weight balanced binary
tree given by HEAD. The function returns a pointer to the new weight
balanced tree. Procedure REBAL is invoked if rebalancing is found to be
necessary.

1. [Check for empty tree]


If HEAD = NULL
then Return(NULL)
2. {Find node to be deleted]
If DATA(HEAD) > X
then LPTR(HEAD) + BAL_DELETE(LPTR(HEAD),X)
Return(HEAD)
If DATA(HEAD) < X
then RPTR{HEAD) ~ BAL_DELETE(RPTR(H&AD}),X)
Return(HEAD)
3. [Delete node]
If LPTR(HEAD) +4 NULL and RPTR(HEAD) 34 NULL
then (replace node with inorder successor and rebalance)
FOLLOW + HEAD
SUCC + RPTR(HEAD)
Repeat while (LPTR(SUCC) 54 NULL)
FOLLOW + SUCC
SUCC + LPTR{SUCC)
If FOLLOW 34 HEAD
then LPTR(FOLLOW) + RPTR(SUCC)
else RPTR(HEAD) ~— RPTR(SUCC)
LPTR(SUCC) ~ LPTR(HEAD)
RPTR(SUCC) ~ RPTR(HEAD)
(check for rebalancing)
If RPTR(SUCC) +4 NULL
then If WEIGHT(RPTR(SUCC) > WEIGHT(LPTR(SUCC))
then If WEIGHT(RPTR(SUCC)) > WEIGHT(SUCC)

6-46
then Call REBAL(SUCC,RPTR(SUCC))
else If WEIGHT(LPTR(SUCC)) > WEIGHT(SUCC)
then Call REBAL(SUCC,LPTR(SUCC))
else If WEIGHT(LPTR(SUCC)) > WEIGHT(SUCC)
then Call REBAL(SUCC,LPTR(SUCC))
Return(SUCC)
else If LPTR(SUCC)
4 NULL
then Return(LPTR(SUCC))
else Return(RPTR(SUCC))

Procedure REBAL(PAR,CHILD). This procedure rebalances the tree


given by PAR, and leaves PAR to point to the newly balanced tree upon
returning to the point of call.

1. [Rebalance]
If LPTR(PAR) = CHILD
then LPTR(PAR) + RPTR(CHILD)
RPTR(CHILD) + PAR
else RPTR(PAR) «+ LPTR(CHILD)
LPTR(CHILD) + PAR
2. [Check for further rebalancing]
If LPTR(PAR) 4 NULL
then If RPTR(PAR) + NULL
then If WEIGHT(LPTR(PAR)) > WEIGHT(RPTR(PAR))
then If WEIGHT(LPTR(PAR) > WEIGHT(PAR)
then Call REBAL(PAR,LPTR(PAR))
else If WEIGHT(RPTR(PAR)) > WEIGHT(PAR)
then Call REBAL(PAR,RPTR(PAR))
else If WEIGHT(LPTR(PAR)) > WEIGHT(PAR)
then Call REBAL(PAR,LPTR(PAR))
else If RPTR(PAR) 44 NULL
thenIf WEIGHT(RPTR(PAR)) > WEIGHT(PAR))
then Call REBAL(PAR,RPTR(PAR))
3. [Assign PAR to point to new tree]
PAR «+ CHILD
Return

6-47
bw Procedure OPTIMIZE_REBAL. This procedure is essentially the same
as that given in the text, with the exception that optimization in rebalancing
is taken advantage of with regards to equal access nodes.

1. [Get the node and its parent from the stack]


CHILD + POP(S,TOP)
PAR <— POP(S,TOP)
2. [Do we need to rebalance?|
If WEIGHT(PAR) > WEIGHT(CHILD)
then Return
3. [Equal access nodes?|
If WEIGHT(PAR) = WEIGHT(CHILD)
then If LPTR(PAR) = CHILD
then If LPTR(CHILD) 4 NULL
then If RPTR(PAR) 4 NULL
then If WEIGHT(LPTR(CHILD))< WEIGHT
(RPTR(PAR))
then Return
else Return
else If RPTR(CHILD) 4 NULL
then If LPTR(PAR) +4 NULL
then If WEIGHT(RPTR(CHILD))< WEIGHT
(LPTR(PAR))
then Return
else Return
4. [Get grandparent from stack]
GPAR + POP(S,TOP)
5. [Exchange parent and child]
If LPTR(PAR) = CHILD
then LPTR(PAR) + RPTR(CHILD)
RPTR(CHILD) + PAR
else RPTR(PAR) + LPTR(CHILD)
LPTR(CHILD) + PAR
If LPTR(GPAR) = PAR
then LPTR(GPAR) + CHILD
else RPTR(GPAR) + CHILD
6. [Put grandparent and child on stack]
Call PUSH(S,TOP,GPAR)
Call PUSH(S,TOP, CHILD)
7. [Recursively bubble up the tree]
Call OPTIMIZE_REBAL
8. [Finished rebalancing]
Return

6-48
3) Function CHANGE(INFO,NEW_WEIGHT). This procedure changes a
particular node with information equal to INFO, in a weight balanced binary
tree. The weight of the node is changed to NEW_WEIGHT. Procedures
REBAL_UP and REBAL_DOWN are invoked should rebalancing be found to
be necessary. The function returns true if the operation is successful; false
otherwise.

1. [Initiate search for given node at head node] ©


CURRENT + HEAD
FOUND + false
TOP + 0
2. [Search until node is found]
Repeat thru step 4 while 7AFOUND and CURRENT ae NULL
3. [Save path]
Cal! PUSH(S,
TOP, CURRENT)
4. [Is there a match?|
If INFO = KEY(CURRENT)
then FOUND + true
else (continue search)
If INFO < KEY(CURRENT)
then CURRENT — LPTR(CURRENT)
else CURRENT + RPTR(CURRENT)
qo [Was node found?|
If -FOUND
then Return(false)
6. [Perform change]
WEIGHT(CURRENT) + NEW_WEIGHT
7. [Node moves downward?]
If RPTR(CURRENT) 4 NULL
then If LPTR(CURRENT) 4 NULL
then If WEIGHT(RPTR(CURRENT))>
WEIGHT
(LPTR(CURRENT))
then COMPARE + RPTR(CURRENT)
else COMPARE + LPTR(CURRENT)
else COMPARE + RPTR(CURRENT)
else COMPARE +«- LPTR(CURRENT)
If COMPARE = NULL
then If WEIGHT(COMPARE) > WEIGHT(CURRENT)
then Call REBAL_DOWN(CURRENT,COMPARE)
Return(true)
8. [Node moves upward?]
CHILD + POP(S,TOP)
If -EMPTY(S)
then PAR + POP(S,TOP)
If WEIGHT(PAR) < WEIGHT(CHILD)
then Cali REBAL_UP(CHILD,PAR)
6-49
9. [Finished]
Return(true)

Procedure REBAL_DOWN(PARENT,CHILD). This procedure


rebalances the weight balanced tree given by PARENT handling the case that
PARENT is moving downward in the tree. PARENT is changed to point to
the new tree.

1. [Rebalance]
If LPTR(PARENT) = CHILD
then LPTR(PARENT) « RPTR(CHILD)
RPTR(CHILD) + PARENT
else RPTR(PARENT) + LPTR(CHILD)
LPTR(CHILD) + PARENT
2. [Further rebalancing necessary?]
If LPTR(PARENT) 34 NULL
then If RPTR(PARENT) 3 NULL
then If WEIGHT(LPTR(PARENT))>WEIGHT(RPTR(PARENT))
then If WEIGHT(LPTR(PARENT))>WEIGHT(PARENT)
then Call REBAL_DOWN(PARENT,LPTR(PARENT))
else If WEIGHT(RPTR(PARENT)) > WEIGHT(PARENT)
then Call REBAL_DOWN(PARENT,RPTR(PARENT))
else If WEIGHT(LPTR(PARENT))> WEIGHT(P ARENT)
then Call REBAL(PARENT,LPTR(PARENT))
else If RPTR(PARENT) 4 NULL
then If WEIGHT(RPTR(PARENT)) > WEIGHT(PARENT)
then Call REBAL_DOWN(PARENT,RPTR(PARENT))
3. [Set PARENT to point to new tree]
PARENT + CHILD
Return

Procedure REBAL_UP(CHILD,PARENT). This procedure rebalances


the tree pointed to by PARENT handling the case that the CHILD is moving
upward in the tree.

1. [Initializations]
GPAR <— NULL
TOP_FLAG + false
2. [Get grandparent from stack]
If -EMPTY(S)
then GPAR + POP(S,TOP)
else TOP_FLAG + true

6-50
3. {Exchange parent and child]
If LPTR(PARENT) = CHILD
then LPTR(PARENT) ~ RPTR(CHILD)
RPTR(CHILD) + PARENT
else RPTR(PARENT) — LPTR(CHILD)
LPTR(CHILD) — PARENT
4, [Set grandparent link]
If -TOP_FLAG
then If LPTR(GPAR) = PAR
‘then LPTR(GPAR) «+ CHILD
else RPTR(GPAR) «+ CHILD
(further rebalancing necessary?)
If WEIGHT(GPAR) < WEIGHT(CHILD)
then Call(REBAL(CHILD,GPAR))
else HEAD + CHILD
5. [Finished]
Return

EXERCISES SECTION6-2.3.4 PAGE 605

1) Procedure TRIE_DELETE(NAME,ROW,TRIE,COL). Given the


parameters as described in the text this procedure performs a deletion of the
entry given by NAME from the trie structure. If the deletion fails, ROW and
COL are assigned a value of zero. It is assumed NAME contains only
alphabetic characters.

1. [Initializations]
COL + 1
LAST_COL + 0
LAST_ROW + 0
2. [Perform search and deletion]
Repeat for K = 1, 2, .... LENGTH(NAME)
ROW + INDEX('BABC...XYZ’,SUB(NAME,K,1))
Repeat while(TRIE[ROW,COL] S '-’)
If TRIE[ROW,COL] = NAME
then (perform deletion)
TRIE[ROW,COL] + '-!
(collapse columns if possible)
If LAST_COL 40
then COUNT + 0
Repeat for P=ind- 3 27

6-51
If TRIE[I,COL] = '-!
then COUNT + COUNT + 1
_ SAVE + TRIE[I,COL]
SAVE_ROW + I
If COUNT i= 1
then TRIE[SAVE_ROW,COL] + !-!
TRIE[LAST_ROW,LAST_COL] + SAVE
Return
If INDEX(' 0123456789! ,SUB(TRIE[ROW,COL],1,1)) = 0
then Write(/NAME NOT FOUND’)
COL — ROW <0
Return
else LAST_ROW + ROW
LAST_COL + COL
COL + TRIE|[ROW,COL]
3. [Missing name]
Write('NAME NOT FOUND’)
ROW «+ COL +606
Return :

Function LINK_TRIE_INSERT(NAME,TRIE). Given NAME, the key


of a new node to be inserted, and TRIE, a pointer to the first column of the
trie structure, this function inserts a new node into the structure, returning
true if no duplicate key is found; false otherwise. It is assumed that every
vector entry has a TAG field: true indicates the vector position is an ENTRY
(or information field) ; false indicates the vector position is a LINK (or pointer
field).

1. [Initializations]
COL «+ TRIE
2. [Perform insertion]
Repeat thru step 3 for K = 1, 2, ..., LENGTH(NAME)
ROW + INDEX('PABC...XYZ!,SUB(NAME,K,1))
3. [Entry or link?]
If TAG[ROW|(COL)
then (enter key into empty position)
If ENTRY[ROW|(COL) = !-!
then ENTRY[ROW](COL) + NAME
Return(true)
(check for duplicate entry)
If ENTRY{[ROW](COL) = NAME
then Write(/DUPLICATE ENTRY’)
Return(false)
(current position occupied)
NEW «+ COLUMN_NODE

6=52
Repeat for I= 1, 2, ..., 27
TAGI|I|(NEW) + true
ENTRY[I|(NEW) < !-!
SAVE — ENTRY[ROW](COL)
TAG[ROW](COL) + false
LINK[ROW](COL) ~NEW
ROW + INDEX (‘PABC...XYZ')
TAG[ROW](NEW) + true
ENTRY{ROW](NEW) — SAVE
COL + NEW
else (determine next column)
COL + LINK{[ROW](COL)

3) Procedure LINK_TRIE_SEARCH(NAME,ROW,COL, TRIE). Given


NAME, the key of an entry to be searched for, and TRIE, a pointer to the
first column of a trie structure, this procedure performs a search of the trie
structure. If the search fails, ROW is set to 0 and COL is set to NULL.

1. [Initializations]
COL + TRIE
2. [Perform the search]
Repeat for K = 1, 2, .... LENGTH(NAME)
ROW + INDEX('PABC...XYZ! ,SUB(NAME,K,1))
Repeat while (sTAG[ROW|(COL) AND LINK[ROW|(COL) 34
NULL) or (TAG[ROW](COL) and ENTRY|ROW](COL) 34 “')
If TAGIROW](COL)
then If ENTRY[ROW|(COL) = NAME
then Return
else Write(/UNEXPECTED NAME FOUND’)
ROW <— 0
COL «+ NULL
Return
else COL + LINK[ROW](COL)
3. [Missing name]
Write(’ NAME NOT FOUND‘)
ROW +0
COL + NULL
Return
4) Function LINK_TRIE_DELETE(NAME,TRIE). Given the parameters
as described in question 2 above, this function deletes the entry with key field
NAME from the given trie structure. The function returns true if the deletion
is successful; false otherwise.

1. , [Initializations]
COL + TRIE
LAST_COL + NULL
LAST_ROW + 0
2. [Perform search]
Repeat for K = 1, 2, ..., LENGTH(NAME)
ROW + INDEX('PABC...XYZ',SUB(NAME,K,1))
Repeat while (>TAG[ROW|(COL) and LINK[ROW](COL)
NULL) or (TAG|ROW](COL) and ENTRY|ROW|(COL) Die )
If TAG[ROW](COL)
then If ENTRY[ROW|(COL) = NAME
then ENTRY[ROW|(COL) + '-!
If LAST_COL + NULL
then COUNT + 0
Repeat for I = 1, 2, ..., 27
If TAG[I](COL)
then If ENTRY{I|(COL) 4 '~!
then COUNT + COUNT +1
SAVE_E «— ENTRY[I](COL)
SAVE_T + TAG|I](COL)
SAVE_ROW + I
else COUNT + COUNT + 1
SAVE_L + LINK{I](COL)
SAVE_T — TAG[I](COL)
SAVE_ROW + I
If COUNT = 1
then TAG[SAVE_ROW](COL) + true
ENTRY|[SAVE_ROW]{COL) + !-!
TAG|LAST_ROW](LAST_COL)
+ SAVE_T
If SAVE_T
then ENTRY[LAST_ROW]
(LAST_COL) — SAVE_E
else LINK{[LAST_ROW]
(LAST_COL) + SAVE_L
Return(true)
else Write(/NAME NOT FOUND’)
Return(false)
else LAST_ROW + ROW
LAST_COL + COL
COL + LINK[ROW](COL)
6-54
3. [Missing name]
Write(/ NAME NOT FOUND’)
Return(false)

5,6,7) program trie(input,output);

{ This program is designed to implement the insert and delete operations to


be performed on the trie described by figure 6-2.19. Note that the backward
quote (‘) is used to denote the blank in order to take advantage of the
convenience of the ascii collating sequence. }

type string = packed array[1..80] of char;


operations = (insert,delete);
types = (leaf,nonleaf);
ptr = ftrienode;
trienode = record
case tag:types of
leaf: (name:string);
nonleaf: (index:array[!‘’..'z'] of ptr)
end;

var t:ptr;
command:operations;
data:string;
i:char;
try :boolean;
tabover:integer;

GABE E EEE SEE AEE EOE EAE EOS S SEES ESA EEG GA EE EE EEE

#include ‘getline.i';
#include 'length.i';
GABE SSE ISAS EAS EEE ES TSE EI EEK EERE EEE EEE EEE EE EE }

function trieinsert(var t:ptr;key:string):boolean;

{ Given t, a pointer to a trie structure represented by a forest, this function


inserts a new node with name field key into the structure. The function
returns true if the insertion is successful, false otherwise. }

var p,q,save:ptr;
k:integer;
row:char;
fini,result:boolean;

6-55
begin
{ initializations }
q:= t;
k= 1:
fini := false;
{ perform insertion }
while (k <= length(key)) and (not fini) do
begin
{ determine next letter }
if (key[k] = ‘|') or (key(k] = ‘ ‘)
then row := '“
else row := key|k];
{ insert key into empty position }
if qf.tag = nonleaf
then if qf.index{row] = nil
then begin
new(p);
pf.tag := leaf;
pf.name := key;
qf.index[row] := p;
result := true;
fini := true
end
else { check for duplicate entry }
if qf.index[row]f.tag = leaf
then begin
if qf.index|row]f.name = key
then begin
writeln;
writeln(/ DUPLICATE KEY: ':15,
key :length(key));
result := false;
fini := true
end
else { current position occupied }
begin
save := qf.index[row];
new(p);
pf.tag := nonleaf;
for i:=' to ‘z' do
pt.index{i] := nil;
qt.index[row] := p;
if (savet.name[k+1] = ‘|') or
(savet.name[k+1] = ‘ ‘)
then row := '“
else row := savef.name[k+1];
pt-index[row] := save;
q:=p
end
end
else q := qf.index/row]
else q := qf.index{row];
k= k +1
end;
trieinsert := result
end;

Selanne tala aided |

function triedelete(var t:ptr;key:string):boolean;

{ This function deletes the entry with name key from the trie structure given
by t. The function returns true if the deletion is successful; false otherwise. }

var p,q,lastcol,save:ptr;
row, Saverow, lastrow,i:char;
k,count:integer;
fini,result:boolean;

begin
fini := false;
result := false;
q:=t
lastcol := nil;
lastrow := ! !;
k= 1;
{ perform search and deletion }
while (k <= length(key)) and (not fini) do
begin
{ determine next letter }
if (key[k] =‘ ') or (key|k] = ‘|')
then row := !"
else row := key|k];
p := qf.index[row];
while (p <> nil) and (not fini) do
begin
{ name found? }
if p{.tag = leaf
then if pf{.name «= key
then begin

6-57
qf .index[row] := nil;
if lastcol <> nil
then begin
count := 0;
for i:='" to 'z! do
if qt.index|i]<> nil
then begin
count := count + 1;
save := qf{.index{i];
saverow := i
end;
if count = 1
then begin
qf .index|saverow] := nil;
lastcolf .index[lastrow]
‘= save
end
end; ,
result := true;
fini := true
end
else begin
result := false;
fini := true
end
else begin
lastrow := row;
lastcol := q;
q:= Pp;
p := pt.index{row|
end
end;
k:=k+1
end;
{ missing name }
if not result
then begin
writeln;
writeln(/ NAME NOT FOUND = ':17,key:length(key))
end;
triedelete := result
end;

6-58
BABIES EASA aaa EIA Sa Aa AIA
EEO EBDESERIES
LEBER EEE EE

procedure print(t:ptr;tabover:integer);

var i:char;
tabstring:string;
j:integer;

begin
{ check for empty tree }
ift <> nil
then begin
{ print info }
writeln;
for j := 1 to SOD ONY a
tabstring|[j] :=
tabstring|tabover+1] :=
writeln(tabstring: Teeside "'NODE' TYPE = /:12;¢f. tag);
if tf.tag
= leaf
then writeln(tabstring:length(tabstring),/
NAME = ':7,
tt.name:length(tf.name))
else begin
for i:='" to'z' do
begin
if tt.index{i] <> nil
then begin
writeln(tabstring:length(tabstring),
‘INDEX = ':8,i:2);
print(tf.index{i],tabover + 20)
end
end
end
end
end;

(FEBS SEE SEERA ASAE AGA AE EGE EE EEE EEE EEE EE EEE}

begin
{ initializations }
tabover := 1;
new(t);
tt.tag := nonleaf;
for i:='“ to'z' do
tf.index[i] := nil;

6-59
{ process all data }
while not eof do
begin
read{command);
getline(data);
if command = insert
then try := trieinsert(t,data)
else try := triedelete(t,data)
end;
print(t,tabover)
end.

DATA:

delete fred
insert. barney
insert wilma
insert betty
insert bam-bam
insert pebbles
delete bedrock
insert ~ quarry
insert bedrock
insert fred
insert dino
insert flintstone
delete barney
insert fred
insert slate
insert hatrock
insert rubble
delete bedrock

RESULTS:

NAME NOT FOUND = fred


NAME NOT FOUND = bedrock
DUPLICATE KEY: fred

NODE TYPE = nonleaf


INDEX = b
NODE TYPE = nonleaf
INDEX = a
NODE TYPE = leaf
NAME, = bam-bam
INDEX = e
NODE TYPE = leaf
NAME = betty
INDEX = d
NODE TYPE = leaf
NAME = dino
INDEX = f
NODE TYPE = nonleaf
INDEX = 1
NODE TYPE = leaf
NAME = flintstone
INDEX = r
NODE TYPE = leaf
NAME = fred
INDEX = h
NODE TYPE = leaf
NAME = hatrock
INDEX = p
NODE TYPE = leaf
NAME = pebbles
INDEX = q
NODE TYPE = leaf
NAME = quarry
INDEX = r
NODE TYPE = leaf
NAME = rubble
INDEX = s
NODE TYPE = leaf
NAME = slate
INDEX = w
NODE TYPE = leaf
NAME == wilma

EXERCISES SECTION 6-2.4 PAGE 621

1) Assuming preconditioning consists of adding the EBCDIC representations of


the keys to obtain a key value x:

PAY:
h = x mod 101
= (215 + 193 + 232) mod 101
= 640 mod 101
ya
6-61
RATE:
h = x mod 101
= (217 + 193 + 227 + 197) mod 101
= 834 mod 101
== 26

AGE:
h = x mod 101
= (193 + 199 + 197) mod 101
= 589 mod 101
= 84

NUMBER:
h = x mod 101
= (213 + 228 + 212 + 194 + 197 + 217) mod 101
l 1261 mod 101
49

Assuming preconditioning consists of adding the ASCII representations of the


keys to obtain a key value x:

PAY:
h = x mod 101
= (80 + 65 + 89) mod 101
= 234 mod 101
== 32

RATE:
h = x mod 101
= (82 + 65 + 84 + 69) mod 101
= 300 mod 101
= 98

AGE:
h = x mod 101
= (65 + 71 + 69) mod 101
= 205 mod 101
= 3

NUMBER:
h = x mod 101
= (78 + 85 + 77 + 66 + 69 + 82) mod 101
= 457 mod 101
= $1

6-62
5
Ei
5
:

Table
of
Contents

Record PAY
Inserting
After RATE TAX PENSION STATUS
DEDUCT SEX SALARIED
DEPENDENTS

6-63
Procedure LP_DELETE(X). This procedure deletes the record with given
key X, from the hash table, using the linear probe technique.

1. [Calculate position]
d + HASH(X)
2. [Locate record]
fhe x
then i+d+1
FOUND + false
Repeat while i 54 d and 7FOUND
If kK, =X
then FOUND + true
else I+ I+1
3. [Was record found?]
If ~FOUND
then Write(/RECORD NOT FOUND IN TABLE! )
Return
4. [Delete record]
Kk; — Empty
mark + i
Repeat for} = mark + 1, mark + 2, ..., m— 1, m, 1, ..., mark - 1
If K; 4 Empty
then If HASH(K,) < i
then K,+ k;
ic j
kK, + Empty
5. [Finished]
Return

6-64
CHAPTER 7

FILE STRUCTURES
EXERCISES SECTION 7-1 PAGE 636

1) The number for records contained on a magnetic tape is given by:


tape length X blocking factor
aE ASOLOSds =
ree length + interblock gap

where block length = blocking factor X eter ee


encoding density

and record size refers to the number of bytes per record. The above formulae
can be combined and simplified into a concise form to solve for #records.
dees tape length
oes record size interblock gap
encoding density blocking factor

te — _ (3600ft)(12in
30 08t /ft)
Lip 80 byte 3/4in
1600 byte/in 1
= 54000 records

43200 in
records = —————________—_
ir ; 80 byte 3/4 in
1600 byte/in 5
= 216000 records

43200 in
records = —————_$_$_______—__
i 80 byte 1/2 in
3200 byte/in 25
= 960000 records

43200 in
records = ————_________
# 80 byte 1/2 in
800 byte/in s 1
= 72000 records
effective #bytes
to—
effective tape density =
length of tape
where effective #bytes = length of tape
— xX block size
block size
+ gap size
s. encoding density
therefore effective tape density = lock size
block size
+ gap size
s. encoding density

3a) 1 3/4Betts
in
effective tape density = se05Bpteic 80 byte

= 100 byte/in ;
1 3/4 in |
b) effective tape density = Genes 400 byte

= 400 byte/in
ay
1 3/8 in
effective tape density = Sas 25(80 bytes)

= 2000 byte/in

d) effective tape density =


| 1 1/2 in c
800 byte/in 80 bytes

= 133 byte/in

4) The time required to read a tape configuration is given by:

‘ amount of info amount of gap


+. ——_———
tine = ———_—__—_._
info reading rate gap pass rate

#records X record length a #blocks X interblock gap


rate info rate gap

i #records X record size #records X interblock gap


~ pate info X encoding density blocking factor X rate gap

d si se interblock
eee ere eee
= #records X ( eee
encoding density X rate info blocking factor X rate gap

where #records was evaluated in question 1.

a) Beet s 80 bytes
OU MAa 3/4 in
time = Z 54000 1600 bytes/in X 125a in/se
s bc it Pec
1 X oma nt:oncc
30 in/se

Tas
= 1372 seconds (22.9 minutes)

80 bytes 3/4 in |
ime. ==) 216000 | ee ee ene
me : |1600 bytes/in X 125 in/sec 5 X 30 in/sec
= 1166 seconds (19.4 minutes)

80 bytes 1/2 in
ti = 960000 | ——_——_——__—____ + — ;
aa 3200 bytes/in X 125 in/sec 25x 30 in/sec

= 832 seconds (13.9 minutes)

d)
te 72000 | 80 bytes 1/2 in |
800 bytes/in X 125in/sec 30 in/sec
= 1258 seconds (21.0 minutes)

A direct-access device is sometimes calied a random-access device because its


usual environment is the processing of records in a random order. Even if
records are processed in sequential order they are generally accessed
independently of the keys of the previous records.

#tracks = [ #sectors / (sectors/track)]


#sectors = [ #records / (records/sector)|
sector size
(records/sector) = Vrecaraize

__ 4 168 char/sector

_ 2 records
sector
(sectors/track) = 64 sectors/track

therefore,
sector track
#tracks = {10000 records x
2 records 64 sectors

= 79 tracks

The time to read the file is given by:

time = #sectors (S(i) + L{i) + T(i))

#sectors = 5000; S(i) = 58 ms; L(i) = 35 ms;

23
TG) sector size
transmission rate

transmission rate = 153.8 char/ms.

therefore,

time = 5000 | 58 ms + 35 168 char


C
s pees toa char/ms
= 470000 ms

= 470 seconds (7.8 minutes)

Recall that the entire sector of a UNIVAC FASTRAND II drum must be read
(independent of actual space used). The assumption that the sectors are in
random order implies the consideration of the seek and latency times at every
sector address. If, instead, the sectors were sequential, these delays need be
considered only once for each track.

block size: 20 records each 80 bytes long and 14 bytes system information
block size = 1614 bytes

blocks/track: 1614 bytes per block


20483 bytes per track
blocks /track = 12

#tracks: 20 records/block
500 blocks for the file
12 blocks/track
#tracks = 42

time to read the file is given by:

time = #blocks(L(i) + S{i) + T(i))


T(i) a sector size a 1614 bytes sen ATR ae
transmission rate 1200 bytes/ms

therefore

time = 500(8.6 ms + 0 + 1.3 ms)


= 4972 ms
= 5.0 seconds

7-4
8a) 64 char
i
nae aaa 3000 char/ms
ee
= 24.3213 ms
char
64 AGRE
e
i
time(D EC RM80) = 25 ms + 8.3 ms + Ta

= 35.3528 ms
ceo
time(COMM D9000) = 153ms + 8.3 ms + —
500 char/ms
= 161.428 ms

The time required to update a 64-char record equals the sum of the time
required to read the 64-char record and 2 X T(i), the time of one period of
revolution.

time
time-DEC RM80 = #sectors *
sector

24 pees a (HH EeSU) + T(i))


sector size
record size

ai +
: + 50)
z [Za iz,
record size |
a # records
sector size | transmission rate

record size

#records : [2.3BE cnet ae 64 chars |

[er
‘1212 chars/ms

== #records * 4.17 ms

time-IBM 2301 = #tracks * aE


track

time - time
=) S
track Sti) 2 Serene block

time - f
block = LU) + Thi)

f=5
we sector size
Li} —
transmission rate

block size = 20 * record size + 14 char


= 20 * 64 char + 14 char
= 1294 char
ti
Mes 8 Bins i 1294 char
sector 1200 char/ms
= 9.68 ms

__ #records
# block
blocks 50

#blocks
#tracks =
#blocks
tracks

#records/20
track size
block size

_ __#records/20 __
20483 char/track
1294 char/block
__ #records
316.6

time-IBM 2391 =
#records
316.6
:
[o+ #records 50* 9.68 ms

It is required to have time-IBM 2301 = time-DEC RM80.

Therefore:

fftecords | Sees = #records * 4.17 ms


316.6 | 20
#records * 9.68 ms
= 4.17 * 316.6
20

#records = 2727.73

Therefore each file should contain 2728 records in order that the total read
time be (approximately) equal.
7-6
EXERCISES SECTION 7-3 PAGE 649

1) A practical example of a multifaceted record item for which logical encoding


would be appropriate is the representation of the set of computer scicace
classes which a computer science professor is capable of teaching. A bit vaiue
is allocated for each class in the desired range.

bo— There are 11 mutually exclusive valucs in the range. Using the binary
encoding scheme an item length of [ log. 11] = 4 is required. Now all that is
left is to assign each value in the range a unique binary number of length four,
five more cities can be added to the list before the code length must be
increased.

3) Procedure I HUFFMAN(P,N,H). Given an array, P, of probabilities for


N item values, this procedure creates an array H, such that H{[I] is the
Huffrnan code of the item with probability Pl]. Temporary array T is
required to preserve array P, and array L is used as a link field within groups
which have been combined. We assume HIGH_VALUE takes on a value
greater than the sum of the probabilities in array P (generally HIGH_VALUE
= 1 should suffice). Function MIN is used to extract the index of the smallest
element in array T by a linear searck.

1. {Initializations]
Repeat for I = 1, 2, ..., N
Til] + P[]j
Hil] gen

L{]] — 0
2. [Set up combining loop]
Repeat thru step 8 for I = 1, 2, ..., N-1
3. [Get index of lowest probability]
LOW1 + LINK + MIN(T)
SAVE < T[LOW]]
T[LOW1] + HIGH_VALUE
4. [Concatenate a zero to the front of each partial code in this group]
Repeat while LINK = 0
H[LINK] ~ ‘0’ © H{LINK]
LINK + L{LINK]
5. [Get index of next lowest probability]
LOW2 + LINK + MIN(T)
6. [Combine probabilities]
T[LOW2] + TILOW2] + SAVE
7. [Concatenate a one to the front of each partial code in this group]
Repeat while LILINK] 4 0

iy
H[LINK] — ‘1! 0 HILINK]
LINK < L/LINK]
H[LINK] — '1' 0 H/LINK]
8. [Extend the group by adding a new link]
L[LINK] — LOW!
9. [Finished]
Return

Procedure R_HUFFMAN(P,N,H). Given an array P, of ordered


(descending) probabilities for N item values, this procedure creates an array H,
such that H[I] is the Huffman code of the item with probability P[I]. The
recursive function R_HUFF given below is invoked by this procedure. It is
assumed that array P is dispensable or has been saved prior to the call.

1. [Illegal array size?


|
IfN<0
then Write('ILLEGAL ARRAY SIZE’)
Return
2. [Initializations]
Repeat for I = 1, 2, ..., N
H[{I] Fee che

3. [Nontrivial case?|
IfN 1
then Call R_HUFF(P,N,H)
4. [Finished]
Return

Procedure R_HUFF(P,N,H). Given array P as previously described, this


procedure recursively evaluates the Huffman codes. The variable NEW refers
to the index of the position of the latest probability sum in the ordered P
array. Since NEW is local to RLHUFF its value must be saved at every
invocation of the procedure.

1. [Calculate the sum of the two lowest probabilities]


P[N] — P[N] + P[N - ]]
NEW+N-1
2. [Insert the new probability into the proper position of the P array]
Repeat while NEW + 1 and P[N] > P[NEW - 1]
P[NEW] + P[NEW - 1]
NEW + NEW - 1
P[NEW] + P[N]
3. [Recursive call]
lf NS 2
7-38
then Call R_HUFF(P,N - 1, H)
4. [Generate the Huffman code]
SAVE + H[N - ]]
H[N} — HINEW] © ‘0!
H[N - 1] + H[NEW] © ‘1’
If NEW = N- 2
then H[NEW] ~— SAVE
else Repeat for 1 = NEW + 1, NEW 4 2,..., N- 2
H[I]+ HI + }
5. [Finished]
Return

5) 1/4 ee BD (AR DOO 1D O Be ee e


1/6 = 8/48 8 8 8 8 8 DANS ne bie sl eae
1/8 = 6/48 6 6 6 6 7 8 0. 412 ej 2
1/8 = 6/48 6 6 6 6 6 7 8 9
1/12 = ° 4/48 Aiis As Richey hOu cee fogi ieGe ay
1/12 = 4/48 4 4 4 4 5 6
1/16 = - 3/48 3 3 3 4 4
1/24. = 2/48 2 2 3 3
1/48. =» 1/48 1 2 2
1/48 = 1/48 1 1
1/48 = 1/48 1
1/4 01 => H(1/4) a 10 = H(NEW YORK)
1/6 111 => H(1/6) == 111 = H(TOKYO)
1/8 110 => H(1/8) = 011 = H(CHICAGO)
1/8 010 => H(1/8) = 010 = H(LONDON)
1/12 000 => H(1/12)* === 000 = H(SAN FRANCISCO)
1/12 1011 => H(1/12) = 1101 = H(PARIS)
1/16 0011 => H(1/16) = 1100 = H(MONTREAL)
1/24 0100 => H(1/24) ...= 0010 = H(DETROIT)
1/48 01100 => H(1/48) = 00110 = H(DUSSELDORF)
1/48 111100 => H(i/48) = 001111 = H(MEXICO CITY)
1/48 011100 => H(1/48) = 001110 = H(ST. LOUIS)

The average or expected length is given by:

n
Vk xX P;
i=I1

where 1], and P; are the length and probability associ


ated with code i
respectively. Therefore, the expected length of the city item
is:

#9
(2 x 1/4) + (3 x 1/6) + (3 x 1/8) + (3 x 1/8) + (3 x 1/12) + (4 x 1/12)
+ (4 X 1/16) + (4 x 1/24) + (5x 1/48) + (6 X 1/48) + (6 X 1/48) = 3.10
bits

The amount of information transmitted from a source is given by:

nD

H= —S/P; logs (Pi)


i=]

Applying this formula to the probabilities (in question 5) of the item values in
question 2, we have:

= -1/4 X logo(1/4) - 1/6 x logo(1/6)— 1/8 x logo(1/8) - -


-1/48 X log,(1/48) = 3.07 bits

This is the minimum average amount of information needed to transmit the


coded value. We note that the expected average length using Huffman coding
is a small fraction larger (3.10 bits). However, using binary encoding, the
expected average length ( = actual length) is 4 bits. The efficiency of the
?iuffman encoding method is X 100% = 98.7%, while the efficiency of

the fixed length code is oe xX 100% = 76.5%.

~]© — name - fixed item


ao

address - fixed item
number of years with the company - fixed item
work classification - binary encoded
OD
SoA degrees held - repeating item
=— previous jobs held - repeating item

DECLARE 1 REC BASED (EMP),


2 NAME CHAR(30),
2 ADDRESS CHAR(30),
2 YEARS_WORKED FIXED BIN(6),
2 WORK_CLASS FIXED BIN(6),
2 DEGREES_HELD FIXED BIN(3),
2 D_PLUS_J FIXED BIN(4),
2 D_OR_J (I REFER (D_PLUS_J)) CHAR(20),
2. 1 FIXED INIT(10);
This structure allows the sum of degrees and jobs to be a maximum of ten.
The first DEGREES_'IELD elements of D_OR_J are degrees. The rest of the
D_PLUS_J elements refer to jobs. The categories are grouped because only
one REFER clause is allowed in a declaration.

ye10
8) WORD POSITION(S) WORD POSITION(S)
a 7,98 memory 43,68
accessible 65 not ol
all 52 of 10, 18,67
an 63 on 21
and 19,27 only Dae
applied 31 operations 20
are 45 point 3
assumed 38 portion 9
at 46 processed 56
by 57 reasons 49
computer 59 representations 17,26
data 22,28,34 reside 40,61
dealt 14 should 60
described 30 storage 25
discussion 12 structures 23
entities 35 text 6
form 66 that 54
has 13 the 5,11,16,24
immediately 64 there 44
in 4,41,62 this 2
information 53 to 1,33,39
is 55 two 48
least 47 were ot
main 42 which 36
major 8 why 50
manipulations 29 with 15

Qa) number of files - fixed item


b) days of week - binary encode
c) favorite recipes - textual item
d) single weather condition - binary encoded
e) multiple weather conditions - logical encoded
—_— former residences - repeating item

EXERCISES SECTION 7-4 PAGE 663

la) If search requests are not batched, there is no advantage in ordering the file
assuming almost all requests access existent records. The average search time
is N/2 in either case where N is the number of records in the sequential file.
However (note difference from question 2), if a large proportion of attempted
retrievals involve illegitimate keys then the search time will be N if the file is

Prt)
not ordered, and N/2 if the file is ordered. The frequency of unsuccessful
searches must be weighed against the overhead in ordering the file.
If the search requests are batched then there is an advantage in ordering the
file provided that the search requests are ordered (by the same key) and the
number of requests is high (enough to overcome the overhead in ordering the
file). The saving in total-search time exists because it is not necessary to scan
the file from the beginning each time a request is made. Instead searching
continues from where the previous search left off. The importance of ordering
the search requests should be evident.

2a,b) Answered above in question 1.


A better way of ordering the file (as opposed to class number) is to order it by
the probabilities of being accessed. The classes which have 3 high probability
of search requests should, appropriately, be near the beginning of the file..

Stream I/O
- information is stored externally on a file in character form
- I/O is at item level
- character conversion takes place in buffer
- buffer size is independent of stored information

Consecutive I/O
- information is stored in internal form
- I/O at record level
- no data conversion required
- buffer contains integral number of logical records

Stream I/O is used primarily for individual data items in single-run


applications. Consecutive I/O is used for structured data (records) which have
a relatively permanent nature.

EXERCISES SECTION 7-7 PAGE 717

1) Algorithm IS_SEQ SCOPE Given an index sequential file, called


MASTER, on the CDC Scope System, this algorithm accesses the records
sequentially. It is assumed that the master index block is already in main
memory, and buffer space has been allocated for one subordinate index block
and one data block. MB_REC, SIB_REC, and DB_REC are the names of the
records in the master index block, subordinate index block buffer, and data
block respectively. The only items in an index entry are a KEY and
ADDRESS field.

Tae,
1. [Initializations]
Open MASTER for input
2. [Process all subordinate index blocks listed in master index block]
X «+ number of subordinate index blocks in master index block
Repeat thru step 5 for I = 1, 2, ..., X
3. [Process all data blocks listed in subordinate index block]
A — ADDRESS of MB_REC|]]
Move block of address A to subordinate block buffer
Y «+ number of data blocks in subordinate block buffer
Repeat thru step 5 for J = 1, 2, ..., Y
4. [Process all records in data block]
A + ADDRESS of SIB_REC{J]
Move block of address A to data block buffer
Z + number of records in data block buffer
Repeat step 5 forK = 1, 2, ..., Z
5. [Process individual record]
A + ADDRESS of DB_REC|K]
Process transactions posted against DB_REC(A)
6. [Finished]
Exit

Algorithm IS_DIR_SCOPE. Given an _ index sequential file, called


MASTER, on the CDC Scope System, this algorithm processes
the transaction
TRAN_REC against the MASTER file. Access will be direct
to the record
with key given by KEY of TRAN_REC. The type of transaction posted
against the record is also given by TRANS of TRAN_REC.
The assumptions
made in Algorithm IS_SEQ_ SCOPE still apply. SIB_LADDR and DB ADDR
are MASTER file addresses of a subordinate index block
and data block
respectively. DBILADDR and MTR_ADDR are the main
memery address of
records in the data block buffer. MB_LOC, SIB_LOC,
and DBI_LOC refer to
the location of index entries in their respective blocks.
Subalgorithms
BIN_BLOCK_SEARCH, SCOPE_INSERT, SCOPE_DELETE, and
SCOPE_ALTER, invoked by this algorithm are given below.

1. [Initializations|
Open MASTER file for update
Read TRAN_REC
2. [Exarnine master index block]
MB_LOC — BIN_BLOCK_SEARCH(KEY of TRAN
SIB_ADDR «— ADDR ofMB_REC(MB_LOC)
_REC, master block )
Move block at SI_LADDR in MASTER file to subordinate index block
buifer in main memory
3. [Examine subordinate index block]
SIB_LOC + BIN_BLOCK_SEARCH(KEY cf TRAN_REC, subordinate
index block buffer) ©,
Jag
DB_ADDR ~— ADDR of SIB_REC(SIB_LOC)
Move block at DB_ADDR to data block buffer in main memory
4. [Examine data block index]
DBI_LADDR + address of index record in data block buffer
DBI_LLOC + BIN_BLOCK_SEARCH{KEY of TRAN_REC, data block
index of data block buffer)
MTR_ADDR + ADDR of DBI_LREC(DBI_LOC)
5. [Matching keys?]
If KEY of record MTR_ADDR ee KEY of TRAN_REC-
then If TRANS = 'ADD!
then Call SCOPE_INSERT
else Write(/TRANS KEY DOES NOT MATCH A FILE KEY’ )
Exit
6. [Deletion or update?]
If TRANS = 'DELETE!
then Call SCOPE_DELETE
else If TRANS = ‘ALTER!
then Call SCOPE_ALTER
else Write(/‘INVALID TRANSACTION’)
Exit

Function BIN_BLOCK_SEARCH(SEARCH_KEY,block of records).


Given SEARCH_KEY, and a block of records in main memory, this function
returns the location of the record in the block with a key field equal to
SEARCH_KEY. It is assumed that the block contains control information
about the record size and the number of records.

1. [Initializations]
E + number of records in block
B+-1
BASE_ADDRESS + address of first record in block
REC_SIZE + size of record in block
Repeat thru step 3 while B < E
2. [Obtain address of middle record in unsearched portion]
I+ [{B + E)J
ADDR «+ BASE_ADDRESS + (I - 1) * REC_SIZE
3. [Compare]
If SEARCH_KEY < KEY of record at ADDR
then. 1 — [1
else If SEARCH_KEY > KEY of record at ADDR
then” Bae l
else Return(ADDR)
4. [Return address where record should be]
If KEY of record at ADDR < SEARCH_KEY.
then Return(ADDR + REC_SIZE)
Y
else Return(ADDR)
seal
Procedure SCOPE_INSERT. This procedure creates a new record, and
inserts it at MTR_ADDR in the data block buffer. Since records may have to
be moved, the data block index record should reflect the change. A block
splitting algorithm may be called if the data j:iock buffer is full; it is
responsible for changing index entries in the subordinate index block, and the
master index block if a subordinate index block overflows. Details of the
splitting algorithm will not be given but we can assume that after the call the
proper data block will be in the data block buffer. The local variables are
REC_ADDR, REC_PREV, IND_ADDR, and IND_PREYV, all of which contain
addresses of index entries in main memory.

1. [Check for overflow]


If number of entries in data block = maximum number of entries
then Perform splitting algorithm
2. [Get address of next index entry and data block record]
REC_ADDR + address of first free space in pad of data block
IND_ADDR + address of first free space in data block index
Repeat step 3 while REC_ADDR + MTR_ADDR
3. [Move index entries and records]
REC_PREV + address of record before DB_REC(REC_ADDR)
IND_PREV + address of record before DBILREC(IND_ADDR)
DB_REC(REC_ADDR) «+ DB_REC(REC_PREV)
DBI_LREC(IND_ADDR) «— DBI_REC(IND_PREV)
REC_ADDR + REC_PREV
IND_ADDR + IND_PREV
4. [Insert new index entry and record]
KEY of DB_LREC(MTR_ADDR) + KEY of DBJI_REC(IND_ADDR) +
KEY of TRAN_REC
INFO of DB_LREC(MTR_ADDR) + INFO of TRAN_REC
ADDR of DBILREC(IND_ADDR) + MTR_ADDR
5. [Move data block buffer back to MASTER file]
Write block at DB_ADDR from data block buffer
Return

Procedure SCOPE_DELETE. Given the address, MTR_ADDR, of a


record to be deleted from the data block buffer, this procedure garbage collects
in the data block buffer and rewrites it in the MASTER file at location
DB_ADDR. This process consists of replacing the deleted record by active
records of higher key value, and maintaining the data block index record. If ~
the single record of the data block is deleted, then the data block is released
and the subordinate index entry of that data block is deleted. Subordinate
index blocks are never released. Temporary variables used are: REC_ADDR
and REC_SUC, record addresses in the data block buffer; IND_ADDR, and
IND_SUC, data block buffer index entries. The roles of the other variables are
given in algorithm IS_DIR_SCOPE.

Pats
1. [Initializations]
REC_ADDR «+ MTR_ADDR
IND_ADDR «+ DBI_LADDR
2. [Move data block buffer records and corresponding index entries|
Repeat while REC_ADDR sa address of last record in data block buffer
REC_SUB < address of record following DB_REC(REC_ADDR)
IND_SUC + address of index entry following DIB_LREC(IND_ADDR)
DB_REC(REC_ADDR) «- DB_REC(REC_SUC)
DBI(IND_ADDR) + DBILREC(IND_SUC)
REC_ADDR «+ REC_SUC
IND_ADDR «— IND_SUC
Delete DB_LREC(REC_ADDR) from data block buffer
3. [Only record of data block buffer released?|
If address of first record in data block buffer = REC_ADDR
then release block at DB_ADDR in MASTER file
REC_ADDR + SIB_LOC
Repeat while REC_ADDR Sa address of last record in SI buffer
REC_SUC + address of record following SIB_REC(REC_ADDR)
SIB_REC(REC_ADDR) + SIB_REC(REC_SUC)
REC_ADDR «+ REC_SUC
Delete SIB_LREC(REC_ADDR) from subordinate index block buffer
else (move data block buffer back to MASTER file)
Write block at DB_ADDR from data block buffer
If MTR_ADDR = address of first record in data block buffer
thenKEY of SIB_REC(SIB_LOC) + KEY of DB_REC(
MTR_ADDR)
else Return
4. [Move subordinate index block buffer to MASTER file]
Write block at SIB_ADDR from subordinate index block buffer
Return

Procedure SCOPE_ALTER. Given the transaction record TRAN_REC,


this procedure alters the INFO field of the record at MTR_ADDR in the data
block buffer.

1. [Alter the info field]


INFO of DB_LREC(MTR_ADDR) + INFO of TRAN_REC
2. [Rewrite data block]
Write block at DB_ADDR from cata block buffer
Return
3) Algorithm IS_PRIME_INSERT. Given a transaction record, this
algorithm inserts a record with the same KEY and INFO field on the prime
track indexed by TRK_INDEX[J]. ADDR is initially pointing at the first
record on the prime track. DELETE_FLAG is introduced as the first bit in
the INFO field (a ‘1’ implies a deleted or dummy record). The remaining
variables are as discussed in Algorithm IS_SEQUENTIAL.

1. [Find proper record location in track]


Repeat while KEY of PRIME_REC(ADDR) < KEY of TRAN_REC
_ ADDR + beginning of next prime-track record
2. [Dummy or deleted record at proper record location?|
If DELETE_FLAG of PRIME_REC(ADDR) = 1 and KEY of
PRIME_REC(ADDR) = KEY of TRAN_REC
then DELETE_FLAG of PRIME_REC(ADDR) + 0
INFO of PRIME_REC(ADDR) + INFO of TRAN_REC
Exit
3. [Overflow?]
TEMP + address of last prime-track record on same track
If DELETE_FLAG of PRIME_REC(ADDR) = 1
then DELETE_FLAG of PRIME_REC(ADDR) < 0
else NEW_LOC «+ OVFLOW_AVAIL
update OVFLOW_AVAIL pointer
Write KEY and INFO of PRIME_REC(TEMP) on MASTER file
at location NEWLOC
(Previous overflow?)
If OVFLOW_ADDR of TRK_INDEX|J] me NORMAL_ADDR
of TRK_INDEX{J}.
then LINK of OVFLOW_REC(NEWLOC) + OVFLOW_ADDR
of TRK_INDEX{J]
else LINK of OVFLOW_REC(NEWLOC) + J
OVFLOW_KEY of TRK_INDEX[J] — KEY
of PRIME_REC(TEMP)
(Reset track index and shift records to the left)
OVFLOW_ADDR of TRK_INDEX[J] + NEWLOC
If TEMP == ADDR
then NORMAL_KEY of TRK_INDEX{J] — KEY of TRAN_REC
else PREV_ADDR +record address before prime-track
record TEMP
NORMAL_KEY of TRK_INDEX[J] — KEY
of PRIME_REC(PREV_ADDR)
Repeat while TEMP 4 ADDR
Write KEY and INFO of PRIMTE_REC(PREV_ADDR)
at location TEMP
TEMP + PREV_ADDR
PREV_ADDR + address of the record before prime-
track record TEMP

Tai]
4. [Finished]
Write KEY and INFO of TRAN_REC on MASTER file at location ADDR
Exit

4) If any processing (insertion, deletion, update) is applied to the file, then it is


advantageous to have the file organized as indexed sequential rather than
sequential. This is because a sequential file must be completely rewritten
_ every time a transaction is applied to it, and the indexed sequential file has
overflow areas for dynamic file change. Eventually, however, even the IS file
should be rewritten (when overflow areas have been filled).

5) FILES: PROCEDURE OPTIONS(MAIN);

/* THIS PROGRAM IS DESIGNED TO CREATE A SALEMN AND


CUSTOM FILE FROM THE FILES SALES AND CUST. THESE TWO
FILES ARE THEN UPDATED USING THE INFORMATION FROM THE
TRANS FILE. THE VALID TRANSACTIONS ARE ADDING A
CUSTOMER, DELETING THE CUSTOMER, ADDING A. SALESMAN,
DELETING A SALESMAN, AND A PURCHASE TRANSACTION. AFTER
THIS IS DONE, THE TWO NEW FILES ARE PRINTED OUT. */

DECLARE (CUST, /* ORIGINAL CUSTOMER INFO FILE +/


SALES, /* ORIGINAL SALESMEN INFO FILE +/
TRANS) /* TRANSACTION INFORMATION FILE * [es
FILE STREAM,

SALEMN /* NEW SALESMAN FILE */ FILE RECORD KEYED ENV


(INDEXED F(950,95)),
CUSTOM /* NEW CUSTOMER FILE */ FILE RECORD KEYED ENV
(INDEXED F(810,81));
DECLARE 1 CREC, /* CUSTOMER RECORD +/
2 FLAG BIT(8), /* DELETE FLAG +/
2 INFO,
3 STATIC,
4 ACCT# CHAR(5),
4 NAME CHAR(21),
4 ADDRESS CHAR(50),
3 AMTT FIXED(7,2); /* TOTAL PURCHASES */
DECLARE 1 SPEC, /# SALESMAN RECORD +*/
2 FLAG BIT(8), /* DELETE FLAG +*/
2 INFO,
3 STATIC,
4 SALE# CHAR(2),
4 NAME CHAR(21),
4 ADDRESS CHAR(50),
3 AMT,
4 A FIXED(7,2),
4 B FIXED(7,2),
4 C FIXED(7,2),
4D FIXED(7,2),
3 AMTT FIXED(7,2); /* TOTAL SALES */

DECLARE 1 TREC,
2 TYPE CHAR(4),
2 AMT,
3A FIXED(6,2),
3B FIXED(6,2),
3C FIXED(6,2),
3D FIXED(6,2),
2 AMTT FIXED(7,2);
/* FIRST, THE SALEMN FILE IS INITIALIZED FROM THE SALES FILE */
OPEN FILE(SALES) INPUT,
FILE(SALEMN) SEQUENTIAL OUTPUT;
SREC.FLAG = (8) '0'B;
SREC.AMT = 0;
SREC.AMTT = C;
/* READ IN INFORMATION FOR EACH SALESMAN IN THE FILE +/
ON ENDFILE(SALES) GO TO CUS;
DO WHILE('1'B);
GET FILE(SALES) EDIT(SREC.INFO.STATIC) (A(2),X(6),A(21),A(50));
WRITE FILE(SALEMN) FROM(SREC) KEYFROM(SALE¥#);
END;
CUS: CLOSE FILE(SALES), FILE(SALEMN);

/* INITIALIZE THE CUSTOM FILE FROM THE CUST FILE */


OPEN FILE(CUST) INPUT,
FILE(CUSTOM) SEQUENTIAL OUTPUT;
CREC.FLAG = (8) /0'B;
CREC.AMTT = 0;
/* READ IN INFORMATION FOR EACH CUSTOMER IN THE FILE +/
ON ENDFILE(CUST) GO TO TRAN;
DO WHILE ('1'B);
GET FILE(CUST) EDIT(CREC.INFO.STATIC) (A(5),X(4),A(21),A(50));
WRITE FILE(CUSTOM) FROM(CREC) KEYFROM(ACCT#);
1A
END;
TRAN: CLOSE FILE(CUST), FILE(CUSTOM);

/* NOW PROCESS THE UPDATES FROM THE TRANS FILE */


OPEN FILE(TRANS) INPUT, _
FILE(CUSTOM) DIRECT UPDATE,
FILE(SALEMN) DIRECT UPDATE;
/* CHECK FOR CUSTOM FILE KEY ERROR + /
ON KEY(CUSTOM) BEGIN;
IF (ONCODE = 51)
THEN PUT FILE(SYSPRINT) SKIP EDIT('CUSTOMER /,
‘ACCOUNT NUMBER NOT FOUND: ' ACCT#) (A,A,A);
IF (ONCODE = 52)
THEN PUT FILE(SYSPRINT) SKIP EDIT(‘DUPLICATE ',
‘CUSTOMER ACCOUNT NUMBER: ' ACCT#) (A,A,A);
IF (ONCODE = 57)
THEN PUT FILE(SYSPRINT) SKIP EDIT(/NO ROOM TO /,
‘ADD CUSTOMER ACCOUNT.') (A,A);
GO TO NEXT;
END;

/* CHECK FOR SALEMN FILE KEY ERROR */


ON KEY(SALEMN) BEGIN;
IF (ONCODE = 51)
THEN PUT FILE(SYSPRINT) SKIP EDIT('SALESMAN /,
‘NUMBER NOT FOUND: ',SALE#) (A,A,A);
IF (ONCODE = 52)
THEN PUT FILE(SYSPRINT) SKIP EDIT(/DUPLICATE ',
‘SALESMAN NUMBER: ',SALE#) (A,A,A);
IF (ONCODE = 57)
THEN PUT FILE(SYSPRINT) SKIP EDIT('NO ROOM TO /,
‘ADD SALESMAN RECORD.) (A,A);
GO TO NEXT;
END;

/* GET TRANSACTIONS AND PROCESS THEM +*/


ON ENDFILE(TRANS) GO TO OTPT;
NEXT: DO WHILE('1'B);
GET FILE(TRANS) EDIT(TYPE) (COL(1),A(4))
IF (TYPE = 'ADDS’) THEN DO; /* ADD SALEMN RECORD +#/
GET FILE(TRANS) EDIT(SREC.INFO.STATIC) (A(3),X(2),A(21),A(50)):
SREC.FLAG = (8) /0'B;
SREC.AMT = 0;
SREC.AMTT = 0;
7720
WRITE FILE(SALEMN) FROM(SREC) KEYFROM(SALE#);
END;
ELSE
IF (TYPE = ‘ADDC’) THEN DO; /* ADD CUST RECORD + /
GET FILE(TRANS) EDIT(CREC.INFO.STATIC) (A(5),A(21),A(50));
CREC.FLAG = (8) '0‘B; .
CREC.AMTT = 0;
WRITE FILE(CUSTOM) FROM(CREC) KEYFROM(ACCT#);
END;
ELSE
IF (TYPE = 'DELS') THEN DO; /* DELETE A SALESMAN'S RECORD */
GET FILE(TRANS) EDIT(SALE#) (A(3));
DELETE FILE(SALEMN) KEY(SALE¥#);
END;
ELSE
IF (TYPE = 'DELC’) THEN DO; /* DELETE A CUSTOMER RECORD + /
GET FILE(TRANS) EDIT(ACCT#) (A(5));
DELETE FILE(CUSTOM) KEY(ACCT#);
END;
ELSE
IF (TYPE = 'PURC’) THEN DO; /* A PURCHASE TRANSACTION */
GET FILE(TRANS) EDIT(SALE#,ACCT#,TREC.AMT)
(A(3),X(2),(5),X(5),4(F(6,2),X(4)))
READ FILE(SALEMN) INTO(SREC) KEY(SALE#);
READ FILE(CUSTOM) INTO(CREC) KEY(ACCT#);
TREC.AMTT = TREC.A + TREC.B + TREC.C + TREC.D;
CREC.AMTT = CREC.AMTT + TREC.AMTT;
SREC.AMTT = SREC.AMTT + TREC.AMTT;
SREC.AMT = SREC.AMT + TREC.AMT;
REWRITE FILE(CUSTOM) FROM(CREC) KEY(ACCT#¥);
REWRITE FILE(SALEMN) FROM(SREC) KEY(SALE#);
END;
ELSE /* ILLEGAL TRANSACTION TYPE */
PUT FILE(SYSPRINT) SKIP EDIT(‘ILLEGAL TRANSACTION: !,
TYPE) (A,A);

OTPT: CLOSE FILE(TRANS), FILE(SALEMN), FILE(CUSTOM);


/* PRINT HEADINGS FOR SALEMN FILE #/
PUT FILE(SYSPRINT) SKIP EDIT(/SALESMAN REPORT’) (X(57),A);
PUT FILE(SYSPRINT) SKIP(4) EDIT(/ NUMBER!,’NAME!,/ADDRESS’,
'A SALES!,!B SALES!,'C SALES!,'D SALES!’ TOTAL SALES’)
(A(X(4),A,X(22),A,X(25),A,4(X(3),A));

S21
/* PRINT SALEMN FILE #/
OPEN FILE(SALEMN) SEQUENTIAL INPUT:
ON ENDFILE(SALEMN) GO TO OTPT1:
DO WHILE('1’B); |
READ FILE(SALEMN) INTO(SREC) KEYTO(SALE#);
PUT FILE(SYSPRINT) SKIP(2) EDIT(SREC.INFO)
(X(2),A,X(3),A(15),X(3),A(38),5(X(3),F(8,2)));
AND’,
OTPT1: CLOSE FILE(SALEMN);

/* PRINT HEADINGS FOR CUSTOM FILE */


PUT FILE(SYSPRINT) EDIT('CUSTOMER REPORT’) (PAGE,X(40),A):
PUT FILE(SYSPRINT) SKIP(4) EDIT(/ NUMBER’ ,/NAME! /ADDRESS’,
‘AMOUNT’) (A,X(7),A,X(33),A,X(28),A);
/* PRINT CUSTOM FILE */
OPEN FILE(CUSTOM) SEQUENTIAL INPUT;
ON ENDFILE(CUSTOM) STOP;
DO WHILE('1'B);
READ FILE(CUSTOM) INTO(CREC) KEYTO(ACCT#);
PUT FILE(SYSPRINT) SKIP(2) EDIT(CREC.INFO)
(A(5),X(3),A(20),X(3),-A(50),X(3),F(8,2));
JD:
)

END FILES:
//GO.CUST DD DSNAME=A900352.SORENSON FYL1,DISP=OLD
//GO.CUSTOM DD DSNAME=BILLING(PRIME),DISP==(NEW,DELETE),
// UNIT=SYSDA,DCB=(DSORG=IS,RKP=1,KEYLEN=5,OPTCD=L,
// CYLOFL=2),SPACE=(CYL,1)
//GO.SALES DD DSNAME=A900352.SORENSON.FYL2,DISP=OLD
//GO.SALEMN DD DSNAME=SMAN(PRIME),DISP=(NEW,DELETE),
// UNIT=SYSDA,DCB=(DSORG=IS,RKP=1,KEYLEN=3,0PTCD=L,
// CYLOFL=2),SPACE=(CYL,1)
//GO.TRANS DD DSNAME=A900352.SORENSON.FYL3,DISP=OLD

7222
EXERCISES SECTION 7-9 PAGE 750

1) The bucket capacity represents the number of records that can be inserted
into an auxiliary memory address region before an overflow takes place. If the
bucket capacity is very small (e.g., 1), then overflows are very frequent. The
time to access a record from an overflow area is excessive. On the other hand,
if the bucket capacity is large, a large amount of main memory buffer space iS
necessary to hold the contents of the bucket. In addition, the more records
there are in a bucket, the longer it takes to locate the particular record
required.

2) Chained overflow with separate lists is a faster collision resolution technique,


especially if each overflow area can be located in the same cylinder as its
corresponding prime area. The ALOS for chained overflow is less than that of
open-addressing. A disadvantage with the chaining technique is that pointers
must be maintained in both the prime area and overflow area and therefore
some additional memory is required.
Open-addressing works reasonably well with large bucket capacities. If
the load factor becomes high, then clustering can occur, and lengthy searches
are required to locate the desired record.
If there is a table or file overflow in the open addressing scheme, then
the entire table or file must be reorganized. This is not true for chained
overflow.
If deletions are involved, they can be easily implemented in both
techniques but the number of probes for the retrieval of a record in open-
addressing may not be reduced.

Procedure C_CL_INSERT(R,X). Given a record R, with key X, this


procedure inserts R into a direct file with record locations Ly, Lys, ..., Ly. Ifa
record is resident at location L;, then its key is dencted K,. If no record is
present, then the key field is represented by a negative number. The overflow
technique is chaining with coalescing lists therefore each record has a link filed
LINK. A bucket size of 1 is used and allows the recapture of the record
location if a deletion is performed. Temporary variables i and SAVE contain
record addresses; the hashing function H is used to calculate an address given
a key.

1. [Apply hashing function]


SAVE + i — H(X)
2. [Empty record location?|
If Kk; < 0
then L;+ R
LINK(i) + NULL
Return

deze
3. [Scan coalescing list for empty record location]
Repeat forever
imi+l
Ifi>N
then i+ 1
Ifi = SAVE
then Write (‘FILE OVERFLOW’)
Return
else IfK, <0
then L;«+R
LINK(i) - LINK(SAVE)
LINK(SAVE) —]
Return

Procedure C_CL_DELETE(X). Given the key X of a record in a direct


file, this procedure deletes the record from the file of n locations Ly, Lo, ..., Ly.
Details of the variables and their roles are the same as in Procedure
C_CL_INSERT. The overflow technique used for the file is chaining with
coalescing lists. The record location of the deleted record is recaptured except
when it is the head of a coalescing list; then the record location of the second
record is recaptured.

1. [Apply hashing function]


SAVE <— H(X)
j + LINK(SAVE)
2. [Delete record at head of list?]

then Ifi = NULL


then Ksave « —]

LINK(SAVE) + NULL
else Ksave << L;
kK; + -l
LINK(i) + NULL
Return
3. [Scan coalescing list until record or end of list found]
Repeat while i 54 NULL
i + LINK(SAVE)
If kK; = X
then K,+« -1
LINK{SAVE) + LINK(i)
LINK(i) — NULL
Return
SAVE + 1
4. [Record to be deleted not found]
Write(/RECORD NOT FOUND’)
Return
7-24
Procedure C_CL_RETRIEVE(X,R). Given a key, X, this procedure
retrieves the record identified by that key from the direct file with record
locations Lj, Log, ..., Lp.

1. [Apply hashing function]


i + H(X)
2. [Scan coalescing list]
Repeat while i 54 NULL
If Ki = X
then R<L;
Return
i — LINK(i)
3. [Record not found]
Write(/RECORD NOT FOUND’)
Return

Procedure DIRECT_SER(B,n,m). Given a direct file with primary


buckets B,, Bo, ....B,, 12 which a particular bucket B,; contains m record
locations bi. bi, aay bi this procedure processes the file serially. If a record is
resident at locationbj,, then its key is denoted ky. If no record is present, then
the key field is represented with a negative number. Overflow entries are in a
linked linear list with the head pointed at by PTR;. The overflow record is
OR; its link field is LINK.

1. [Examine all buckets]


Repeat thru step 3 for i = 1,:2, ..., n
2. [Examine record locations]
Repeat for } = 1, 2, ..., m
IfKj, >0
then Process transaction against record by
3. [Examine overflow list]
P — PTR,
Repeat while P a NULL
Process transactions against OR(P)
P + LINK(P)
4. [Finished]
Return

5) A record-addressable device provides searching at the track-level of a disk for


a record with a particular key. Therefore, address translation usually involves
the derivation of a track address and then the placement of a record with a
particular key at the first free location on that track. In effect, a track is
treated as though it is a bucket.

7225
The major difference between the two techniques is that records within a
track in a record-addressable device are scanned on the basis of a key without
bringing the records into main memory. This results in a significant time
saving. With sector addressable devices, the complete sector must be brought
into main memory and records are individually examined to locate a desired
record.
In sector-addressable devices, some inter-sector space can be lost because
an integral number of records may not fit in a complete sector. This problem
is not faced in a record-addressable device.
Sector addressable devices cost less and provide reasonable performance
when many records can reside in a bucket (i.e., sector) and some overflows are
expected.

In REGIONAL(1) files, the exact location of the region is determined by the


key using an address translation scheme. In REGIONAL(2) files the starting
point for a linear search is determined by the key. Now, if variable length
records were allowed, the location of a particular region would depend upon
the location of previous regions (i.e., a function of more than just the key).
Since the size of intermediate records could not be known a priori these types
of file structures do not allow variable length records.

Since the airline reservation system is on-line, it is necessary to have fast


access. The two-file system is faster than the one file system because shorter
records have to be scanned in the region(3) FILE, and this record is the
potential bottleneck in the system. The short record consists of a source key
associated with the REGIONAL(1) type passenger file. Access to a
REGIONAL(1) file requires very little time.
Whenever one element in a system is optimized another element is
sacrificed. In this example, more memory is used in the two file system.
Every passenger must be allocated an extra field, namely the source key for its
record in the passenger file.
A consequence of the two file system is the necessity for garbage
collection or returning of source keys from cancelled passenger records and
passenger lists of completed flights. This extra processing need not be done
on-line but in some regular fashion (perhaps by demand). Another
ramification of the two file system is ready access to the passenger file which
may be required as the information needs are expanded or amount of
information is changed.
A disadvantage with the two file system is that passenger information,
which is stored on the REGIONAL(1) file, must be of fixed length, whereas
variable length records can be used in a REGIONAL(3) file.

7-26
EXERCISES SECTION 7-12 PAGE 810

1) Function LOCATE(S,P,D). Given S, P, and D, the three-level address of


a word in virtual memory, this function locates the address of the word in
main memory. If the page table for segment 5S is not present, then it must be
fetched. Similarly, if page P of the page table is external, then it must be
fetched. SEG# give the number of segments in the segment table (which
always resides in main memory). Temporary indices are I, J, and Q.

1. [Examine segment table]


I+ 1
Repeat while I < SEG# and SEGMENT_NAME!]] Ss
I+I+1
IfI> SEG#
then Write('SEGMENT NOT FOUND’)
Return(0)
2. [Page table present?|
If PRESENCE|I] = 0
then Read page in auxiliary memory at address P_LTAB_ADDRI]|
into page frame at address Q (where Q is chosen by some
page replacement algorithm)
P_TAB_ADDRI]] — Q
Repeat for J = Q, Q + 1, ..., Q + LENGTH_IN_PAGES|]] - 1
Read page in auxiliary memory at address PAGE_ADDR{J]
into page frame at address Q (where Q is chosen by some
page replacement algorithm)
PAGE_ADDR[J] — Q
else If PAGE_ADDR[P] = external address
then Read page in auxiliary memory at address PAGE_ADDR[P]
into page frame at address Q (where Q is chose by some
page replacement algorithm)
PAGE_ADDRIP] + Q
3. [Add displacement to page frame address}
Return(PAGE_ADDR[P] + D)

The MULTICS file system is user oriented; no special knowledge of system


command language instructions for describing files is needed. All virtual
addresses are translated automatically by the operating system into real
main-memory addresses. The penalty for such a convenience may be extra
I/O transfers due to paging and less efficient use of external memory.
Consider first the processing of direct files and the direct processing of
indexed-sequentia! files. A request for one record from a data segment results
in the fetching of an entire page. All I/O commands involve at least one page
and may promote thrashing which decreases efficiency dramatically.

Vr27
For serial processing, the page frame can be thought of as a memory
buffer. Given this view, the MULTICS file system should behave in a manner
very similar to a file-based system for serial processing.
The conversion and installation of application programs should not
present any major difficulties. *

If a page or segment is replaced on a strictly random basis then thrashing is


probable. Thrashing is the condition where pages are demanded from external
memory so often that most of the time is spent replacing and moving pages.
The cause of thrashing is the replacement of frequently referenced pages.
A better method is to replace pages which are rarely referenced (i.e.,
error message modules, initialization procedures). One such replacement
strategy is the Least Recently Used strategy (LRU). It involves keeping track
of which pages in main memory were recently used. The page least recently
used is the candidate for replacement.
Other strategies are Least Often Used, First-In-First-Out, and
combinations thereof. No method works well all the time, but in some cases it
is possible to write a program-dependent page replacement algorithm which is
very efficient for the particular program.

4) Algorithm VSAM_SKIP_SEQ. Given a VSAM file, MASTER, this


algorithm accesses the records skip sequentially according to a transaction file,
TRANSACTION. A typical record of the index set, IND_REC, contains a
KEY and ADDR field, where the ADDR field is a link to a sequence set. A
record from the sequence set, SEQ REC, has the same format, but its ADDR
field is a link to a control interval, except for the last record where it is a link
to the first record in the next sequence set. The control intervals contain the
MASTER records. Such a record is called MRECORD and contains a KEY
and INFO field. The TRANSACTION record, TRECORD, has an additional
field, TYPE. This algorithm is similar to algorithm IS_SEQ SCOPE, but
should employ = subalgorithms similar to those in algorithm
IS_DIRECT_SCOPE to process the individual transaction types. It is
assumed that the address of the first index set record is contained in the
variable ADDRESS. Other address variables include SEQS_ADDR,
OLD_SEQS_ADDR, SEQR_ADDR, HIGH, and TEMP, all of which reference
a sequence set record; CONTILADDR and OLD_CONTI_ADDR, which
reference a control interval; and MREC_ADDR and OLD _MREC_ADDR,
which reference records of the MASTER file.

1. [Initializations|
Open MASTER file for I/O
Open TRANSACTION file for input
OLD_SEQS_ADDR + OLD_CONTI_ADDR «+ OLD_MREC_ADDR + NI
SEQS_ADDR + ADDR of IND_REC(ADDRESS)
HIGH + address of second last record at sequence set SEQGS_ADDR

720
2. [Process all transactions]
INSERT_FLAG + false
Read TRANSACTION file into TRECORD
Repeat step 3 while send of TRANSACTION file and -INSERT_FLAG
3. [Locate proper sequence set]|
Repeat while KEY of SEQ _REC(HIGH) < KEY of TRECORD
TEMP + address of last record at SEQS_ADDR
If ADDR of SEQ_REC(TEMP) = NULL
then INSERT_FLAG + true
else SEQS_ADDR «+ ADDR of SEQ_REC(TEMP)
HIGH + address of second last record at sequence
set SEQS_ADDR
(locate proper control interval)
If SEQS_ADDR = OLD_SEQS_ADDR
then SEQR_ADDR ~— OLD_SEQR_ADDR
else SEQR_ADDR + address of first record in IBeqRICAICE
set SEQS_ADDR
Repeat while KEY of SEQ_REC(SEQR_ADDR) < KEY
of TRECORD
SEQR_ADDR + address of next record in sequence
set SEQS_ADDR
CONTI_ADDR + ADDR of SEQ_REC(SEQR_ADDR)
(locate proper record)
If CONTI_ADDR = OLD_CONTI_ADDR
then MREC_ADDR + OLD_MREC_ADDR
else MREC_ADDR + address of first record in control
interval CONTI_LADDR
Repeat while KEY of MRECORD(MREC_ADDR) < KEY
of TRECORD .
MREC_ADDR + address of next record in control
interval CONTI_ADDR
(process the transaction)
Process transaction against MRECORD(MREC_ADDR)
(prepare for next transaction)
OLD_SEQS_ADDR + SEQS_ADDR
OLD_CONTI_ADDR + CONTI_ADDR
OLD_MREC_ADDR «+ MREC_ADDR
4. [Expected insertion transaction]
If INSERT_FLAG
then Repeat while ~end of TRANSACTION file
If TYPE of TRECORD $ insertion
then Write(/INVALID TRANSACTION’)
else Process insertion transaction
Read TRANSACTION file into TRECORD

IELo
5. [Finished]
Close MASTER file
Close TRANSACTION file
Return

Algorithm VSAM_DIRECT(MASTER). Given a VSAM file, MASTER,


this algorithm accesses a record directly and processes a transaction against it.
All variables used in this procedure are as described in algorithm
VSAM_SKIP_SEQ. ADDRESS is assumed to be initialized to the address of
the first record in the index set. Recall that the transaction types can be
handled in a manner similar to the subalgorithms of IS_DIRECT_SCOPE.

1. [Initializations]
Open MASTER file
Read TRECORD
2. [Insertion at end of MASTER file?]
TEMP + address of last record in index set
If KEY of TRECORD > KEY of IND_REC(TEMP)
then If TYPE of TRECORD ea insertion
then Write(/INVALID TRANSACTION’)
Return
else TEMP + ADDR of IND_REC(TEMP)
ADDRESS + address of second last record in sequence
set TEMP
TEMP + ADDR of SEQ_REC(ADDRESS)
ADDRESS + address of first free space in control
interval TEMP
Process transaction against ep oer ene)
Return
3. (Locate pproper sequence set]
Repeat while KEY of IND_REC(ADDRESS) < KEY of TRECORD
ADDRESS + address of next record in index set
TEMP + ADDR of IND_REC(ADDRESS)
4. [Locate proper control interval]
ADDRESS + address of first record in sequence set TEMP
Repeat while KEY of SEQ_REC(ADDRESS) < KEY of TRECORD
ADDRESS + address of next record in sequence set TEMP
TEMP + ADDR of SEQ_REC(ADDRESS)
= [Locate proper record]
ADDRESS + address of first record in control area TEMP
Repeat while KEY ofMRECORD(ADDRESS) < KEY of TRECORD
ADDRESS + address of next record in control area TEMP
6. [Process the transaction]
Process transaction against MRECORD(ADDRESS)
Return

7-30
5) The basic advantages of a key-sequenced VSAM file over an IBM indexed
sequential file are:
— dynamic processing capabilities
— garbage collection which recovers space from deletion and updates
which yield a shorter record length.
— insertions never go into overflow area (a responsibility of user in
IBM IS files); therefore a simple access algorithm.
— additional access nodes
— skip sequential
— relative byte
— the average access time for a single record in a VSAM file is less than
that of an IBM IS file. This is because of the linear search required for
records in the overflow are.

Of course there are disadvantages in choosing a VSAM file over IBM IS file:

— larger overhead in VSAM - algorithms are required for garbage


collection, control interval splitting, sequence set splitting.
— accessing an IBM IS file (on disk) sequentially may involve less cylinder
head movement because of the same cylinder overflow technique (i.e.,
the logical order of a VSAM file does not correspond to the physical
order.

La
EXERCISES SECTION 7-13 PAGE 825

1) Two tables are required in our general multilist structure: the secondary index
table, and the info/field corrélation table. Examples below are given to
demonstrate their use in accessing a record.

Info/Field Correlation Table


GENERAL FIELD BEGIN
1 ‘address! N 1
‘doctor! 2) /1\
‘drug! 3

‘name!
G# ‘ward!
‘dummy’

Secondary Index Table


PARTICULAR PKEY LENGTH
‘Black! 20913628» 2 eee ee ee
"Novak!
4! Turtle!
"Wald!
'Cyrol! 0913628 2
"Hy poch!
1p nyt

INFO(1) INFO(2) LINK(2) INFO(3) _ LINK(3) 2. INFO(N)


0913628 ‘Black’ 1029372 ‘Cyrol’ 4111234 i S'toon
Each record consists of several link fields and several (more) information
fields. The link fields form a chain of records which share 2 common property
(with the particular value in the associated INFO field). A link of null always
denotes the end of the list.
The PKEY field of the secondary index table supplies the primary key of
the head of the list of a PARTICULAR value for a GENERAL category. As
expected the length of the linked list is contained in the LENGTH field. Note
that every range in the secondary index table is ordered alphabetically by the
PARTICULAR field.

1332
The Info/Field correlation table is responsible via the BEGIN field for
identifying a range in the secondary index table for each category. The
FIELD field points out which INFO in the record contains the GENERAL
category.
Recall the example query: ‘‘List the names of all patients in the general
ward who are taking (the drug) CYROL.” In this case ‘ward general”, and
“drug CYROL” correspond to X and Y, and ‘‘name”’ corresponds to the
output Z. Note ‘‘drug’’, ‘‘ward”, and ‘‘name”’ are the general categories
whereas ‘‘general’’ and ‘‘CYROL”’ are the particular values. Therefore we
shall assumed from some sort of query scanner, the following input:
_ an array, G, of subscripts into the info/field correlation table.
_ an array, P, of character strings, supposedly properties in the secondary
index table.
— an index, N, which gives the size of array P (and also determines the size
of array G = N + 1). By virtue of the query we expect P[I] (1 <1 <
N) to be a property of the general category GENERAL.
Usually the problem is well enough defined or constrained that the general
categories are known a priori. Then the logic of the algorithm is modified so
that the info/field correlation table is not required, and the proper secondary
index table is automatically searched. A particular item value will suffice
alone in such a query because the category is assumed.

Procedure MULTILIST(P,G,N). Given the miultilist structure as


previously described, and the arrays P and G with index N, this procedure
outputs information G[N+1] for all records with properties Bil) PieL Pin
in general categories G[1], G[2], ..., G[N] respectively. Temporary subscripts
are I, B, E, and SHORT. NEXT contains a value for primary key, and
EMPTY_SET, a boolean variable is used to check for the existence of at least
one record which satisfies both properties.

1. [Search for particular values in secondary index table]


MIN + high-value ;
Repeat fori ='1, 2.2 N
B + BEGIN[G[I]]
E + BEGIN(G[I]+1] - 1
Repeat while B < E and PARTICULARIB] aPII]
B+B+1
IffB>E
then Write('NON-EXISTENT PARTICULAR VAUE')
Return
If LENGTH(B) < MIN
then MIN +- LENGTHIB]
SHORT -—B

230
2. [Chain down list of shortest length]
NEXT + PKEY|[SHORT]
P[SHORT] + P[N]
G[SHORT] — G[N]
EMPTY_SET < true
Repeat while NEXT 4 NULL (more records in shortest list)
Read RECORD(NEXT)
|iets
(check if all other properties hold)
Repeat while I < N and INFO(FIELD[G[I]]) of RECORD(NEXT) =: Pil]
eae
Ifl=N
then Write INFO(FIELD[G[N+1]]) of RECORD(NEXT)
EMPTY_SET + false
NEXT «+ LINK(FIELD[G[N]]) of RECORD({NEXT)
3. [Any records satisfy conditions?|
If EMPTY_SET
then Write(/NO RECORDS SATISFY ALL CONDITIONS’)
Return

bo In the general inverted list structure, two tables are required: the inverted list
and the property table.

property table inverted list

PROPERTY BEGIN PKEY


Va! 1 0931
iB! 4 1013
Lol 6 3931
td! 7 1029
3084
0913

The given inverted list is actually the concatenation of several inverted


lists, one for each property. he property table is ordered by property name
and provides the applicable range.
The input variables: X, Y, and Z, are cha:acter strings. Supposedly X
and Y are found in the property table. The output category z is assumed to
be contained in the field INFO(Z).

7-34
Procedure INVERTLIST(X,Y,Z). Given the tables of the inverted list
structure and the character strings, X, Y, and Z, this procedure outputs
information Z for all records with properties described by X and Y. INFO(Z)
is the file which contains information Z; PROP# gives the number of
properties in the property table. Temporary variables are: TEMP, J, BA, BB,
EA, and EB, indices into the property table, and EMPTY_SET, a boolean
variable.

1. [Get indices for properties X and Y]


ett bex toe Y:
then, “Xx <> Y
I-11
TEMP + X
Repeat while I < PROP# and PROPERTY(I] 54 TEMP
I-I+1
Ii PROP?
then Write(/INVALID PROPERTY’)
Return
A+lI
I+ 1
TEMP + Y
Repeat while I < PROP# and PROPERTY|(I] 4 TEMP
I+I+1
If 1 > PROP#
then Write(/INVALID PROPERTY’)
Return
B+ I
2. [Get range of each property in inverted list]
BA + BEGIN{[A]
EA + BEGIN[A + 1] -1
BB «— BEGINIB]
EB + BEGINIB + 1] - 1
EMPTY_SET + true
3. [Find common elements in each range]
Repeat while BA < EA and BB < EB
If PKEY[BA] = PKEY[BB]
then Read RECORD(PKEY([BA])
Output INFO(Z)
BA + BA+1
BB + BB+1
EMPTY_SET + false
else If PKEY[BA] > PKEY[BB]
then BB+ BB+1
else BA+ BA+1

1335
4. [Any records satisfy both properties?|
If EMPTY_SET
then Write(’NO ITEM SATISFIES BOTH PROPERTIES’)
Return

The item values for a category in a controlled list-length muitilist can be


‘segregated (by collating or arightmetic sequence usually) into several groups.
Since each group is distinguishable from the others and the items of a group
are chained together, we have the general multilist structure. Therefore,
algorithm MULTILIST of exercise 1, with the following modifications will
suffice as an algorithm for a controlled list-length multilist.
The operator ‘‘satisfies’’ must be introduced because the item value of
the secondary index table need not equal the input property to satisfy the
property condition (i.e. other conditions are subset, or approximation). It
may, however, be the case that the record item must satisfy a more restrictive
condition.

Procedure CONT_MULT(P,G,N). This procedure is identical to


procedure MULTILIST except for the following changes:

Ms [J
B + BEGIN[G[]]]
EB — BEGIN(G[I] + 1) -1
Repeat while B < E and -(PARTICULAR|B] satisfies P[]])
Ba Bi I
ff Bo > E
then Write('NO SUBSET OF PROPERTY APPLIES’)
Return
If LENGTHIB] ...
[..4 then
Read RECORD(NEXT)
eat
Repeat while I < N and INFO(FIELD[G[I]]) of RECORD(NEXT) satisfies P[]]
l—1+a
Ifil>N
then Output INFO(FIELD[G[N+]]}) ...

7-36
An example of the controlled list-length multilist follows:

GENERAL | FIELD | BEGIN PARTICULAR | PKEY | LENGTH


"AGE! 1 ‘10’
8 15!
‘20!
195!

‘35!

'50
‘90! mem
to
© W

PKEY 8437 is a primary key for the head of a chain of records with age field
item in range 50-89

In our example using cellular serial access, two tables are required:

property table cell table

PROPERTY | FIELD | BEGIN | END POSITION | LENGTH


rat 10 2 2
'p! 4 5 1
tel oT 6 1
‘gq! 3 1 2
is 2 is
4 2
5 1

cell 1

4450 rd! 6843 cell 2


6313 ly! null
6843 rae null

ToT.
Procedure CELLULAR_SERIAL(X,Y,Z). Given the cellular-serial
structure as previously described, and the character strings, X, Y, and Z, this
procedure outputs information from the INFO({Z) field of all records with
properties X and Y. This procedure is similar to both procedures MULTILIST
and INVERTLIST, so most of the variables used are previously discussed. S is
the index of an entry in the cell table (whose LENGTH field is minimal), PL is
the index of an entry in the property table, and FL is the field of a record
which contains the category of PROPERTY[PL]. Generally, S implies short,
L implies long for variable names.

1. [Get indices for properties X and Y]


(as in algorithm INVERTLIST)
2. {Find cells which share property X and Y]
BA + BEGIN[A]
EA + END[A]
BB + BEGIN|B]
EB «+ END[B]
EMPTY_SET + true
Repeat step 3 while BA < EA and BB < EB
3. [Find entries in cell which share property X and Y|
If CELL[BA] = CELL[BB]
then If LENGTH[BA] > LENGTH[BB]
then S «+ BB
PL<-A
else S+ BA
PL+B
PS + POSITION{S]
FL + FIELD[PL]
Repeat while PS A 0
Read RECORD(PS) of CELL(S)
If INFO[FL] of | RECORD[PS] in CELLS]
PROPERTY|PL]
then Output INFO(Z) of RECORD(PS) in CELL(S)
EMPTY_SET + false
PS — LINK(PL) of RECORD(PS) in CELL(S)
BA — BA +1
BB «+ BB+ 1
else If CELL[BA] > CELL[BB]
then BB+ BB+1°
else BA+BA+1
4. [Any records satisfy both properties?|
If EMPTY_SET
then Write(/NO ITEM SATISFIES BOTH PROPERTIES’)
Return
The primary criteria for record selection in the given situation is to minimize
the reading of records altogether. Any technique which can do this will
certainly be worth the extra effort, however, the success of the technique
depends on the structure of the lists.
If the range of the inverted lists is unordered (by primary key) or the
multilist secondary index links are unordered (also by primary key), then the
only method is to choose the shortest list, read all the records of that list and
examined them for the presence of the other property. The length of the
inverted list is the number of entries in the range, and the length of the
multilist (given by LENGTH fields) is the number of records in the chain.
However, if both lists are ordered, then optimizations can be made to
the average case. The algorithm which takes advantage of the ordering
follows.

property table inverted list


PROPERTY BEGIN’ END PRIME-KEY
"4! 21 24 0931
ubt 4 4 1013
: “ 6311
> 1029
3084
ix! 1 oe eet { 411]
ys 5 6 ~ 0913
un 13 16 3056
7614
8496 ;

multilist index : records


Oe PRIME-KEY LENGTH : PRIME-KEY INFO LINK ETC
A! 1013 3 0913 - null
'B! 0913 1 0931 - 0987
1001 - 7654
DY 6331 3 is oe ie
nyé null 0 1989 - 8561
‘TZ! 0931 4 55

The guiding principle in the algorithm is to read a record from the


shortest list provided the record is a candidate. A record is a candidate when
its primary key is greater than or equal to the primary key of the most
recently examined entry of the longer list, otherwise the entry from the longer
list is discarded and the next is examined. The algorithm terminates when the
shortest list has been completely examined.
The worst possible case of this algorithm is as bad as the unordered list,
but the average case is much improved.

0559
Procedure MULTI_& INVERT(A,B). Given A, the subscript to an
entry in the property list which corresponds to a range in the inverted list,
and B, the subscript of an entry in the multilist index, this procedure outputs
information from all the records with PROPERTY|A] of the property table
and PROPERTY|B] of the multilist index. Variable names and notation will
be as in the earlier exercises in this section.

1. [Initializations]
BA + BEGIN|A]
EA + END[A]
NEW_KEY + PRINT_KEY[B] of multilist index
L + LENGTHIB] of multilist
EMPTY_SET < true
2. [Read all records which have been proved to be necessary]
Repeat while BA < EA and L > 0
If PRIME_KEY|[BA] of invert list = NEW_KEY
then Read RECORD(NEW_KEY)
Output desired information from record
NEW_KEY + LINK(NEW_KEY)
BA — BA +1
L+L-1
EMPTY_SET + false
If PRIME_KEY[BA] of invert list < NEW_KEY
then BA «+ BA+1
else IfL=1
then L+0O
else IfL<EA-BA+1
then Read RECORD(NEW_KEY)
NEW_KEY + LINK(NEW_KEY)
L+L-l
else Read RECORD(PRIME_KEY|BA]) of
inverted list
If INFO(PRIME_KEY|BA])=PROPERTY
[B] of multilist index
_then
Output desired information
EMPTY_SET + false
NEW_KEY + LINK(PRIME_KEY!?A])
BA + BA +1
3. [Any information displayed?]
If EMPTY_SET
then Write(/NO RECRODS SATISFY BOTH PROPERTIES’)
Return

7-40
6) An involute structure has all the advantages and disadvantages of the
multilist structure and the following:
advantages: Most efficient use of storage (warranted when knowledge of
a secondary index item is not required at involute record level)
disadvantages: It is difficult, time-consuming, and costly (but not
impossible) to determine a secondary index item of an involute record
A very good structure when answering question such as ‘‘Does property X,
property Y, etc. hold for a databox?”’.

7) Function COUNT Given the inverted list structure of exercise 2, and


properties X,, Xo, -.-, Xp, this function counts the number of records which
share all those properties. All items provide secondary access through the
inverted list structure. Two arrays: B, and E, are required to save the
boundaries of the range of each property. Other temporary variables are the
subscripts I and J. The variable P# gives the number of properties in the
property table.

1: [Initializations]
RESULT + 0
2: [For each property isolate the range in the inverted list]
Repeat for I = 1, 2, ..., N
J+1
Repeat while J < P# and x, P{J]
J+ J+1
If J > P#
then Write(‘INVALID PROPERTY’)
Return(0)
Bil] — BEGIN|J]
E[I] — END[J]
[Compare entries of each property range to the first property range]
Repeat thru step 8 while B[I] < E[I]
[Look for common entry in all ranges]
I+2
Repeat thru step 7 while I < N
[Isolate location of expected entry]
Repeat while B[I] < E[I] and PKEY(B[!]) < PKEY(B[1])
B{I] — Bil] + 1
[End of property range?|
If Bil] > Ey]
then Return(RESULT)
{Matching primary keys?|
If PKEY(B[I]) = PKEY(B[1))
then I+I+1
else Repeat while B[1] < E[1] and PKEY(B[1]) < PKEY(BJ}])
Bil] + Bil] + 1

7-41
If Bil] > E[1]
then Return(RESULT)
else [+2
8. [All property ranges have primary key in common]
RESULT « RESULT + 1
Bi1] — Bil] + 1
I+ 2
9. [Finished]
Return(RESULT)
,

If a repeated field item is used in any record then the complications of


variable size records are introduced. If it is used as a secondary index item
then the trouble really begins. Common to all structures is the increase in
overhead and processing time.
A multilist structure is not particularly well suited for a repeated field
item as a secondary index because conjunctive queries are still difficult and an
extra link field must be allocated for cach extra item. It is necessary to store
the value of each item because they are irreproducible (i.e., an involute
structure would be impossible). However, the multilist structure does have the
advantages of using very little main memory and being easy to program.
The inverted list structure still handles conjunctive terms in queries but
at the expense of much main memory (the inverted list will be getting even
larger).

7-42

You might also like