0 ratings0% found this document useful (0 votes) 175 views42 pagesStack
Data Structures Stack Chap
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content,
claim it here.
Available Formats
Download as PDF or read online on Scribd
6.36 Data Structures
2. [Find new value of REAR.)
If FRONT := NULL, then: [Queue
Set FRONT := I and REAR := 1
Else if REAR = N, then:
Set REAR
Else;
Set REAR := REAR + 1.
[End of If stracture.}
3. Set QUEUE[REAR] :=
4, Return.
(TEM. [This inserts new element.]
Procedure 6.14: QDELETE(QUEUE, N, FRONT, REAR, ITEM)
This procedure deletes an element from a queue and
ITEM.
1. [Queue already empty}
If FRONT := NULL, then: Write: UNDERFLOW, and Return.
2. Set ITEM := QUEUE[FRONT].
3. [Find new value of FRONT.]
If FRONT = REAR, then: [Queue has only one element to start.]
signs it to the variable
Set FRONT := NULL and REAR := NULL,
Else if FRONT = N, then:
Set FRONT :=
Else:
Set FRONT := FRONT + 1
{End of If structure.}
4. Return.
6.11 LINKED REPRESENTATION OF QUEUES
In this section we discuss the linked representation of a queue. A linked queue is a queue
implemented as a linked list with two pointer variables FRONT and REAR pointing to the nodes
which is in the FRONT and REAR of the queue. The INFO ficlds of the list hold the elements of
the queue and the LINK fields hold pointers to the neighboring elements in the queue. Fig. 6.22
illustrates the linked representation of the queue shown in Fig. 6.16(a).
aes | | —{ cco | | —+{ poo |x
Front Rear
Fig, 6.22Stacks, Queues, Recursic
START
AAAI I |
|
Fig. 6.27
INFO PRN _LINK
1 BBB 2 [ 6
stant [5 Le 7
Ln ——
3 | 0DD 4 4
AVAIL | 2 4 | GEE 4 8 1
es [aaa 1] { 4 |
6 | ccc 2 3
7 10
8 | GGG 5 0
9 | FFF 4 3
10 1"
" 12
12 0 |
Fig. 6.28
The main property of the one-way list representation of a priority queue is that the
element in the queue that should be processed first always appears at the beginning |
of the one-way list. Accordingly, it is a very simple matter to delete and process an !
element from our priority queue, The outline of the algorithm foltows.
Algorithm 6.17: This algorithm deletes and processes the first element in a priority queue
whieh appears in memory as a one-way list.
Set ITEM := INFO[START].-[This saves the data in; the first node]
Delete first node from the list.
Process ITEM.
Exit
Beyer6.6 Data Structures
Minimizing Overflow
There is an essential difference between underflow and overflow in dealing with stacks. Underflow
depends exclusively upon the given algorithm and the given input data, and hence there is no
direct control by the programmer. Overflow, on the other hand, depends upon the arbitrary choice
of the programmer for the amount of memory space reserved for each stack, and this choice does
influence the number of times overflow may occur.
Generally speaking, the number of elements in a stack fluctuates as elements are added to or
removed from a stack. Accordingly, the particular choice of the amount of memory for a given
stack involves a time-space tradeoff. Specifically, initially reserving a great deal of space for each
stack will decrease the number of times overflow may occur; however, this may be an expensive
use of the space if most of the space is seldom used. On the other hand, reserving a small amount
of space for each stack may increase the number of times overflow occurs: and the time required
for resolving an overflow, such as by adding space to the stack. may be more expensive than the
space saved.
Various techniques have been developed which modify the array representation of stacks so that
the amount of space reserved for more than one stack may be more efficiently used, Most of these
techniques lie beyond the scope of this text. We do illustrate ane such technique in the following
example.
Example 6.3
Suppose a given algorithm requires two stacks, A and B. One can define an array
STACKA with 1, elements for stack A and an array STACKS with n, elements for stack
B. Overflow will occur when either stack A contains more than nm, elements or stack B
contains more than n, elements.
Suppose instead that we define a single array STACK with a = m, +n, elements for
stacks A and B together. As pictured in Fig. 6.6, we define STACK[1] as the bottom of
stack A and let A “grow” to the right, and we define STACK{n] as the bottom of stack
B and let B “grow” to the left. In this case, overflow will occur only when A and B
together have more than n =n, +n, elements. This technique will usually decrease
the number of times overflow occurs even though we have not increased the total
amount of space reserved for the two stacks. In using this data structure, the
operations of PUSH and POP will need to be modified.
12) 8 4 n-9 9-2 n-1 oo
CI EF
SuackA Stack 8
Fig, 6.6Stacks, Queues, Recursion 6.33
| ‘AAA BB } occ DD j
| (a) |
Bae }—-[ ec }—-[b00 i
i ©) |
}
| 588 (eee |—-| po) EGE FFF |
| ©
|
ee. 000 cee |} —-[ FFF
@)
| Fig. 6.19 i
Representation of Queues
Queues may be represented in the computer in various ways, usually by means at one-way lists or
linear arrays. Unless otherwise stated or implied, each of our queues will be maintained by a linear
array QUEUE and two pointer variables: FRONT, containing the location of the front element of
the queue; and REAR, containing .the location of the rear element of the queue. The condition
FRONT = NULL will indicate that the queue is empty.
Figure 6.20 shows the way the array in Fig. 6.19 will be stared in memory using an array
QUEUE with N elements. Figure 6.20 also indicates the way elements will be deleted from the
queue and the way new elements will be added to the queue. Observe that whenever an clement is
deleted from the queue, the value of FRONT is increased by 1; this can be implemented by the
assignment
FRONT := FRONT + 1
Similarly, whenever an element is added to the queue, the value of REAR is increased by 1: this
can be implemented by the assignment
REAR := REAR + 1
This means that after N insertions, the rear element of the queue will occupy QUEVE[N] or, in
other words; eventually the queue will occupy the last part of the array. This occurs even though
the queue itself may not contain many elements.
Suppose we want to insert an element [TEM into a queue at the time the queue does occupy the
last part of the array, i.e, when REAR = N, One way (0 do this is to simply move the entire queue
to the beginning of the array, changing FRONT and REAR accordingly, and then inserting ITEM
as above, This procedure may be very expensive. The procedure we adopt is to assume that the
array QUEUE is circular, that is, that QUEUE[!] comes after QUEVE[N] in the array. With this
assumption, we insert ITEM into the queue by assigning ITEM to QUEUE[I]. Specifically, instead
of increasing REAR to N + 1, we reset REAR = | and then assign
QUEUE/REAR] := ITEM68 Data Structures
‘The array representation of stack calls for the maintenance of a variable MAXSTK which gives
the maximum number of elements that can be held by the stack. Also, it calls for the checking of
OVERFLOW in the case of push operation (TOP=MAXSTK) and UNDERFLOW in the case of
pop operation (TOP=0). In contrast, the linked representation of stacks is free of these requirements.
There is no limitation on the capacity of the linked stack and hence it can support as many push
operations (insertion of nodes) as the free-storage list ( the AVAIL list) can support. This dispenses
With the need to maintain the MAXSTK variable and consequently on the checking of OVERFLOW
of the linked stack during a push operation.
Procedure 6.3: PUSH_LINKSTACK(INFO, LINK, TOP, AVAIL, ITEM)
This procedure pushes an ITEM into a linked stack
1, [Available space?] If AVAIL = NULL, then Write
OVERFLOW and Exit
2, [Remove first node from AVAIL list]
Set NEW := AVAIL and AVAIL := LINK[AVAIL].
3. Set INFO[NEW] := ITEM [ Copies ITEM into new node}
4, Set LINK[NEW] := TOP [New node points to the original top node in
the stack]
5. Set TOP = NEW [Reset TOP to point to the new node at the top of
the stack]
6. Exit.
Procedure 6.4: POP_LLINKSTACK(INFO, LINK, TOP, AVAIL, ITEM)
This procedure deletes the top element of a linked stack and assigns it to the
variable [TEM
1. [Stack ha
IF TO!
an item to be removed?}
NULL then Write: UNDERFLOW and Exit.
2. Set ITEM := INFO[TOP] [Copies the top clement of stack into ITEM }
3. Set TEMP := TOP and TOP = LINKITOP]
[Remember the old value of the TOP pointer in TEMP
and reset TOP to point to the next element in the stack }
4. [Return deleted node to the AVAIL list]
Set LINK[TEMP] = AVAIL and AVAIL = TEMP.
5. Exit.
However, the condition TOP = NULL may be retained in the pop procedure to prevent deletion
from an empty linked stack and the condition AVAIL = NULL to check for available space in the
free-storage list.
Example 6.4
Consider the linked stack shown in Fig. 6.7, the snapshots of the stack structure on
execution of the following operations are shown in Fig. 6.10:Chapter Six
Stacks, Queues, Recursion
6.1 INTRODUCTION
The linear lists and linear arrays discussed in the previous chapters allowed one to insert and delete
elements at any place in the list—at the beginning, at the end, or in the middle, There are certain
frequent situations in computer science when one wants to restrict insertions and deletions so that
they can take place only at the beginning or the end of the list, not in the middle. Two of the data
structures that are useful in such situations are stacks and queues.
A stack is a linear structure in which items may be added or removed only at one end. Figure
6.1 pictures three everyday examples of such a structure: a stack of dishes, a stack of pennics and
a stack of folded towels. Observe that an item may be added or removed only from the top af any
of the stacks. This means, in particular, that the last item to be added to a stack is the first item to
be removed. Accordingly, stacks are also called last-in first-out (LIFO) lists. Other names used for
stacks are “piles” and “push-down lists.” Although the stack may seem to be a very restricted type
of data structure, it has many important applications in computer science
A queue is a linear list in which items may be added only at one end and items may be removed
only at the other end, The name “queue” likely comes from the everyday use of the term. Consider
a queue of people waiting at a bus stop, as pictured in Fig, 6.2. Each new person who comes takes
his or her place at the end of the line, and when the bus comes, the people at the front of the line
board first. Clearly, the first person in the line is the first person to leave. Thus queues are also
called first-in first-out (FIFO) lists. Another example of a queue is a batch of jobs waiting to be
processed, assuming no job has higher priority than the others.
The notion of recursion is fundamental in computer science. This topic is introduced in this
chapter because one way of simulating recursion is by means of a stack structure.Stacks, Queues, Recursion
6.4 LINKED REPRESENTATION OF STACKS
In this section we discuss the representation of stacks using a one-way list or singly linked list. The
advantages of linked lists over arrays have already been underlined. It is in this perspective that
one appreciates the use of a linked list for stacks in comparison to that of arrays.
The linked representation of a stack, commonly termed linked stack is a stack that is implemented
using a singly linked list. The INFO fields of the nodes hold the clements of the stack and the
LINK fields hold pointers to the neighboring element in the stack. The START pointer of the
linked list behaves as the TOP pointer variable of the stack and the null pointer of the last node in
the list signals the bottom of stack. Figure 6.7 illustrates the linked representation of the stack
STACK shown in Fig. 6.5.
Top (START)
“Lim fw [| a
INFO LINK
Top of stack Bottom of stack
Fig, 6.7
A push operation into STACK is accomplished by inserting a node into the front or start of the
list and a pop operation is undertaken by deleting the node pointed to by the START pointer.
Figure 6.8 and Fig. 6.9 illustrate the push and pop operation on the linked stack STACK shown in
Fig. 6.7.
Push’ WWW' inte STACK
STACK betoro Push oporation:
Top
XXX yy | {zzz ]=
‘STACK aftor Push operation
“Top
www Xxx [yy -[ azz [x
Fig. 6.8
Pop from STACK
STACK Betore pop operation:
Yop
me Le} ae
STACK af
|—-[ zz |=Stacks, Queues, Recursion 65)
Procedure 6.1: PUSH(STACK, TOP, MAXSTK, ITEM)
This procedure pushes an ITEM onto a stack.
1, [Stack already filled?)
If TOP = MAXSTK, then: Print: OVERFLOW, and Return.
2. Set TOP := TOP + |. [Increases TOP by 1.]
3. Set STACK[TOP] := ITEM. [Inserts ITEM in new TOP position.)
4. Return.
Procedure 6.2: POP(STACK, TOP, ITEM)
This procedure deletes the top element of STACK and assigns it to the variable
ITEM,
1, [Stack has an item to be removed?}
If TOP = 0, then: Print: UNDERFLOW, and Return.
2. Set ITEM := STACK[TOP]. [Assigns TOP clement to ITEM.}
3. Set TOP := TOP = }. [Decreases TOP by 1.]
4. Return.
Frequently, TOP and MAXSTK are global variables; hence the procedures may be called using
only
PUSH(STACK, ITEM) and POP(STACK, ITEM)
respectively. We note that the value of TOP is changed before the insertion in PUSH but the value
of TOP is changed after the deletion in POP.
Example 6.2
(a) Consider the stack in Fig, 6.5. We simulate the operation PUSH(STACK, WWW):
4. Since TOP = 3, contral is transferred to Step 2.
| 2, TOP =3+1=4
| 3. STACK{TOP] = STACK(4] = WWW.
4. Return.
Note that WWW is now the top element in the stack.
| (b) Consider again the stack in Fig. 6.5. This time we simulate the operation
POP(STACK, ITEM):
1. Since TOP = 3, control is transferred to Step 2.
| 2. ITEM = ZZZ.
3. TOP =3-1=2. |
4. Return.
Observe that STACK[TOP] = STACK[2] = YYY is now the top element in the stack.Stacks, Queues, Recursion 6.37
In the case of insertion into a linked queue, a node borrowed from the AVAIL list and carrying
the item to be inserted is added as the last node of the linked list representing the queue. The
REAR pointer is updated to point to the last node just added to the list. In the case of deletion, the
first node of the list pointed to by FRONT is deleted and the FRONT pointer is updated to point to
the next node in the list. Fig. 6.23 and Fig. 6.24 illustrate the insert and delete operations on the
queue shown in Fig. 6.22.
"EEE'into queve O:
\y AAR Bee eee {ooo [x] —+{ eee |x
| t {
I I
Front Fear pear
\ Ue
Fig. 6.23
-{ cco poo | eee [x
Rear
Fig. 6.24
The array representation of a queue suffers from the drawback of limited queue capacity. This in
turn calls for the checking of OVERFLOW condition every time an insertion is made into the
queue. Also, duc to the inherent disadvantage of the array data structure in which data movement
is expensive, the maintenance of the queue calls for its circular implementation.
In contrast, the linked queue is not limited in capacity and therefore as many nodes as the
AVAIL list can provide, may be inserted into the queue. This dispenses with the need to check for
the OVERFLOW condition during insertion. Also, unlike the array representation, the linked
queue functions as a linear queue and there is no need to view it as ‘circular’ for efficient
management of space.
Procedure 6.15: LINKQ_INSERT(INFO,LINK, FRONT. REAR,AVAILTEM).
his procedure inserts an [TEM into a linked queue
1. [Available space?] If AVAIL = NULL, then Write
OVERFLOW and Exit
2, [Remove first node from AVAIL list]
Set NEW := AVAIL and AVAIL := LINK[AVAIL]
3. Set INFO[NEW] := ITEM and LINK|NEW|=NULL
‘opies ITEM into new node]6.28 Data Structures
(b) Restore the top values of the stacks, That is, set the parameters and local variables equal
to the top values on the stacks, and set ADD equal to the top value on the stack STADD.
(e) Go to Step ADD.
Observe that the translation of “Step K. Call P” does depend on the value of K, but that the
translation of “Step J. Return” does not depend on the value of J. Accordingly, one need translate
only one Return statement, for example, by using
Step L. Return.
as above and then replace every other Return statement by
Go to Step L.
This will simplify the translation of the procedure
Towers of Hanoi, Revisited
Consider again the Towers of Hanoi problem, Procedure 6.11 is a recursive solution to the problem
for n disks. We translate the procedure into. a nonrecursive solution. In order to keep the steps
analogous, we label the beginning statement TOP := NULL as Step 0, Also. only the Retum
statement in Step 5 will be translated, as in (3) on the preceding page,
Procedure 6.12: TOWER(N, BEG, AUX, END)
This is a nonrecursive solution to the Towers of Hanoi, problem for iv disks
Jhieh is obtained by translating the recursive solution TN, STBEG,
TAUX, STEND and STADD will correspond, respe: to the variables
N, BEG, AUX, END and ADD.
0. Set TOP := NULL.
1. If N =1, then:
(a) Write: BEG > END.
(b) Go to Step 5.
[End of If structure.]
2, [Translation of “Call TOWER(N - 1, BEG, END, AUX).”]
(a) (Push current values and new return address onto stacks.]
(i) Set TOP := TOP + 1.
Gi) Set STN[TOP] := N, STBEG|TOP] := BEG,
STAUX{TOP] := AUX, STEND[TOP] := END,
STADD[TOP]
(b) [Reset parameters,]
Get N:= N= 1, BEG := BEG, AUX := END, END := AUX.
(©) Go to Step 1.
3. Write: BEG — END.
4, [Translation of “Call TOWER(N — 1, AUX, BEG, END)
(a) [Push current values and new return address onto stacks.]16 | Data Structures
In order to apply the reduction step again, the algorithm removes the top values, 6
and 12, from the stacks, leaving
| LOWER: 1 UPPEI
and then applies the reduction step to the corresponding sublist A[6], A[7], «.+,
Al12]. The reduction step changes this list as in Fig. 6.9. Observe that the second
| sublist has only one element. Accordingly, the algorithm pushes only the boundary
values 6 and 10 of the first sublist onto the stacks to yield |
LOWER: 1,6 UPPER: 4, 10 |
And so on. The algorithm ends when the stacks do not contain any sublist to be
processed by the reduction step. |
| Ale), AT), ANB]. ALS. AUTO), ALTA}, AL12}.
| 77, 60, 9,88,
66, 77,60, $5, |
66, 77, (60. 55, 99 |
| 6, 77, 60, 8,5, 99
|
First sublist Second sublist |
Fig. 6.13
The formal statement of our quicksort algorithm follows (on pages 6.16-6.17). For notational
convenience and pedagogical considerations, the algorithm is divided into two parts. The first part
gives a procedure, called QUICK, which executes the above reduction step of the algorithm, and
the second part uses QUICK to sort the entire list,
Observe that Step 2(c) (iii) is unnecessary. It has been added to emphasize the symmetry
between Step 2 and Step 3. The procedure does not assume the elements of A are distinct.
Otherwise, the condition LOC # RIGHT in Step 2{a) and the condition LEFT # LOC in Step 3(a)
could be omitted.
The second part of the algorithm follows (on page 6.17). As noted above, LOWER and UPPER
are stacks on which the boundary values of the sublists are stored. (As usual, we use NULL = 0.)
Procedure 6.7: QUICK(A, N, BEG, END, LOC)
Here A is an array with N elements. Parameters BEG and END contain the
boundary values of the sublist of A to which this procedure applies. LOC
keeps irack of the position of the first clement A[BEG] of the sublist during
the procedure. The local variables LEFT and RIGHT will contain the boundary
values of the list of elements that have not been scanned.
1, {Initialize.] Set LEFT := BEG, RIGHT := END and LOC »
2. [Scan from right to left.]
(a) Repeat while A[LOC) < A[RIGHT] and LOC # RIGHT:
RIGHT := RIGHT - 1.
[End of loop.)
BEG.Stacks, Queues, Recursion 6.21
Observe that the first procedure evaluates N! using an iterative loop process. The second procedure,
‘on the other hand, is a recursive procedure, since it contains a call to itself. Some programming
languages, notably FORTRAN, do not allow such recursive subprograms.
Suppose P is a recursive procedure. During the running of an algorithm or a program which
contains P, we associate a level number with cach given execution of procedure P as follows. The
original execution of procedure P is assigned level 1; and each time procedure P is executed
because of a recursive call, its level is | more than the level of the execution that has made the
recursive call. In Example 6.8, Step 1 belongs to level I, Hence Step 2 belongs to level 2, Step 3 to
level 3, Step 4 to level 4 and Step 5 to level 5. On the other hand, Step 6 belongs to level 4, since
it is the result of a return from level 5. In other words, Step 6 and Step 4 belong to the same level
of execution. Similarly, Step 7 belongs to level 3, Step 8 to level 2, and the final step, Step 9, to
the original level 1.
‘The depth of recursion of a recursive procedure P with a given set of arguments refers to the
maximum level number of P during its execution.
Fibonacci Sequence
The celebrated Fibona
i sequence (usually denoted by Fo, Fj, Fo
0, 1. 1, 2, 3, 5,8, 13, 21, 34, 55, ...
‘That is, Fy =0 and F, = | and each succeeding term is the sum of the two preceding terms. For
example, the next two terms of the sequence are
34455=89 and 55 +89 = 144
A formal definition of this function follows:
.) is as follows:
Definition 6.2: (Fibonacci Sequence)
(a) If n = Oorn =I, then F, =n,
(b) If r> 1, then F, a+ Fat
This is another example of a recursive di ition, since the definition refers to itself when it
uses F,_> and F,. , Here (a) the base values are 0 and 1, and (b) the value of F, is defined in
terms of smaller values of m which are closer to the base values. Accordingly, this function is well-
defined.
A procedure for finding the nth term F, of the Fibonacci sequence follows.
Procedure 6.10:
FIBONACCIIFIB, N)
‘This procedure calculates Fy and returns the value in the first parameter FIB.
. IfN=OorN = 1, then: Set FIB := N, and Return.
Call FIBONACCI(FIBA. N — 2).
. Call FIBONACCI(FIBB, N = 1).
. Set FIB := FIBA + FIBB
. Return,
This is another example of a recursive procedure, since the procedure contains a call to itself, In
fact, this procedure contains two calls to itself. We note (sce Solved Problem 6.17) that one can
also write an iterative procedure to calculate F, which does not use recursion.6.14 Dato Structures
‘Symbol Scanned | STACK Expression P
a) A ( A
@ 4 Cs A
@ ¢ Cre A
; @ 8 (+e AB
| @ ¢ Cee AaB
@ ¢ C+ ABC
a - Cee ABC:
a) ¢ (+O ABC:
@) 0 C+ 0- ABC-D
ao C+ O- C1 ABG+D
i (1) E C+ e- cr ABC-DE
027 (+#€-(/ Tt) ABC + DE
(1a) F (+C-(Cr Tt] aABoc+OEF
(14) ) (+ (- ABC-DEFT?/
(5) (*#C-5 ABC+DEFTS
(16) G (+e ABCG+DEFT/G
(7) (+ ABC-DEFT/IG.: -~
(8) + (+s ABG+DEFTIG+—
(19) (ae [Link]/G--H
(20) ) LABG+DEFT/G+-~Het
Fig. 6.12
6.6 QUICKSORT, AN APPLICATION OF STACKS
Let A be a list of n data items. "Sorting A” refers to the operation of rearranging the elements of A
so that they are in some logical order, such as numerically ordered when A contains numerical
data, or alphabetically ordered when A contains character data. The subject of sorting, ineluding
various sorting algorithms, is treated mainly in Chapter 9. This section gives only one sorting
algorithm, called quicksort, in order to illustrate an application of stacks.
‘Quicksort is an algorithm of the divide-and-conquer type. That is, the problem of sorting a set is,
teduced to the problem of sorting two smaller sets. We illustrate this “reduction step” by means of
a specific example.
Suppose A is the following list of 12 numbers:
33, 11, 55, 77, 90, 40, 60, 99, 88,
The reduction step of the quicksort algorithm finds the final position of one of the numbers; in
this illustration, we use the first number, 44. This is accomplished as follows. Beginning with the
Jast number, 66, scan the list from right to left, comparing cach number with 44 and stopping at the
first number less than 44. The number is 22. Interchange 44 and 22 to obtain the list
@) 33, 11. 55, 77, 90, 40, 60, 99, @) 88, 66
(Observe that the numbers 88 and 66 to the right of 44 are each greater than 44.) Beginning with
22, next scan the list in the opposite direction, from left to right, comparing each number with 44
and stopping at the first number greater than 44. The number is 55. Interchange 44 and 55 to
obtain the listStacks, Queues, Recursion 6.45,
22, 33 11, 77. 90, 40, 60, 99, 65) 88. 66
(Observe that the numbers 22, 33 and 11 to the left of 44 are each less than 44.) Beginning this
time with 55, now scan the list in the original direction, from right to left, until mecting the first
number less than 44. It is 40. Interchange 44 and 40 to obtain the list
22, 33, 11, GO) 77, 90, G4) 60, 99, 55, 88, 66
(Again, the numbers to the right of 44 are each greater than 44.) Beginning with 40, scan the list
from left to right. The first number greater than 44 is 77. Interchange 44 and 77 to obtain the list
22, 33, 11, 44, 90, a 60, 99, 55, 88, 66
(Again, the numbers to the left of 44 are each less than 44.) Beginning with 77, scan the list from
right to left seeking a number less than 44. We do not meet such a number before meeting 44. This
means all numbers have been scanned and compared with 44. Furthermore, all numbers less than
44 now form the sublist of numbers to the left of 44, and all numbers greater than 44 now form the
‘sublist of numbers to the right of 44, as shown below:
22,33, 11, 40, 90, 77, 60, 99, 55, 88 66
First sublist Second sublist
Thus 44 is correctly placed in its final position, and the (ask of sorting the original list A has now
been reduced to the task of sorting each of the above subli
The above reduction step is repeated with each sublist containing 2 or more clements. Since we
can process only one sublist at a time, we must be able to keep track of some sublists for future
processing. This is accomplished by using two stacks, called LOWER and UPPER, to temporarily
“hold” such sublists. That is, the addresses of the first and fast elements of each sublist, called its
boundary values, are pushed onto the stacks LOWER and UPPER, respectively: and the reduction
step is applied to a sublist only after its boundary values are removed from the stacks. The
following example illustrates the way the stacks LOWER and UPPER are used.
Example 6.8
Consider the above list A with n = 12 elements. The algorithm begins by pushing the
boundary values 1 and 12 of A onto the stacks to yield
LOWER: 1 UPPER: 12
In order to apply the reduction step, the algorithm first removes the top values 1 and
12 from the stacks, leaving
LOWER: (empty) UPPER: (empty)
and then applies the reduction step to the corresponding list A{1], A[2], .... A[12].
The reduction step, as executed above, finally places the first element, 44, in A[5].
Accordingly, the algorithm pushes the boundary values 1 and 4 of the first sublist
and the boundary values 6 and 12 of the second sublist onto the stacks to yield
LOWER: 1,6 UPPER: 4, 12Data Structures
Divide-and-Conquer Algorithms
Consider a problem P associated with a set S. Suppose A is an algorithm which partitions § into
smaller sets such that the solution of the problem P for $ is reduced to the solution of P for one or
more of the smaller sets. Then A is called a divide-and-conquer algorithm
Two examples of divide-and-conquer algorithms, previously treated, are the quicksort algorithm
in Sec. 6.6 and the binary search algorithm in Sec. 4.7. Recall that the quicksort algorithm uses a
reduetion step to find the location of a single element and to reduce the problem of sorting the
entire set to the problem of sorting smaller sets. The binary search algorithm divides the given
sorted set into two halves so that the problem of searching for an item in the entire set is reduced to
the problem of searching for the item in one of the two halves.
A divide-and-conquer algorithm A may be viewed as a recursive procedure. The reason for this
is that the algorithm A may be viewed as calling itself when it is applied to the smaller sets, The
base criteria for these algorithms are usually the one-element sets. For example, with a sorting
algorithm, a one-clement set is automatically sorted; and with a searching algorithm, a one-element
set requires only a single comparison.
Ackermann Function
The Ackermann function is a function with two arguments each of which can be assigned any
nonnegative integer: 0, 1, 2,.... This function is defined as follows:
Definition 6.3: (Ackermann Function)
(a) If m = 0, then A(m, n) = + 1.
(b) If m #0 but = 0, then A(m, n) = Atm - 1, 1).
(c) If m #0 and n #0, then A(m, n) = A(m = 1, AGn.n = 1)
Once more, we have a recursive definition, since the definition refers to itself in parts (b) and
(c). Observe that A(m, n) is explicitly given only when m = 0, The base criteria are the pairs
OO OD. OL 2, (0,3), sere Os me ove
Although it is not obvious from the definition, the value of any AQ, n) may eventually be
expressed in terms of the value of the function on one or more of the base pairs.
The value of A(1, 3) is calculated in Solved Problem 6.18. Even this simple case requires 15
steps. Generally speaking, the Ackermann function is too complex to evaluate on any but a trivial
example. Its importance comes from its use in mathematical logic. The function is stated here
mainly to give another example of a classical recursive function and to show that the recursion part
of a definition may be complicated.
6.8 TOWERS OF HANOI
“The preceding section gave examples of some recursive definitions and procedures. This section
shows how recursion may be used as a tool in developing an algorithm to solve a particular
problem. The problem we pick is known as the Towers of Hanoi problem.Stacks, Queues, Recursion 6.25
() TOWER(N = 1, BEG, END, AUX)
(2) TOWER(1, BEG, AUX, END) or BEG — END
3) TOWER(N - |, AUX, BEG, END)
Observe that each of these three subproblems may be solved directly or is essentially the same as
the original problem using fewer disks. Accordingly, this reduction process does yield a recursive
solution to the Tawers of Hanoi problem.
Figure 6.17 contains a schematic diagram of the above recursive solution for
TOWER(, A, B,C)
TOWER(1, A, C,B)....A +B
oo AG... AG
TOWERU,B, A.C)... BC
me AoB... coe AB
TOWER(,€, B, A)... CA
Nocece C58... C48
TOWER(1, AC, 8)... A+B
TOWER(A, A, B, C) - see -- AC
TOWER(1, 8, A.C)...8 3 C
a B.C, A)
aT
TOWER(, C, B.A)... CA
BALBOA
TOWERG, B, x SS Bac
TOWER(1, A, C,8)...A 9B
a
Nec RAO Ae
—
TOWER(1, B, A, C)...B > G
Hig. 6.47 Recursive Solution to Towers of Hanoi Problem for n = &
Observe that the recursive solution for n = 4 disks consists of the following 15 moves:
A+B AC B2C A+B CA CB AGB AGC
BOC B2A C+A BC ASB ABC BSC
In general, this recursive solution requires fln) = 2" - 1 moves for n disks.
We summarize our investigation with the following formally written procedure.Stacks, Queues, Recursion 6.27
function subprogram. (This is no loss in generality, since function subprograms can easily be
written as subroutine subprograms.) We also assume that a recursive call to P comes only from the
procedure P. (The treatment of indirect recursion lies beyond the scope of this text.)
The translation of the recursive procedure P into a nonrecursive procedure works as follows.
First of all, one defines:
()_ A stack STPAR for each parameter PAR
(2)_ A stack STVAR for each local variable VAR
(3) A local variable ADD and a stack STADD to hold retum addresses
Each time there is a recursive call to P, the current values of the parameters and local variables are
pushed onto the corresponding stacks for future processing. and cach time there is a recursive
return to P, the values of parameters and local variables for the current execution of P are restored
from the stacks. The handling of the return addresses is more complicated; it is done as follows.
Suppose the procedure P contains a recursive Call P in Step K. Then there are two return
addresses associated with the execution of this Step K:
() There is the current retum address of the procedure P, which will be used when the current
level of execution of P is finished executing.
(2) There is the new return address K + 1, which is the address of the step following the Call P
and which will be used to return to the current level of execution of procedure P.
Some texts push the first of these two addresses, the current return address, onto the retum address
stack STADD, whereas some texts push the second address, the new return address K + 1, onto
STADD. We will choose the latter method, since the translation of P into a nonrecursive procedure
will then be simpler. This also means, in particular, that an empty stack STADD will indicate a
return to the main program that initially called the recursive procedure P. (The alternative translation
which pushes the current return address onto the stack is discussed in Solved Problem 6.21.)
The algorithm which translates the recursive procedure P into a nonrecursive procedure follows.
It consists of three parts: (1) preparation, (2) translating each recursive Call P in procedure P and
(3) translating cach Return in procedure P.
(1) Preparation.
(a) Define a stack STPAR for each parameter PAR, a stack STVAR for each local v:
VAR, and a local variable ADD and a stack STADD to hold return addresses.
(b) Set TOP := NULL.
(2) Translation of “Step K. Call P-”
(a) Push the current values of the parameters and local variables onto the appropriate stacks,
and push the new return address [Step] K + | onto STADD.
(b) Reset the parameters using the new argument values.
(c) Go to Step I. [The beginning of the procedure P.]
(3) Translation of “Step J. Return.”
(a) If STADD is empty, then: Return. [Control is returned to the main program.]
bleStacks, Queues, Recursion 6.23
Suppose three pegs, labeled A, B and C, are given, and suppose on peg A there are placed a
finite number n of disks with decreasing size. This is pictured in Fig. 6.14 for the ease # = 6. The
object of the game is to move the disks from peg A to peg C using peg B as an auxiliary. The rules
of the game are as follows:
(a) Only one disk may be moved at a time. Specifically, only the top disk on any peg may be
moved to any other peg.
{b) Atno time can a larger disk be placed on a smaller disk.
A 8 c
Fig. 6.44 Initial Setup of Towers of Hanoi with n = 6
Sometimes we will write X — Y to denote the instruction “Move top disk from peg X to peg Y."
where X and ¥ may be any of the three pegs.
The solution to the Towers of Hanoi problem for # = 3 appears in Fig. 6.15, Observe that it
consists of the following seven move:
n= 3: Move top disk from peg A to peg C.
Move top disk from peg A to peg B.
Move top disk from peg C to peg B.
Move top disk from peg A to peg C.
Move top disk from peg B to peg A.
Move top disk from peg B to peg C.
Move top disk from peg A to peg C.
(a) Inital (Ase @)A>B @)C>B
A BC A BG A 8 ¢ A Bc
(A> (BA (6)B>C (ASC
Fig. 6.156.24 Data Structures
In other words,
n=3 ASC, ASB, C3B, ASC, BOA, BoC, ASC
For completeness, we also give the solution to the Towers of Hanoi problem for m = | and m= 2:
n=l: ASC
AB, AOC, BoC
Note that n= 1 uses only one move and that n = 2 uses three moves.
Rather than finding a separate solution for each , we use the technique of recursion to develop
a general solution. First we observe that the solution to the Towers of Hanoi problem for n > 1
disks may be reduced to the following subproblems:
(1) Move the top 1 ~ | disks from peg A to peg B.
(2) Move the top disk from peg A to peg C: A > C.
(3) Move the top 2 ~ | disks from peg B to peg C.
This reduction is illustrated in Fig. 6.16 for = 6. That is, first we move the top five disks from
peg A to peg B, then we move the large disk from peg A to peg C, and then we move the top five
disks from peg B to peg C.
A B Cc A B c
i: c
oo
1 i 1
{a) initiat: n= 6 (b) Move top five disks from peg A to peg B
A 8 c A 8 ¢
(c) Move top disk from peg Ato peg (d) Move top five disks from peg B topeg G
Fig. 6.16
Let us now introduce the general notation
TOWER(N, BEG, AUX, END)
to denote procedure which moves the top n disks from the initial peg BEG to the final peg END
using the peg AUX as an auxiliary. When n = 1, we have the fallowing obvious solution:
TOWER(|, BEG. AUX, END) consists of the single instruction BEG — END.
Furthermore, as discussed above, when n > 1, the solution may be reduced to the solution of the
following three subproblems:6.40 Data Structures
The procedures which insert and delete elements in deques and the variations on those procedures
are given as supplementary problems. As with queties, a complication may arise (a) when there is
overflow, that is, when an element is to be inserted into a deque which is already full, or (b) when
there is underflow, that is, when an element is to be deleted from a deque which is empty. The
procedures must consider these possibilities.
6.13 PRIORITY QUEUES
A priority queue is a collection of elements such that each element has been assigned a priority
and such that the order in which elements are deleted and processed comes from the following
rules:
(1) An element of higher priority is processed before any element of lower priority.
(2) Two elements with the same priority are processed according to the order in whieh they
were added to the queue.
A prototype of a priority queue is a timesharing system: programs of high priority are processed
first, and programs with the same priority form a standard queue.
There are various ways of maintaining a priority queue in memory. We discuss two of them
here: one uses a one-way list, and the other uses multiple queues. The ease or difficulty in adding
elements to or deleting them from a priority queue clearly depends on the representation that one
chooses.
One-Way List Representation of a Priority Queue
One way to maintain a priority queue in memory is by means of a one-way list, as follows:
(a) Each node in the list will contain three items of information: an information field INFO, a
priority number PRN and a link number LINK.
(b) A node X precedes a node Y in the list (1) when X has higher priority than Y or (2) when
both have the same priority but X was added to the fist before Y. This means that the order
in the one-way list corresponds to the order of the priority queue.
Priority number
priority.
s will operate in the usual way: the lower the priori
number, the higher the
Example 6.13
Figure 6.27 shows a schematic diagram of a priority queue with 7 elements. The
diagram does not tell us whether BBB was added to the list before or after DDD. On |
the other hand, the diagram does tell us that BBB was inserted before CCC, because :
BBB and CCC have the same priority number and BBB appears before CCC in the list. 1
Figure 6.28 shows the way the priority queue may appear in memory using linear
arrays INFO, PRN and LINK. (See Sec. 5.2.)6.46 Data Structures
8, B Bs By Bs Be
(a)
8, B. Bs Bs Be
(b)
Fig. 6.31
6.6 A Programming language provides two functions ALLOCATE (X) and FREE(X) for the
maintenance of linked list structures. ALLOCATE(X) allots a node with address X for use
in the linked list structure and FREE(X) frees the node with address X used in the application
to the AVAIL list. Assuming the AVAIL list to be maintained as a linked stack, write
procedures to implement the functions ALLOCATE and FREE.
With the AVAIL list maintained as a linked stack, the procedure ALLOCATE(X) performs a
pop operation on the linked stack to release the top node whose address is X. Also, the
procedure FREE(X) performs a push operation on the linked stack, inserting the node that
has been deleted from the application and whose address is X, to the top of the stack.
Procedure ALLOCATE(X)
1. If AVAIL = NULL then NO_MORE_NODES
2, X = AVAIL [Allot top node of AVAIL to X]
3. AVAIL = LINK(AVAIL) [Reset AVAIL to point to the next node}
4, Exit
Procedure FREE(X)
1, LINK(X) = AVAIL
2. AVAIL = X
3, Exit
Polish Notation
6.7 Translate, by inspection and hand, each infix expression into its equivalent postfix expression:
(a) (A -B) « (DIE) (b) (A+B TDME-F)+G
() A * (B + DYE-F + (G+ HR)
Using the order in which the operators are executed, translate each operator from infix to
postfix notation, (We use brackets [ ] to denote a partial translation.)
(a) (A - B)(D/E) = [AB-]«[DE/] = AB - DE/+
(b) (A+ BT DME - F) + G= (A+ [BDT)/EF -] + G = [ABDT+/(EF-] + G
= [ABDT +EF = /] + G = ABDT+EF/G +
(©) As(B + D) /E - Fe(G + H/K) = As[BD +J/E - Fe(G + [HK/])
= [ABD + *VE - Fe[GHK/ +]6.4 Oata Structures
||
a 8 a
[a] A A A A
@ io) © @ ©) ©
Fig. 6.4
Similarly, after completing the processing of C, we remove folder B ftom the stack, leaving the
stack as pictured in Fig, 6.4(c), and continue to process B. Finally, after completing the processing
of B, we remove the last folder, A, from the stack, leaving the empty stack pictured in Fig, 6.4(0,
and continue the processing of our original project A.
Observe that, at each stage of the abave processing, the stack automatically maintains the arder
that is required to complete the processing. An important example of such a processing in computer
science is where A is a main program and B, C and D are subprograms called in the order given.
6.3 ARRAY REPRESENTATION OF STACKS
Stacks may be represented in the computer in various ways, usually by means of a one-way list or
a linear array. Unless otherwise stated or implied, each of our stacks will be maintained by a linear
array STACK; a pointer variable TOP, which contains the location of the top element of the stack:
and a variable MAXSTK which gives the maximum number of elements that can be held by the
stack. The condition TOP = 0 or TOP = NULL will indicate that the stack is empty.
Figure 6.5 pictures such an array representation of a stack. (For notational convenience, the
array is drawn horizontally rather than vertically.) Since TOP = 3, the stack has three elements,
XXX, YYY and ZZZ; and since MAXSTK = 8 there is room for 5 more items in the stack.
‘STACK
mT =y 1
TOP | 3 __J MAXSTK
Fig. 6.5
The operation of adding (pushing) an item onto a stack and the operation of removing (popping)
an item from a stack may be implemented, respectively, by the following procedures, called PUSH
and POP. In executing the procedure PUSH, one must first test whether there is room in the stack
for the new item; if not, then we have the condition known as overflow. Analogously, in executing
the procedure POP, one must first test whether there is an element in the stack to be deleted; if not,
then we have the condition known as underflow.Stacks, Queues, Recursion 6.19
A recursive procedure with these two properties is said to be well-defined.
Similarly, a function is said to be recursively defined if the function definition refers to itself.
Again, in order for the definition not to be circular, it must have the following two properties:
(There must be certain arguments, called base valves, for which the function does not refer
to itself.
2) Each time the function does refer to itself, the argument of the function must be closer to a
base value
A recursive function with these two properties is also said to be well-defined.
The following examples should help clarify these ideas.
Factorial Function
The product of the positive integers from 1 ton, inclusive, is called “n factorial” and is usually
denoted by nt:
2-3... u= 2 1)
It is also convenient to define 0! = 1, so that the function is defined for all nonnegative integers.
Thus we have
Ol=1 Ist 2te4-2
"
nm
Ba1-2-3=6 4=1-2-3-4=24
Stel 4 1-2:354+5-6=720
and so on, Observe that
S!=S-4t=5-24=120 and 6! =6-S!=6- 120=720
This is tue for every positive imeger n; that is,
Ce
Accordingly, the factorial function may also be defined as follows:
Definition 6.1: (Factorial Function)
(a) In = 0, then n! = 1.
(b) f'n > 0, then al=n- (nD!
Observe that this definition of x! is recursive, since it refers to itself when it uses (2 — 1)!
However, (a) the value of mt! is explicitly given when a =0 (thus O is the base value); and (b) the
value of a! for arbitrary n is defined in terms of a smaller value of m which is closer to the base
value 0. Accordingly. the definition is not circular, or in other words, the procedure is well-
defined.
Example 6.9
Let us calculate 4! using the recursive definition. This calculation requires the
following nine steps:6.32 Data Structures
Observe that the output consists of the following seven moves:
ASC, ASB. C3B, ASC BOA, BoC. ABC
This agrees with the solution in Fig. 6.15.
Summary
The Towers of Hanoi problem illustrates the power of recursion in the solution of various algorithmic
problems. This section has shown how to implement recursion by means of stacks when using a
programming language—notably FORTRAN or COBOL—which does not allow recursive programs,
In fact, even when using 2 programming langus upport recursion,
the programmer may want to use the nonrecursive solution, since it may be much less expensive
than using the recursive solution.
6.10 QUEUES
A queue is a linear list of elements in which deletions can take place only at one end, called the
front, and insertions can take place only at the other end, called the rear. The terms “front” and
“rear” are used in describing a linear list‘only when it is implemented as a queue.
Queues are also called first-in first-out (FIFO) lists, since the first element in a queue will be the
first element out of the queue. In other words, the order in which elerhents enter a queue is the
order in which they leave. This contrasts with stacks, which are I in first-out (LIFQ) lists.
Queues abound in everyday life. The automobiles waiting to pass through an intersection, form a
queue, in which the first car in line is the first car through; the people waiting in line at a bank
form a queue, where the first person in line is the first person to be waited on; and so on. An
important example of a qucue in computer science occurs in a timesharing system, in which
programs with the same priority form a queue while waiting to be executed. (Another structure,
called a priority queue, is discussed in Sec. 6.13.)
Example. 6.10
Figure 6.19(a) is a schematic diagram of a queue with 4 elements: where AAA is the
front element and ODD is the rear element. Observe that the front and rear elements
of the queue are also, respectively, the first and last elements of the list. Suppose an
element is deleted from the queue. Then it must be AAA. This yields the queue in Fig.
6.19(b), where BBB is now the front element. Next, suppose EEE is added to the
queue and then FFF is added to the queue. Then they must be added at the rear of
the queue, as pictured in Fig. 6.19(c). Note that FFF is now the rear element, Now
suppose another element is deleted from the queue; then it must be BBB, to yield the
queue in Fig, 6,19(d), And so on. Observe that in such a data structure, EEE will be
deleted before FFF because it has been placed in the queue before FFF. However, EEE
will have to wait until CCC and DDD are deleted.Dota Structures
‘Stack of Stack of Stack of
dishes Pennies. folded towels
Fig. 6.1
Bus
Stop
Fig. 6.2 Queue Waiting for a Bus
6.2 STACKS
A stack is a list of elements in which an element may be inserted or deleted only at one end, called
the top of the stack. This means, in particular, that elemenis are removed from a stack in the
reverse order of that in which they were inserted into the stack.
Special terminology is used for two basic operations associated with stacks:
(a) “Push” is the term used to insert an element into a stack.
(b) “Pop” is the term used to delete an element from a stack.
‘We emphasize that these terms are used only with stacks, not with other data structures.
Example 6.1
Suppose the following 6 elements are pushed, in order, onto an empty stack:
| ‘AAA, BBB, CCC, DDD, EEE, FFF
Figure 6.3 shows three ways of picturing such a stack. For notational convenience, we
will frequently designate the stack by writing:
STACK: AAA, BBB, CCC, DDD, EEE, FFF
The implication is that the right-most element is the top element. We emphasize that,
regardless of the way a stack is described, its underlying property is that insertions
and deletions can occur only at the top of the stack, This means EEE cannot be
deleted before FFF is deleted, DDD cannot be deleted before EEE and FFF are deleted,
and so on, Consequently, the elements may be popped from the stack only in the
reverse order of that in which they were pushed onto the stack,6.44 Data Structures
| SOLVED PROBLEMS | PROBLEMS
STACKS
6.1 Consider the following stack of characters, where STACK is allocated N = 8 memory cells:
STACK: A, C,D,F, K, __.
(For notational convenience, we use “___” to denote an empty memory cell.) Deseribe the
stack as the following operations take place:
(a) POP(STACK, ITEM) (e) POP(STACK. ITEM)
(b) POP(STACK, ITEM) (ff) PUSH(STACK, R)
(c) PUSH(STACK, L) (g) PUSH(STACK, S)
(d) PUSH(STACK, P) (h) POP(STACK, ITEM)
‘The POP procedure always deletes the top element from the stack, and the PUSH procedure
always adds the new element to the top of the stack. Accordingly:
(a)
(by
©
(ay
©
©
(g)
(hy
6.2 Consider the data in Problem 6.1. (a) When will overflow occur? (b) When will C be
deleted before D?
(a) Since STACK has been allocated N = 8 memory cells, overflow will occur when STACK
contains & elements and there is a PUSH operation to add another clement to STACK,
(b) Since STACK is implemented as a stack, C will never be deleted before D.
6.3. Consider the following stack, where STACK is allocated N = 6 memory cells: —_
STACK: AAA, DDD, EEE, FFF, GGG.
Describe the stack as the following operations take place: (a) PUSH(STACK, KKK). (b)
POP(STACK, ITEM), (c) PUSH(STACK, LLL), (d) PUSH(STACK, SSS), (¢) POP(STACK,
ITEM) and (f) PUSH(STACK, TTT).
(a) KKK is added to the top of STACK. yielding
STACK: AAA, DDD, EEE, FFF, GGG, KKKStacks, Queues, Recursion 6.45
64
65
(b) The top element is removed from STACK, yielding
STACK: AAA, DDD, EEE, FFF, GGG,
(©) LLL is added to the top of STACK, yielding
STACK: AAA, DDD, EEE, FFF, GGG, LLL
(4) Overflow occurs, since STACK is full and another element SSS is to be added to
STACK.
No further operations can take place until the overflow is resolved—by adding additional
space for STACK, for example.
Suppose STACK is allocated N = 6 memory cells and initially STACK is empty, or, in
other words, TOP = 0). Find the output of the following module:
1. Set AAA ‘= 2 and BBB := 5.
2. Call PUSH(STACK, AAA).
Call PUSH(STACK, 4).
Call PUSH(STACK, BBB + 2)
Call PUSH(STACK, 9).
Call PUSH(STACK, AAA + BBB).
3. Repeat while TOP 4 0:
Call POP(STACK, ITEM).
Write: ITEM.
[End of loop.]
4. Return,
Step 1. Sets AAA = 2 and BBB = 5.
Step 2, Pushes AAA = 2, 4, BBB + 2 = 7, 9 and AAA + BBB =7 onto STACK, yielding
STACK: 2, 4, 7,9, 7, _
Step 3. Pops and prints the elements of STACK until STACK is empty. Since the top
clement is always popped, the output consists of the following sequence:
7,9,7,4,2
Observe that this is the reverse of the order in which the elements were added to STACK.
Suppose a given space S of N contiguous memory’ cells is allocated to K = 6 stacks.
Describe ways that the stacks may be maintained in'S.
Suppose no prior data indicate that any one stack will grow more rapidly than any of the
other stacks. Then one may reserve N/K cells for each stack, as in Fig. 6.31(a), where B,,
B,, ..., By denote, respectively, the bottoms of the stacks. Alternatively, one can partition the
stacks into pairs and reserve 2N/K cells for each pair of stacks, as in Fig. 6.31(b). The
second method may decrease the number of times overflow will occur.6.30 Data Structures
(c) (Level 3) The Step 2 recursive call [TOWER(N - 1, BEG, END, AUX)] assigns the
following values to the parameters:
N:=N-1=1, BEG:=BEG=A, AUX := END =B, END := AUX=C
Step |, Now N = 1. The operation BEG — END implements the move
AoC
‘Then control is transferred to Step 5. [For the Return,]
Step 5. The stacks are not empty, so the top values on the stacks are removed, leaving Fig.
6.18(c), and are assigned as follows:
N:=2, BEG:=A, AUX:=C, END:=B, ADD
Control is transferred to the preceding Level 2 at Step ADD.
(@) (Level 2) [Reactivated at Step ADD = 3.]
Step 3. The operation BEG — END implements the move
A+B
Step 4, This is a recursive call. Hence the current values of the variables and the new
return address (Step 5) are pushed onto the stacks as pictured in Fig. 6.18(d).
(e) (Level 3) The Step 4 recursive call [TOWER(N - 1, AUX, BEG, END)] assigns the
following values to the parameters:
N:=N-1=1, BEG:=AUX=C, AUX :=BEG=A,
END := END = B
Step 1. Now N = 1. The operation BEG > END implements the move
CoB
‘Then control is transferred to Step 5. [For the Return.]
Step 5. The stacks are not empty; hence the top values on the stacks are removed, leaving
6.18(¢), and they are assigned as follows:
N BEG =A, AUX:=C, END:=B, ADD
Control is transferred to the preceding Level 2 at Step ADD.
() (Level 2) (Reactivation at Step ADD = 5.]
Step 5. The stacks are not empty; hence the top values on the stacks are removed, leaving
6.18(, and they are assigned as follows:
No=3, BEG:=A, AUX:=B, END:=C, ADD:=3
Control is transferred to the preceding Level | at Step ADD.
(g) (Level 1) [Reactivation at Step ADD = 3.]
Step 3. The operation BEG + END implements the move
ASC
Step 4. This is a recursive call. Hence the current values of the variables and the new
return address (Step 5) are pushed onto the stacks as pictured in Fig. 6.18(g).Data Structures
4, If (FRONT = NULL) then FRONT = REAR = NEW
[If Q is empty then ITEM is the first element in the queue Q]
else set LINK[REAR] := NEW and REAR = NEW,
[REAR points to the new node appended to
the end of the list]
5. Exit,
Procedure 6.16: LINKQ_DELETE (INFO, LINK, FRONT, REAR, AVAIL, ITEM)
This procedure deletes the front element of the linked queue and stores it in
ITEM
1, [Linked queue empty’] if (FRONT = NULL) then Write: UNDERFLOW
and Exit
2, Set TEMP = FRONT [If linked queue is nonempty, remember FRONT in
a temporary variable TEMP]
3, ITEM = INFO (TEMP)
4, FRONT = LINK (TEMP) [Reset FRONT to point to the next element in
the queue]
5, LINK(TEMP) =AVAIL and AVAIL=TEMP [retum the deleted node
TEMP to the AVAIL list]
6, Exit,
Example 6.12
For the linked queue shown in Fig. 6.22, the snapshots of the queue structure after
the execution of the following operations are shown in Fig. 6.25.
(i) Delete (ii) Delete (iii) Insert FFF
Original linked queue:
(i) Delete
AAA aB8 coc opp
Let eee)
Front Rear
(@)
aK | BBB cece ppp | «
pA!
1 i
Front Front Roar59
5.10
5.11
Linked Lists 7
Write a program which reads the social security number SSS of an employee and prints the
employee's record. Test the program using (a) 165-64-3351, (b) 136-46-6262 and (c) 177-
44-5555.
Write a program which reads an integer K and prints the name of each male employee when
K = | or of each female employee when K = 2. Test the program using (a) K = 2, (b) K =5
and (c) K = 1.
Write a program which reads the name NNN of an employee and deletes the employee's
record from the structure. Test the program using (a) Davis, (b) Jones and (c) Rubin.
Write a program which reads the record of a new employee and inserts the record into the
file. Test the program using (a) Fletcher, 168-52-3388, Female, 21 000; and (b) Nelson, 175-
32.2468, Male, 19 000.
Remark: Remember to update the header record whenever there is an insertion or a deletion.The terminology sometimes used for Step 5 is that ® will “sin|
Stacks, Queues, Recursion [6.3
(a) Repeatedly pop from STACK and add to P cach operator (on
the tap of STACK) which has the same precedence as or higher
precedence than ®.
(b) Add @ to STACK.
{End of If structure.}
6. Ifa right parenthesis is encountered, then:
(a) Repeatedly pop from STACK ‘and add to P each operator (on
the top of STACK) until left parenthesis is encountered,
(b) Remove the left parenthesis. [Do not add the left parenthesis to
Py
[End of If structure.]
[End of Step-2 Joop.]
7. Exit.
* to its own level.
Example 6.7
Consider the following arithmetic infix expression Q:
Q: A+(B+C-(D/ETF)*G)*H
‘We simulate Algorithm 6.6 to transform Q into its equivalent postfix expression P.
First we push “(“ onto STACK, and then we add “)” to the end of Q to obtain:
A + ( B+ € - ( Df —E T FY ©
@) @ @ ® &) (© () ) @) (0) (a) (12) (13) (14) (15)
© ) + H )
(46) (17) (18) (19) (20)
The elements of Q have now been labeled from left to right for easy reference. Figure
6.12 shows the status of STACK and of the string P as each element of Q is scanned.
‘Observe that
(2) Each operand is simply added to P and does not change STACK.
(2) The subtraction operator (-) in row 7 sends » from STACK to P before it (-) is
pushed onto STACK.
(3) The right parenthesis in row 14 sends 7 and then / from STACK to P, and then
removes the left parenthesis from the top of STACK.
(4) The right parenthesis in row 20 sends « and then + from STACK to P, and then
removes the left parenthesis from the top of STACK.
‘After Step 20 is executed, the STACK is empty and
PA BC+ DEFT SG *-H* +
which is the required postfix equivalent of Q.Stacks, Queues, Recursion _ 63
1 [aaa
2 | BBB
3 | cee
oP 4 [pp
L TOP 5 | cee
EEE 7
DoD s| |
coc 9
BBB :
“AAA Ne
N
(a) (b)
AA | 888 | CCC | DDD | ECE | FFF oe
+ 2 8 «@ 8 6 7 @ 8 Not N
Fig. 6.3 Diagrams of Stacks
Consider again the AVAIL list of available nodes discussed in Chapter 5. Recall that free nodes
were removed only from the beginning of the AVAIL list, and that new available nodes were
inserted only at the beginning of the AVAIL list. In other words, the AVAIL list was implemented
as a stack. This implementation of the AVAIL list as a stack is only a matter of convenience rather
than an inherent part of the structure. In the following subsection we discuss an important situation
where the stack is an essential tool of the processing algorithm itself.
Postponed Decisions
Stacks are frequently used to indicate the order of the processing of data when certain steps of the
processing must be postponed until other conditions are fulfilled. This is illustrated as follows.
Suppose that while processing some project A we are required to move on to project B, whose
completion is required in order to complete project A. Then we place the folder containing the data
of A onto a stack, as pictured in Fig. 6.4(a), and begin to process B. However, suppose that while
processing B we are led to project C, for the same reason. Then we place B on the stack above A,
as pictured in Fig. 6.4(b), and begin to process C. Furthermore, suppose that while processing C
we are likewise led to project D. Then we place C on the stack above B, as pictured in Fig. 6.4(c),
and begin to process D.
On the other hand, suppose we are able to complete the processing of project D. Then the only
Project we may continue to process is project C, which is on top of the stack. Hence we remove
folder C from the stack, leaving the stack as pictured in Fig. 6.4(d), and continue 10 process C.6.18 Data Structures
Complexity of the Quicksort Algorithm
‘The running time of a sorting algorithm is usually measured by the number fin) of comparisons
required to sort # elements. The quicksort algorithm, which has many variations, has been studied
extensively. Generally speaking, the algorithm has a worst-case running time of order n°/2, but an
average-case running time of order m log 2. ‘The reason for this is indicated below.
The worst case occurs when the list is already sorted. Then the first element will require
comparisons to recognize that it remains in the first position. Furthermore, the first sublist will be
empty, but the second sublist will have — 1 elements. Accordingly, the second element will
require n— | comparisons to recognize that it remains in the second position, And so on. Conse-
quently, there will be a total of
ne) 2 om = 00)
2
comparisons, Observe that this is equal to the complexity of the bubble sort algorithm (Sec. 4.6).
The complexity fin) = Or log n) of the average case comes from the fact that, on the average,
each reduction step of the algorithm produces two sublists. Accordingly:
fn
ne (nal tre Ze
(2) Reducing the initial list places 1 element and produces two sublis
(2) Reducing the two sublists places 2 elements and produces four sublists.
(3) Redueing the four sublists places 4 elements and produces eight subli
(4) Reducing the eight sublists places 8 elements and produces sixteen sublists.
And so on. Observe that the reduction step in the kth level finds the location of 2! elements;
hence there will be approximately log, n levels of reductions steps. Furthermore, cach level uses at
most 1 comparisons, sof) = O(n log n). In fact, mathematical analysis and empirical evidence
have both shown that
fin) = 1.4 Tn log nl
is the expected number of comparisons for the quicksort algorithm
6.7 RECURSION
Recursion is an important concept in computer science. Many algorithms can be best described in
terms of recursion. This section introduces this powerful tool, and See, 6.9 will show how recursion
may be implemented by means of stacks.
Suppose P is a procedure containing cither a Call statement to itself or a Call statement to a
second procedure that may eventually result in a Call statement back to the original procedure P.
Then P is called a recursive procedure. So that the program will not continue to run indefinitely, a
recursive procedure must have the following two properties:
(1) There must be certain criteria, called base criteria, for which the procedure does not call
itself.
(2) Bach time the procedure does call itself (directly or indirectly), it must be closer to the base
criteria.6.20 Dato Structures
(1) aba 4-3!
(2) 3!
@) 22s
(4) ei. o!
(5) ob=1
(6) Uede dad
q 2a2ele2
(8) 313-256
(9) 46=4-6=26
That is:
Step 1. This defines 4! in terms of 3!, so we must postpone evaluating 4! until we
evaluate 3! This postponement is indicated by indenting the next step.
Step 2. Here 3! is defined in terms of 2!, so we must postpone evaluating 3!
evaluate 2!
Step 3. This defines 2! in terms of 1!
Step 4. This defines 1! in
Step 5. This step can explicitly evaluate O!, since 0 is the base value of the recursive
definition,
Steps 6 to 9. We backtrack, using 0! to find 1!, using 1! to find 2!, using 2! to find
31, and finally using 3! to find 4! This backtracking is indicated by the
“reverse” indention.
Observe that we backtrack in the reverse arder af the original postponed evaluations.
Recall that this type of postponed processing lends itself ta the use of stacks. (See
Sec. 6.2.)
til we
The following are two procedures that each calculate n factorial.
Procedure 6.94: FACTORIAL(FACT, N)
‘This procedure calculates N! and returns the ¥:
1. If N = 0, then: Set FACT := L, and Return.
2. Set FACT := I. [Initializes FACT for loop.]
3. Repeat for K = | to N.
Set FACT := K*FACT.
{End of loop.}
4, Retum,
jue in the variable FACT.
Procedure 6.9B: FACTORIAL(FACT, N)
This procedure calculates N! and returns the value in the variable FACT.
1. If N = 0, then: Set FACT , and Return.
2. Call FACTORIAL(FACT, N — 1).
3. Set FACT := N*FACT.
4. Retum.Stacks, Queues, Recursion 6.17
(b) If LOC = RIGHT, then: Return.
(c) If A{LOC] > A[RIGHT], then:
(® [Interchange A[LOC) and A[RIGHT].]
TEMP := A[LOC). A[LOC]
A[RIGHT] := TEMP.
) Set LOC := RIGHT.
(iii) Go to Step 3.
[End of If structure.
3. [Scan from left to right.)
(a) Repeat while A{LEFT] ¢ A[LOC) and LEFT # LOC:
LEFT := LEFT + 1.
{End of loop.]
(b) If LOC = LEFT, then: Retum.
(e) If A[LEFT] > A[LOC}, then
(@) [Interchange A[LEFT] and A[LOC].]
(i) Set LOC
(ili) Go to Step 2.
[End of If structure.
Algorithm 6.8: (Quicksort) This algorithm sorts an array A with N elements,
1. [Initialize.] TOP := NULL.
2, [Push boundary values of A onto stacks when A has 2 or more elements.]
If N > 1, then: TOP := TOP + 1, LOWER{1] := 1, UPPER[I] = N.
3. Repeat Steps 4 to 7 while TOP # NULL.
4 {Pop sublist from stacks.]
Set BEG := LOWER{TOP}, END := UPPER[TOP],
‘TOP := TOP - 1.
5, Call QUICK(A, N, BEG, END, LOC), [Procedure 6.5.]
6 {Push left sublist onto stacks when it has 2 or more elements.]
Wf BEG < LOC - 1, then:
TOP := TOP + 1, LOWER[TOP] := BEG,
UPPER[TOP] = LOC - 1.
[End of If structure.]
7. {Push right sublist onto stacks when it has 2 or more elements.]
LOC + | < END, then:
‘TOP := TOP + 1, LOWER(TOP]
UPPER[TOP] := END.
[End of If structure,]
[End of Step 3 loop.]
8. Exit.
LOC + 1,6.26 Data Structures
Procedure 6.11: TOWER(N, BEG, AUX, END)
This procedure gives a recursive Solution to the Towers of Hanoi problem for
N disks.
1. If N= 1, then:
(a) Write: BEG — END.
(b) Return,
[End of If structure.]
2, [Move N ~ 1 disks from peg BEG to peg AUX.]
Call TOWER(N — 1, BEG, END, AUX).
3. Write: BEG — END.
4, [Move N — | disks from peg AUX to peg END.)
Call TOWER(N ~ 1, AUX, BEG, END).
5. Rem.
One can view this solution as 2 divide-and-conquer algorithm, since the solution for m disks is
reduced to a solution for n — | disks and a solution for 2 = | disk
6.9 IMPLEMENTATION OF RECURSIVE PROCEDURES BY STACKS
The preceding sections showed how recursion may be a useful tool in developing algorithms for
specific problems. This section shows how stacks may be used to implement recursive procedures.
It is instructive to first discuss subprograms in general.
Recall that a subprogram can contain both parameters and local variables. The parameters are
the variables which receive values from objects in the calling program, called arguments, and
which transmit values back to the calling program. Besides the parameters and local variables, the
subprogram must also keep track of the return address in the calling program, This return address
is essential, since control must be transferred back to its proper place in the calling program. At the
time that the subprogram is finished executing and control is transferred back to the calling
program, the values of the local variables and the return address are no longer needed.
Suppose our subprogram is a recursive program. Then cach level of execution of the subprogram
may contain different values for the parameters and local variables and for the return address.
Furthermore, if the recursive program does call itself, then these current values must be saved,
since they will be used again when the program is reactivated.
Suppose a programmer is using a high-level language which admits recarsion, such as Pascal.
Then the computer handles the bookkeeping that keeps track of all the values of the parameters,
local variables and return addresses. On the other hand, if a programmer is using a high-level
language which does not admit recursion, such as FORTRAN, then the programmer must set up
the necessary bookkeeping by translating the recursive procedure into a nonrecursive one. This
bookkeeping is discussed below
Translation of a Recursive Procedure into a Nonrecursive Procedure
Suppose P is a recursive procedure. We assume that P is a subroutine subprogram rather than axiv Preface
supplementary problems. The solved problems illustrate and amplify the material, and the
supplementary problems furnish a complete review of the material in the chapter.
I wish to thank many friends and colleagues for invaluable suggestions and critical review of the
manuscirpt. I also wish to express my gratitude to the staff of the McGraw-Hill Schaum’s Outline
Series, especially Jeffrey McCartney, for their helpful cooperation. Finally, I join many other
authors in explicitly giving credit to Donald E, Knuth who wrote the first comprehensive treatment
of the subject of data structures, which has certainly influenced the writing of this and many other
texts on the subject.
Seymour Lipschutz6.34 Data Structures
QUEVE
FRONT: 1 z
Reana [AAA | BBB | oc | DOD
1 2 3 4 5 6 7 N
(a)
QUEUE
FRONT:2 T
AeA G ses|ccc|opo| |
1 2 3 4 8 6 F N
(b)
QUEUE
FRONT: 2
GEARS pep | ccc | opp | cee | FFF
1 2 3 4 5 6 7 N
te)
QUEUE
FRONT:3
REAR: ccc] opp] Eee] FFF]
1 2 38 4 &§ 6 FN
(a)
Fig. 6.20 Array Representation of a Queue
Similarly, if FRONT = N and an clement of QUEUE is deleted, we reset FRONT = | instead of
increasing FRONT to N + 1. (Some readers may recognize this as modular arithmetic, discussed in
Sec. 2.2.)
Suppose that our queue contains only one element, i.c., suppose that
FRONT = REAR # NULL
and suppose that the element is deleted. Then we assign
FRONT := NULL. and REAR := NULL
to indicate that the queue is empty.
Example 6.11
Figure 6.21 shows how a queue may be maintained by a circular array QUEUE with
N= 5 memory locations. Observe that the queue always occupies consecutive
locations except when it occupies locations at the beginning and at the end of the
array. If the queue is viewed as a circular array, this means that it still occupies
consecutive locations, Also, as indicated by Fig. 6.21(m), the queve will be empty
only when FRONT = REAR and an element is deleted. For this reason, NULL is assigned
to FRONT and REAR in Fig. 6.21(m).6.12 Data Structures
The elements of P have been labeled from left to right for easy reference. Figure 6.11
shows the contents of STACK as each element of P is scanned. The final number in
STACK, 37, which és assigned to VALUE when the sentinel “)” is scanned, is the value
of PL
Transforming Infix Expressions into Postfix Expressions
Let Q be an arithmetic expression written in infix notation. Besides operands and operators, Q may
also contain left_and right parentheses. We assume that the operators in Q consist only of
exponentiations (7), multiplications (*), divisions (/), additions (+) and subtractions (-), and that
they have the usual three levels of precedence as given above. We also assume that operators on
the same level, including exponentiations, are performed from left to right unless otherwise indicated
by parentheses. (This is not standard, since expressions may contain unary operators and some
languages perform the exponentiations from right to left. However, these assumptions simplify our
algorithm.)
The following algorithm transforms the infix expression Q into its equivalent postfix expression
P. The algorithm uses a stack to temporarily hold operators and left parentheses. The postfix
expression P will be constructed from left to right using the operands from Q and the operators
which are removed from STACK. We begin by pushing a left parenthesis onto STACK and adding
a right parenthesis at the end of Q. The algorithm is completed when STACK is empty.
Algorithm 6.6: POLISH(Q. P)
Suppose Q is an arithmetic expression written in infix notation. This algorithm
finds the equivalent postfix expression P.
1. Push “(" onto STACK, and add “)" to the end of Q.
2. Scan Q from left to right and repeat Steps 3 to 6 for each element of Q
until the STACK is empty:
3. If an operand is encountered, add it to P.
4, Ifa left parenthesis is encountered, push it onto STACK,
5. If an operator ® is encountered, then: ‘Stacks, Queues, Recursion
6.43
‘The computer usually evaluates an arithmetic expression written in infix notation in two steps.
First, it converts the expression to postfix notation, and then it evaluates the postfix expression. In
each step, the stack is the main tool that is used to accomplish the given task. We illustrate these
applications of stacks in reverse order. That is, first we show how stacks are used to evaluate
Postfix expressions, and then we show how stacks are used to transform infix expressions into
postfix expressions.
Evaluation of a Postfix Expression
Suppose P is an arithmetic expression written in postfix notation. The following algorithm, which
uses a STACK to hold operands, evaluates P.
Algorithm 6.5: This algorithm finds the VALUE of an arithmetic expression P written in postfix.
notation,
1. Add a right parenthesis “)” at the end of P. [This acts as a sentinel.)
2. Scan P from left to right and repeat Steps 3 and 4 for each element of P until
the sentinel “)” is encountered.
3. If an operand is encountered, put it on STACK.
4, If an operator @ is encountered, then:
(a) Remove the two top elements of STACK, whére’ A’ isthe! top
element and B is the next-to-top element.
(b) Evaluate B® A.
(e) Place the result of (b) back on STACK,
[End of If structure.]
[End of Step 2 loop.
5, Set VALUE equal to the top clement on STACK.
6. Exit.
‘We note that, when Step 5 is executed, there should be only one number on STACK.
Example 6.6
| Consider the following arithmetic expression P written in postfix notation:
| P56 BH te 1
| (Commas are used to separate the elements of P so that 5, 6, 2 is not interpreted as
| the number 562.) The equivalent infix expression Q follows:
Q: 5+(6+2)-12/4
Note that parentheses are necessary for the infix expression Q but not for the postfix
expression P.
We evaluate P by simulating Algorithm 6.5. First we add a sentinel right
parenthesis at the end of P to obtain
P: 5, 6, 2 + *, 12, Ae i - )
@® @ 8 @ 6) & (8) (M9)+ 6.10 Date Structures
Example®6.5
Suppose we want to evaluate the following parenthesis-free arithmetic expression:
2T345e2T2-12/6
First we evaluate the exponentiations to obtain
8+5%4-12/6
Then we evaluate the multiplication and division to obtain 8 + 20 - 2. Last, we
evaluate the addition and subtraction to obtain the final result, 26. Observe that the
expression is traversed three times, each time corresponding to a level of precedence
of the operations.
Polish Notation
For most common arithmetic operations, the operator symbol is placed between its two operands.
For example,
A+B C-D E+F GH
This is called infix notation, With this notation, we must distinguish between
(A + Bac and A+(BsC)
by using either parentheses or some operator-precedence convention such as the usual precedence
levels discussed above, Accordingly, the order of the operators and operands in an arithmetic
expression does not uniquely determine the order in which the operations are to be performed.
Polish notation, named after the Polish mathematician Jan Lukasiewicz, refers to the notation in
which the operator symbol is placed before its two operands, For example,
+AB -CD *EF /GH
We translate, step by step, the following infix expressions into Polish notation using brackets [ ] to
indicate a partial translation:
(A + B)*C = [+AB]+C = ++ ABC
A+ (BeC)= A+ [*BC) = + A*BC
(A + B)(C = D) = [+ABJ/[-CD] = / + AB - CD
‘The fundamental property of Polish notation is that the order in whieh the operations are 10 be
performed is completely determined by the positions of the operators and operands in the expression.
Accordingly, one never needs parentheses when writing expressions in Polish notation.
Reverse Polish notation refers to the analogous notation in which the operator symbol is placed
after its 1wo operands:
AB+ CD- EF* GH/
Again, one never needs parentheses to determine the order of the operations in any arithmetic
expression written in reverse Polish notation. This notation is frequently called posifix (or suffix)
notation, whereas prefix notation is the term used for Polish notation, discussed in the preceding
‘paragraph.Stacks, Queues, Recursion 6.9
(]) Push BBB (ji) Pop (iii) Pop (iv) Push MMM
Original linked stack:
Top
NS XXX yw | i zzz |x
(a)
(i) Push BBB
Top
eee |} | few | [ae [=
(6)
(ii) Pop
Jop
Top »
a6 P-L 00 T -—-wr [ ]}- —[ 2zz [=
©
Gil) Pop
(iv) Push MMM
Top
MMM >| YY | zzz |x
(e)
Fig. 6.10
6.5 ARITHMETIC EXPRESSIONS; POLISH NOTATION
Let Q be an arithmetic expression involving constants and operations, This section gives an
algorithm which finds the value of Q by using reverse Polish (postfix) notation. We will see that
the stack is an essential tool in this algorithm.
Recall that the binary operations in Q may have different levels of precedence. Specifically, we
assume the following three levels of precedence for the usual five binary operations:
Highest: Exponentiation (1)
Next highest: Multiplication (+) and division ()
Lowest: Addition (+) and subtraction (-)
(Observe that we use the BASIC symbol for exponentiation.) For simplicity, we assume that Q
contains no unary operation (e.g., a leading minus sign). We also assume that in any parenthesis-
free expression, the operations on the same level are performed from left to right. (This is not
standard, since some languages perform exponentiations from right to left.)