Principles of Programming
Principles of Programming
CodeWarrior
TM
Principles of
Programming
Documentation stored on the compact disc may be printed by licensee for personal use.
Except for the foregoing, no part of this documentation may be reproduced or transmitted in
any form by any means, electronic or mechanical, including photocopying, recording, or any
information storage and retrieval system, without permission in writing from Metrowerks Inc.
Metrowerks, the Metrowerks logo and Software at Work are registered trademarks of
Metrowerks Inc. CodeWarrior, PowerPlant, and PowerPlant Constructor are trademarks of
Metrowerks Inc.
All other trademarks or registered trademarks are the property of their respective owners.
Table of Contents
Chapter 1 A Road Map
1.1 Preview....................................................................14
1.2 Introduction to The Principles of Programming........15
A Global View.........................................................15
The Road Ahead.......................................................16
Signs Along the Road...............................................17
1.3 Computers................................................................18
A Low Level View...................................................18
Systems and Their Environments...............................19
History of Programming and the Earth.....................21
1.4 Review Top Ten Things to Remember....................24
1.5 Glossary...................................................................25
1.6 Problems..................................................................27
Chapter 2 An Overview
2.1 Preview....................................................................30
2.2 Problem Solving and the Computer..........................31
Step 1 Problem Definition.......................................32
Step 2 Solution Design............................................33
Step 3 Solution Refinement......................................34
Step 4 Testing Strategy Development.......................35
Step 5 Program Coding and Testing........................36
Step 6 Documentation Completion..........................37
Step 7 Program Maintenance...................................37
Using the Problem Solving Method..........................38
Problems and Plans Dividing and Conquering........38
2.3 Break-Out Diagrams..................................................39
More on Break-Out Diagrams...................................41
2.4 Algorithms and Their Representations.......................45
Modifying Algorithms..............................................47
Alternative Algorithms.............................................52
Equivalence of Algorithms........................................53
Testing......................................................................54
2.5 Programming Languages..........................................56
Communicating Algorithms......................................56
Basic.........................................................................56
Fortran.....................................................................57
Pascal.......................................................................57
Modula-2..................................................................58
C..............................................................................58
iv Table of Contents
Ada..........................................................................59
Other programming languages.................................59
2.6 Life Cycles Stages of Programming.........................60
2.7 Review Top Ten Things to Remember....................63
2.8 Glossary...................................................................65
2.9 Problems..................................................................67
Chapter 3 Algorithms
3.1 Preview....................................................................74
3.2 What Are Algorithms?..............................................75
Algorithm Definition................................................75
General Properties of Algorithms..............................75
Desirable Attributes for Algorithms...........................77
3.3 Different Algorithm Representations.........................78
Verbal Representations.............................................80
Algebraic Representations (formulas and
expressions).....................................................82
Tabular Representations (tables, arrays, and
matrices)..........................................................86
3.4 Data-Flow Diagrams.................................................89
Black Boxes vs. Glass Boxes.......................................89
General Data-Flow Diagrams....................................91
Integer Data-Flow Diagrams.....................................94
Logical Data-Flow Diagrams.....................................98
Data Flow Black Boxes..............................................101
More on Data Flow Components and Diagrams........105
3.5 Flow of Control Diagrams........................................107
Flowcharts................................................................107
Larger Flowcharts Using Subprograms...................110
Flowblocks...............................................................113
Pseudocode..............................................................115
3.6 Review Top Ten Things to Remember....................118
3.7 Glossary...................................................................119
3.8 Problems..................................................................121
Alternative Algorithms.............................................137
4.4 Top-down Algorithm Design....................................140
Job Description Example...........................................144
Change Maker Example............................................145
A Game Example, Fifty.............................................148
4.5 How Data and Algorithms Fit Together....................152
Structured Data.........................................................153
Chili Recipe Example................................................155
Card Trick Example..................................................158
Binary Conversion Example......................................159
Guessing Game Example...........................................160
4.6 Review Top Ten Things to Remember.....................164
4.7 Glossary...................................................................166
4.8 Problems..................................................................167
5.10 Problems..................................................................236
Functions..................................................................345
Modules...................................................................346
7.6 Review Top Ten Things to Remember....................348
7.7 Glossary...................................................................350
7.8 Problems..................................................................351
Swap Sort..........................................................422
Swap Sort Analysis............................................424
Select Sort..........................................................425
Select Sort Analysis............................................427
Insert Sort..........................................................428
9.3 More Complex Sorting..............................................428
Improving Sorts........................................................428
Recursive Sorts.........................................................432
9.4 Searching..................................................................435
Linear Searching.......................................................436
Binary Searching.......................................................437
Pattern Matching......................................................438
9.5 Implementing Abstract Data Types...........................441
Stacks.......................................................................441
Implementing Stacks with Arrays.............................441
Implementing Stacks with Pointers...........................444
Queues.....................................................................445
Implementing Queues of Arrays...............................446
Implementing Queues with Pointers.........................448
Trees.........................................................................449
9.6 Review Top Ten Things to Remember....................451
9.7 Glossary...................................................................453
9.8 Problems..................................................................454
Appendix: Solutions
Chapter 1 Solutions 1-3.......................................................508
Chapter 2 Solutions 1-3.......................................................508
Chapter 3 Solutions 1-7.......................................................510
Chapter 4 Solutions 1-3.......................................................511
Chapter 5 Solutions 1-3.......................................................512
Chapter 6 Solutions 1-3.......................................................514
Chapter 7 Solutions 1-3.......................................................515
Chapter 8 Solutions 1-3.......................................................516
Chapter 9 Solutions 1-3.......................................................517
Index ..........................................................................................519
x Table of Contents
Preface
The purpose behind The Principles of Programming is to provide the
reader/student with a structured method to solve problems using a computer.
Since the Principles book is language-independent (it provides the steps and
tools to solve problems without centering on a specific computer
programming language), a companion book, Programming Practice: Pascal,
is also provided on this CD.
While using this book to learn the principles of programming, you may find
that there are too many examples and that some topics have been over-
explained. You are encouraged to select only the topics and examples that
best suit your needs and work habits.
Chapter Outline 13
Chapter Overview
1.1 Preview....................................................................14
1.2 Introduction to The Principles of Programming............15
A Global View..........................................................15
The Road Ahead.......................................................16
Signs Along the Road................................................17
1.3 Computers.................................................................18
A Low Level View.....................................................18
Systems and Their Environments................................19
History of Programming and the Earth......................21
1.4 Review Top Ten Things to Remember........................24
1.5 Glossary...................................................................25
1.6 Problems...................................................................27
14 Chapter 1 A Road Map
1.1 Preview
This is a text book—it is intended to teach you about computer programming.
Learning is like a journey and, with any journey, it is helpful to know something
about the terrain before setting out, for you can make proper preparations and
know what will be expected of you. This chapter provides you with a road map
of your journey. The coming pages will present a great deal of detailed matter
and it is all too easy to get mired down in this detail and lose sight of how it
fits in with the whole. Here is a very general view that will allow you to gain
a picture of where the details are leading.
This chapter is presented in two major sections, starting with an introduction to
The Principles of Programming which contains the following subsections:
• A Global View describes the layout of the text book’s material in very
general detail. This sub-section also offers an idea of the way in which
Principles of Programming should be read and studied.
• The Road Ahead gives a very brief synopsis of each chapter so that
you can visualize how all the chapters fit together. This provides a
route that will take you from an introduction to computers (the last
section in this chapter) to being able to write large useful programs.
• Road Signs describes the common pattern on which each of the chapters
are based, tells you how to read the road signs, and gives a brief
explanation of some of the visual aids that will be used throughout the
book.
As you can see, the first section of this chapter is organized to go from the very
general to the particular. This is no accident. A major technique presented in
this book is that of starting with an overview and then filling in the details.
This technique is called the “top-down approach” and you will be meeting it
again and again on your journey.
Finally, a section introducing computers is provided. Computers are the
physical machines that execute (or “run”) programs. These machines are
capable of performing a relatively small number of different operations. Such
operations, which can be combined to carry out complex tasks, include:
• Arithmetic operations, such as the addition, subtraction,
multiplication, and division of numbers.
• Comparison operations, such as determining whether one number is
greater than another.
• Input and output operations, such as accepting data from a keyboard or
displaying data on the screen.
It is not necessary to know much about the detailed construction of computers in
order to use, or program, them. At the end of this chapter, we provide only a
brief introduction into the structure of a computer and a computing system. This
section also ends with a brief glance at history. This view, of both computing
Section 1.1 Preview 15
and world history, should put the brief lifetime of computers and computing
into its proper perspective.
A Global View
The goal of this book is to teach you how to program computers. At the
beginning, no previous knowledge of computers is assumed although, these days,
it is almost impossible to grow up without gaining some familiarity with the
vocabulary and concepts of computers. Nevertheless, to make sure that
everybody starts at the same level, we have assumed nothing and describe
everything we need. If you come to a section that you think you already know,
please do not skip it, there may well be an important nugget of information that
is new to you.
Learning to write computer programs is very much like learning any skill—you
must first understand the underlying principles upon which the craft is based
and then practice, practice, practice. For example, you can read all the books
ever published about riding a bicycle but, until you actually get on one and start
pedaling on your own, you will not know how to ride a bicycle. The same
applies to computer programming! Here, we provide the first book, the
Principles of Programming, which treats computer programming in general. A
second book, the Practice of Programming describes the application of the
principles to a particular language—the way in which a computer program is
expressed so that it can be used on a computer.
We can make an analogy with natural language. There are certain principles of
language, such as the distinction between nouns—names of things— and verbs—
names of actions— that apply to all human languages. However, the way in
which these principles are expressed and the detailed rules that apply to
them varies considerably from language to language. For instance, the rules of
French are different from the rules of German and they are both different from
the rules of English. The situation is similar with programming languages;
there are many different languages each with its own set of rules. For this
reason, there is one Principles and several versions of Practice, one for each of
the programming languages we cover.
This book emphasizes the adage, “it’s best to learn through examples.”
Keeping this in mind, each chapter uses many examples to teach the same
point. For this reason, you may find the number of examples overwhelming and
you should feel free to pay attention to only the examples which you feel best
describe the point that is being illustrated.
16 Chapter 1 A Road Map
end of the book (Solutions Appendix). You are encouraged to try your
hand at these before looking at the solutions. In any case, programming
is an intensely practical skill that can only be acquired by practice.
Remember: “Practice makes perfect!”
Apart from following a similar pattern, each chapter uses many signs to
visually illustrate important points and concepts. The most frequently used
visual aids are note (or tip) boxes. An example is provided below.
Note: This is a tip or note box. Inside this box, important information and
tips can be found.
This is a note in In addition to tip boxes, when a paragraph briefly touches upon a subject which
margin which is covered in more detail in another chapter, a reference is provided in the left
directs you to margin.
useful
information.
1.3 Computers
Input Output
Here, we look at computing from the view of a computer interacting with both
the human and the physical environment.
Translators
compilers interpreters
Plotter Disk
Utilities
editors libraries
Precambrian
Mesozoic
Paleozoic
(fish & reptiles) Triassic
Jurassic
dinosaurs
Mesozoic Cretaceous
Cenozoic Cenozoic
mammals Tertiary Pleistocene
Quaternary humans (ice age)
Holocene
22 Chapter 1 A Road Map
Recent history is briefly shown in Figure 1.4. You may wish to add your own
favorite historical events. Notice that the classical levels (the last 2000
years) are a very small part of the history of the earth. An even smaller part
is the history of computing shown on the right-hand side of Figure 1.3.
1960 McCarthy's
Lisp
1980 Wirth's
Pascal
In the classical levels of Figure 1.4, going from AD 1 to 1800, we find a number of
persons who had an influence on computing. For instance...
• Al-Khwarizmi, a ninth century mathematician, studied sets of rules
which are now called algorithms (named after him).
• Blaise Pascal, a French mathematician and philosopher, designed the
first mechanical adding machine in 1642.
• Based on Pascal’s machine, Gottfried Wilhelm von Leibniz, a German
mathematician, created a mechanical calculating machine that could
perform both addition and multiplication in 1694.
• In the more recent period going from 1800 to 2000, we find others who
influenced modern computers. In 1801, Joseph Jacquard, a Frenchman,
developed a loom for weaving cloth with patterns controlled by
punched cards.
• In the 1840s, George Boole discovered that the symbolism of
mathematics could be applied to logic. His algebra forms a basis for
both the hardware (interconnections of components) and also the
software (programs with compound conditions).
Section 1.3 Computers 23
1.5 Glossary
A to D converter: (Analogue to Hardware: The collection of
Digital converter) A physical device physical devices making up a
that takes an analog or continuous computer system.
value (for instance, the intensity of
an electric current) and converts it Input/Output: The devices designed
into a digital (numerical) value. to send external information into the
computer memory and to produce
ALU: Arithmetic Logic Unit, a external information from the
component of the computer Central memory.
Processing Unit that executes
arithmetic and comparison Instruction register: A CPU register
operations. that holds the machine instruction
being executed.
Analog value: A directly measurable
physical value (temperature, current Machine Language: A programming
voltage, pressure, and so on). language that is used directly by a
computer; synonymous with low-level
Bus: A signal transmission cable language.
making it possible to interconnect
various devices. Memory: The component of a
computer used to store information
Compiler: A piece of software used to (data and program instructions).
translate a program written in a
high-level programming language Modem: A device used to connect a
into machine language. computer to other computers through
telephone lines.
CPU: Central Processing Unit, the
heart of the computer that controls Processing unit: CPU.
the behavior of its other components
and performs the operations on the Program register: A CPU register
data. containing the address of the next
machine instruction to be executed
D to A converter: Digital to Analog (also called program counter).
converter, a device to convert digital
(numerical) values to their physical Register: Special purpose computer
equivalent (current voltage, memory cells used to store the pieces
temperature, and so on). of information on which a machine
instruction operates.
Editor: A utility program that helps
a user prepare data or programs for a
later operation.
Utility program: A computer
Execute: Perform the actions program in general support of the
associated to a program.
26 Chapter 1 A Road Map
1.6 Problems
1 Human Environments
Which of the following are considered human environments when it
comes to the interaction between computers and humans.
a. Keyboard
b. Analogy-Digital Converter
c. Scanner
d. Mouse
e. Clock
2 Physical Environments
Which of the following are considered physical environments when it
comes to the interaction between computers and transducers.
a. Display
b. Sensor
c. Digital-Analog Converter
d. Scanner
e. Clock
3 Influential People
Match the following list of names with their contributions to
computing. Note: there is one more contribution than there are
contributors!
4 Memory
List the three functions of the Memory Unit. Besides data, what does
the Memory Unit store? What happens if an item of data is too big for a
single “pigeon-hole” of memory?
6. Think Big
Suppose that entire computers became as small as bugs (roaches or
integrated circuits), and had the ability to move around and
manipulate things (carry, measure, cut, and so on). Write a brief essay
indicating possible uses and potential benefits of such programmable
bugs (PRUGS).
For example, many functions could be performed differently. Lawns
could be maintained, not by mowing, but with an "army" of PRUGS
roaming around randomly, measuring each individual blade of grass
and cutting it off at a precise length.
7. Think Well
Write another brief essay describing the potential negative
consequences of the PRUGS in the previous problem.
8. Do Justice to History
Select some topic in the history of computing (person, machine,
program, era, machine, and so on) and investigate it thoroughly.
Relate this to other similar topics.
Chapter Outline 29
Chapter 2 An Overview
This chapter provides an overview of problem solving with a computer,
showing a brief “bird’s-eye” view of the general ideas, and how they are
related.
Chapter Overview
2.1 Preview....................................................................30
2.2 Problem Solving and the Computer............................31
Step 1 Problem Definition........................................32
Step 2 Solution Design..............................................33
Step 3 Solution Refinement.......................................34
Step 4 Testing Strategy Development.......................35
Step 5 Program Coding and Testing...........................35
Step 6 Documentation Completion............................37
Step 7 Program Maintenance.....................................37
Using the Problem Solving Method............................38
Problems and Plans Dividing and Conquering............38
2.3 Break-Out Diagrams.................................................39
More on Break-Out Diagrams....................................41
2.4 Algorithms and Their Representations......................45
Modifying Algorithms..............................................47
Alternative Algorithms............................................52
Equivalence of Algorithms........................................53
Testing......................................................................54
2.5 Programming Languages............................................56
Communicating Algorithms.......................................56
Basic........................................................................56
Fortran.....................................................................57
Pascal.......................................................................57
Modula-2..................................................................58
C..............................................................................58
Ada..........................................................................59
Other programming languages...................................59
2.6 Life Cycles Stages of Programming...........................60
2.7 Review Top Ten Things to Remember........................63
2.8 Glossary...................................................................65
2.9 Problems...................................................................67
30 Chapter 2 An Overview
2.1 Preview
Using a computer to solve a problem frequently requires programming—the
formulation of a plan for precisely defined actions to be performed by the
computer to obtain the solution to the problem. Such a plan is an algorithm. In
this chapter, we introduce a helpful method for solving a problem with a
computer. We also show ways of breaking up a problem into smaller
subproblems. Of course, in this introductory chapter, we will consider only some
simple problems, such as the computation of part of a weekly payroll.
Algorithms are plans for performing actions. Common examples of algorithms
are:
• Directions for getting somewhere: Directions for Getting to Fred’s Pizza Parlor
1. Take Route 116 until you come to the T-
junction at Route 9.
2. Turn onto Route 9and go about three-
quarters of a mile and it will be on your
left. You can’t miss it!
Recipe for
complete solution Cream
Horms
The box at the top of the chart represents our complete solution, the three boxes
at the next level below represent the components of that solution, and the three
boxes at the lowest level represent the sub-components of the component Finish
The Horns. Similarly, all components can be broken into smaller sub-
components.
34 Chapter 2 An Overview
Here we have used the verb Set to associate the name Gross Pay with a
computed value. We could also have used a more mathematical notation like
the following.
Section 2.2 Problem Solving and the Computer 35
Care should be taken to make the algorithm check the data values for
reasonableness. If any data item is out of range, an error message should be
produced instead of computing a meaningless result. This process of checking
that the input data are acceptable is called data validation.
Note: For all test cases, the expected results must be computed and
specified before proceeding to the next step. Complete test cases can
then be used to check algorithms and programs efficiently.
Notice that the pseudocode Set...to has been replaced by “:=“ and that
multiplication is indicated by an asterisk. Most programming languages use a
notation similar to this one. Names like GrossPay are called variables and
can be thought of as named “information holders” whose contents can be used
and changed by statements in the program. The above Pascal code would only
be a small part of a complete Pascal program that calculates a weekly payroll
Once the algorithms have been coded, the resulting computer program must be
tested using our testing strategy. The program must be run and, for each test case
developed in Step 4, the results produced must match those computed during the
development of the test strategy. If there is a discrepancy, the produced results
must be analyzed in order to discover the source of the error. The error may lie
in one of four places:
• The coding: The error could have been formed when the algorithm was
translated into the programming language.
• The algorithms: The error could have existed in the algorithm and has
never been noticed.
• The designof the program: The program’s design may be flawed and
lead to errors during execution.
• The computation of the expected test results: The results for a test case
may have been calculated wrong.
Once the error has been discovered, the appropriate revision must be made and
the tests rerun. This is repeated until we are sure that our program produces a
correct solution to the problem under all circumstances. This process of coding
and testing is called implementation.
Section 2.2 Problem Solving and the Computer 37
Even in problems that seem simple, such as computing a weekly payroll, there
could be considerable complexity. For example, actions that depend on various
changing conditions, such as income tax rules, can turn computing a weekly
payroll into a complex task.
When faced with complexity, use Step 2, Solution Design, of our seven step
method to develop a systematic way of thinking about such problems. As we
have already mentioned, the best way to go about solving a problem is to break
the problem into smaller subproblems: the “divide and conquer” approach.
But breaking up a problem into smaller subproblems is not always as easy as it
seems. There are many ways to break up anything with some ways being better
than others. In addition, the number of subproblems required for computing are
often so numerous that they create another problem: the complexity of
quantity. Our challenge is to organize this complexity while avoiding
confusion.
To avoid confusion, a complex problem can only be viewed by looking at a small
number of its subproblems at any one time and seeing how they fit into the
“bigger problem.”
Month
day 1 day 2 day 3 day 15 day 30
Day
hour 1 hour 2 hour 24
The space in this book, represented in Figure 2.4, is broken down horizontally.
First the book is broken into chapters, then into sections. This book space could
be broken down further by including sentences, words and finally letters.
Actions, such as computing a weekly payroll, can be broken down into smaller
actions (determine the gross pay, determine the deductions) as shown in Figure
2.5. Each of these sub-actions may also be broken down further. In fact, the rest
of this chapter will mainly be concerned with the subproblem of computing an
employee’s gross pay
Sub-Actions
Determine Gross Pay Determine Deductions
Person
Attributes
Name Sex Seniority Address Supervisor BirthDate
Notice how break-out diagrams can describe four entities as varied as time,
space, actions and data. These diagrams essentially show how the long, linear
list of small “leaves” at the right, or at the bottom, is organized or grouped
together (into branches) forming a two-dimensional tree. More importantly,
these structure charts show how to break a problem into its subproblems.
Pre-Coffee
Coffee Break
Post-Coffee
AM
Work Lunch Problem: Lunch is a part of
Day PM both AM and PM.
Pre-Tea-Time
EVE Tea-Time
Dinner Time
Snack Time
Pre-Coffee
Coffee Break
Post-Coffee
AM Pre-lunch snack
Work Lunch Lunch Solution: Lunch is on the
Day same level as
PM Coffee AM, PM and EVE.
Pre-Tea-Time
EVE
Tea-Time
Dinner Time
Snack Time
Morning
Routine
46 Chapter 2 An Overview
This graphical form makes it easy for people to follow the sequence of
actions, or flow of control, provided the flowchart is small. Figure 2.11
represents the pay algorithm we just described. Notice that in the
computation of the pay for more than 40 hours (the box on the right of
the diagram), the pay for the basic 40 hours is shown as 10×40 and not
as 400. To have shown 400 in the algorithm, would have hidden the
two “components” of the product. The 400 would appear as an
anonymous “magic” number and the algorithm would be more difficult
to understand.
Input Hours
Output Pay
end
15
d c
10
5 a b
H
20 40 60 hours worked
50
50 hours
H
Gross Pay
P
$550
Pay
Modifying Algorithms
Once a useful algorithm has been defined, it often goes through many changes in
its “lifetime.” It may be made more powerful, more useful, more convenient,
more efficient, or more foolproof. Sometimes, it is used as part of larger
algorithms. The five processes for modifying are detailed below.
• Generalizing algorithms is the process of making them apply to more
cases. For example, the previous pay algorithm, shown in Figures 2.10
and 2.13, applies only to people paid at the same constant basic hourly
rate of $10. This algorithm could be generalized by requiring the input
48 Chapter 2 An Overview
Output Pay
end
This modified algorithm, Figure 2.15, can be used to compute the pay
for people working at different pay rates, and is thus more general and
more widely useful. Actually the overtime limit of 40, which is used
three times, could be replaced by a variable Maximum-Hours
indicating the overtime threshold, thus making the algorithm even
more general. Thus, if Maximum-Hours is set to 35, the overtime rate is
applied to all hours worked over 35, and not over 40 as in the
algorithms of Figure 2.14 and 2.14.
• Extending algorithms to include more cases is also very common. For
example, the original algorithm pays “time-and-a-half” for hours
worked over 40. Often, the overtime rate becomes even larger (up to
twice the regular rate) when more than a certain number of hours have
been worked (usually 60). The original algorithm of Figure 2.15 can be
extended to include a second rate of overtime. In this case, the original
pay algorithm applies for the first 60 hours, and the hours over 60 are
paid at double rate. An extended version of the original algorithm,
that allows for a double rate, is shown in Figure 2.16.
Section 2.4 Algorithms and Their Representations 49
Set Pay to
Rate × Hours Set Pay to
Rate × 40 +
1.5 × Rate × (Hours - 40)
Set Pay to
Rate × 40 + 1.5 × Rate × 20 + Extension: All hours worked
2 × Rate × (Hours - 60) above 60 are
now paid at
double rate.
Output Pay
end
Let’s execute or “trace” this algorithm with an input value of 100 hours
and an hourly rate of $10.00. First the number of hours and rate are
input, then the number of hours is compared to 60 and the rightmost
path is taken out of the decision box into the following computation.
Pay = Rate × 40 + 1.5 × Rate × 20 + 2 × Rate × (Hours - 60)
= $10.00 × 40 + 1.5 × $10.00 × 20 + 2 × $10.00 × (Hours - 60)
= $400.00 + $15.00 × 20 + $20.00 × 40
= $400.00 + $300.00 + $800.00
= $1500.00
This formula (and others) can be derived from finding the area of
various rectangles under a new graph of Rate versus Hours, an extension
of Figure 2.12 shown in Figure 2.17. Notice that by doubling the number
of hours worked (from 50 to 100), the resulting Pay more than doubles
(from $550 to $1500). In fact, the Pay almost triples.
50 Chapter 2 An Overview
20
15
10 800
300
5 400
H
20 40 60 80 100 hours worked
Set Pay to
Rate × Hours Set Pay to
Rate × 40 +
1.5 × Rate × (Hours - 40)
Set Pay to
Rate × 40 + 1.5 × Rate × 20 +
2 × Rate × (Hours - 60)
important to keep in mind that the algorithms that you write are likely to be
modified during their lifetimes. In other words, create algorithms with the
intent to make them easy to modify. When algorithms are well designed, their
modification can lead to better algorithms. Otherwise, a modification may
lead to disaster.
Alternative Algorithms
In computing, as is the case with many disciplines, there are often many ways
of accomplishing the same thing. This means that a choice must be made
between the various possibilities. For example, let’s consider the previous
simple pay algorithm from Figure 2.11, which is repeated on the left side of
Figure 2.19.
Set Pay to
10 × Hours
True Hours False
≤ Equivalent
40 in True Hours False
Set Pay to behavior ≤
Set Pay to 10 × 40 + 1.5 ×
10 × Hours 40
10 × (Hours - 40) Add to Pay
5 × (Hours - 40)
end end
The algorithm next to it, on the right side of Figure 2.19, shows an alternative
way to compute the gross pay.
First, the hours are input and the pay is computed by multiplying these hours
by the regular hourly rate ($10). For instance, in the case of 50 hours of work,
this would yield a value of 50 × 10 = $500.
Next, the hours are compared to 40 and, if they are greater than 40, the hours in
excess of 40 (overtime) are multiplied by 5 (half the regular rate) and the result
added to the first value. If the hours are not greater than 40, then nothing is
added to the first value. In the case of 50 hours of work, the overtime is
(50 - 40), or 10 hours, multiplied by the extra $5 per hour, which yields $50.
This overtime pay is then added to the first $500 for a total of $550 dollars.
Section 2.4 Algorithms and Their Representations 53
Equivalence of Algorithms
The two algorithms of Figure 2.19 are different in structure, but they are
equivalent in behavior. In other words, for identical input data, they will
produce identical results. Which do you prefer? Why?
In this example (Figure 2.19), there is no serious reason to prefer one algorithm
over the other. However, in some cases, one algorithm may be considerably
smaller, faster, simpler, or more reliable than another. The interesting thing is
that one embedded algorithm can be replaced by another with the same
behavior, like a spare part or a module, without changing the behavior of the
whole program. This “plug-in” capability of modules or building blocks can be
very useful.
Let us consider a more complex algorithm; the extended gross pay algorithm of
Figure 2.16 is repeated on the left side of Figure 2.20 with an equivalent
algorithm on the right.
Hours Hours
True > 7 × 24 or True > 7 × 24 or
Hours Hours
<0 <0
False False
Set Pay to
10 × Hours
True Hours False
≤
60
True Hours False
>
40
True Hours False
≤ Add
40 Equivalent
in 5 × (Hours - 40)
behavior to Pay
Set Pay to Set Pay to
10 × Hours 10 × 40 +
15 × (Hours - 40)
end end
Because the equivalence of these two algorithms may be less obvious, let us try
the algorithm on the right for an input of 100 hours. After the first condition is
False, the pay is computed from 10 × HOURS, giving $1,000. Then the second
decision (100 > 40) adds the amount 5 × (100 - 40) or $300. The third decision
(100 > 60) adds the amount 5 × (100 - 60) or $200. Finally, the output is the
54 Chapter 2 An Overview
sum of these three amounts (1000 + 300 + 200) or $1500. This output is identical
to the previously computed output for the algorithm on the left.
Testing
The fourth step of our problem solving method, Testing Strategy Development,
leads us to define the following:
1. A strategy, and then
2. a collection of test cases for the particular problem being solved.
In the example seen in Figure 2.20, there are only a few ranges of values that
could be used to test the algorithms. The left side of Figure 2.21 shows how the
input values could be split into the following five distinct ranges:
• Input values less than zero and those greater than 168 indicate errors.
• Values from 0 to 40 (inclusive) belong to the regular range,
• Values above 40 and up to 60 belong to the time-and-a-half range, and
• Values above 60 to 168 belong to the double-time range.
To compare these two algorithms, we must test them with input data taken
from each of these ranges. Only one value from each range is required since all
values within a particular range will follow the same path through the
algorithms (check it for yourself!).
So, to compare these algorithms, we must take one typical test value from each
of the ranges. Let us try -20, 20, 50, 100 and 200. These five values will exercise
all possible paths in the flow charts. Other equally good test values could be
-50, 30, 55, 150 and 170, or -5, 5, 45, 65 and 205. In addition, it is always useful to
test critical values, or limit values, such as -1, 0, 40, 41, 60, 61, 168, and 169.
The right side of Figure 2.21 displays a table of test values with the
corresponding output of each algorithm. This table shows identical outputs for
all of the input values. Verify for yourself that the two algorithms behave
identically for the limit values.
We can now say that the algorithms in Figure 2.20 are equivalent because the
test values were chosen carefully to cover all possible cases and the results of
the test values come on the same for both algorithms. It should be realized
that it is not always easy to test algorithms in this way. In some algorithms,
there may be hundreds or thousands of possible paths and test cases. Testing on
this scale will be discussed in Chapter 5.
Now that the two algorithms have been shown to be equivalent, which of them
is better? The difference between them is not great, but most people feel that
the second (the one on the left) is simpler and clearer because it consists of a
long and thin series of smaller decisions. Algorithms with a long and thin form
usually appear simpler than a “nesting” of short-and-fat decisions.
Because the two algorithms of Figure 2.20 are equivalent, there is a single
description of w h a t they both do; however, there are two different descriptions
of h o w they do it. This illustrates the difference between Step 2, Solution
Design, and Step 3, Solution Refinement. Solution Design gives us a description
of w h a t each sub-task must do to solve the problem, while Solution Refinement
gives us descriptions of h o w each sub-task is to be done. This distinction is
extremely important because the definition of w h a t is to be done should be
made independently from h o w it will be done. Defining w h a t generates the
plan for the solution, while defining h o w comes with the application of the
plan.
Communicating Algorithms
The subject of this book is programming, and as you progress, you’ll write
programs to run on a computer. To do this, you’ll need to use a specific
programming language.
Programming languages are notations used for communicating algorithms
between people and computers. There are now hundreds of such languages; to
give you a taste of these, Figures 2.20 to 2.25 show the same payroll algorithm
(taken from Figure 2.11) expressed in six different programming languages,
Basic, Fortran, Pascal, C, Modula-2 and Ada.
56 Chapter 2 An Overview
If you don’t understand all of these examples perfectly, don’t worry! These
examples are here only to suggest similarities and differences. All of these
programs have a similar meaning (semantics) but differ greatly in the details
of their form (syntax). For example, they all input the number of hours, but
each program specifies this input differently: Basic uses the command INPUT,
Fortran and Pascal use READ, C uses scanf, Ada uses Get and Modula-2 uses
ReadInt.
Basic
BASIC(Beginner’s All-Purpose Symbolic Instruction Code) was developed by
John Kemeny at Dartmouth College around 1967. It is a simple programming
language, designed to be easy to learn and to use. Many versions (or dialects) of
BASIC have appeared since and are still in use.
In Basic, the numbers at the beginning of each line are reference numbers for use
in the program. The word REM is used to introduce a “remark”, a comment to
help people understand the program. Each of the programming languages
shown here have their own way of marking comments. Some versions of Basic
limits the names of variables to a single letter, possibly followed by a single
digit. Here, we have used H for HOURS and P for PAY. Also notice that the
asterisk, *, is used as the symbol for multiplication instead of the × from
mathematics. This use of the asterisk as a symbol for multiplication is common
to most programming languages.
Fortran
Fortran (FORmula TRANslation), developed by John Backus around 1957, was
intended for engineering and scientific computations. Revised versions of
Fortran are still extensively used for numerical work.
Section 2.5 Programming Languages 57
Pascal
Pascal, created by Niklaus Wirth around 1970, was based on an international
language called Algol 60. It is somewhat similar to both Basic and Fortran, but
incorporates many refinements in structure. It was designed as a teaching
language for beginning students. Comments in Pascal are enclosed in braces, {
and }.
BEGIN
Read(hours);
IF hours <= 40 THEN
pay := 10 * hours
ELSE
pay := 10 * 40 + 15 * (hours - 40);
Writeln('Gross pay is ', pay:6);
END.
Modula-2
Modula-2 was also created by Niklaus Wirth in the late 1970s. Not only is it
an extension of Pascal, but a totally new language that retained Pascal’s good
features while adding some other important features. Its clarity, simplicity
and unity make it suitable for first time programmers and programming
professionals alike. Comments in Modula-2 start with (* and end with *).
58 Chapter 2 An Overview
C
C is a programming language created at the Bell Laboratories in the early 1970s
when low level access to the machine was considered important. Comments in C
start with /* and end with */.
Ada
A d a is a language created to the specifications of the U.S. Department of
Defense. It is a large, complex language named after Ada Lovelace, who is said
to have been the first programmer, and was a colleague of Charles Babbage as
well as the daughter of Lord Byron. Comments in Ada are introduced by the
characters -- and continue to the end of the line.
Section 2.5 Programming Languages 59
Planning and
20% Specifying 8%
Life Cycles of large programming projects have the typical form shown
in Figure 2.29. The four steps in this figure are explained as follows:
1. Planning and specifying involves studying the problem,
analyzing the requirements, specifying functions (actions) and
data. It encompasses Steps 1 and 2 of our seven step method.
2. Designing and Developing involves decomposing the whole
project into parts, refining the parts, coding them, and
documenting (describing) the design. It comprises Steps 3, 4,
part of 5, and 6 of our seven step method.
3. Testing and Evaluating involves verifying the function, testing
the performance, optimizing (improving time or space), and
62 Chapter 2 An Overview
2.8 Glossary
Action: An operation performed in an Design: The activities preceding the
algorithm or program. actual code writing.
2.9 Problems
4 4
3 3
2 2
1 1
Q Q
2 4 6 8 2 4 6 8
Discrete Quantity Continuous Quantity
a. Represent: Show
Draw a flowchart corresponding to this algorithm where the
quantity Q is input and the total cost T is output.
b. Analyze: Observe
Compute the total cost T when the quantity Q varies from 0 to 8.
Draw this as a table with three columns, Q, P and T. Then, draw a
graph of total cost T versus the quantity Q in both the discrete and
continuous cases. Observe this graph for surprising insights.
Hint: How many items can be purchased for 12 dollars?
c. Extend: Grow
Modify this algorithm if the price is further reduced to 2 dollars a
unit when the quantity purchased is more than 5. Draw the
flowchart for the extended algorithm. Draw also a graph of T
versus Q for the discrete and continuous cases both shown on one
graph.
68 Chapter 2 An Overview
d. Foolproof: fail-safe
Modify the above extended flowchart to include any foolproofing
that would be necessary.
e. Embed: Repeat
Modify the above flowchart to repeat the process for as long as the
input quantity Q is not zero.
f. Integrate: Generalize
Redraw all of the above features onto one flowchart, and
generalize all numeric constants to named constants P1, P2, Q1, Q2,
and so on.
g. Test: Evaluate
Select a set of test values to evaluate the final algorithm.
2. Scissors Search
Indicate which of the following verbal algorithms is better for finding
an object, such as a pair of scissors, and explain why:
a. Look on the rightmost end of the lower shelf of the middle cabinet
in the garage.
b. Look in the garage, in the middle cabinet, on the lower shelf, at the
rightmost end.
3. Break-Out Problems
Create break-out diagrams describing four of the following:
a. a telephone number
b. the arrangement of five books on a shelf
c. performing some process (laundry, cooking)
d. your entire past life
e. the plan for your present day
f. the plan for the next five years
g. the layout of newspaper sections
h. anything else of interest to you.
4. Language Look
Even without knowing any programming languages, you can now make
meaningful comparisons among the six programming languages
presented in this chapter.
Section 2.9 Problems 69
5. More Pay
a. If the condition for overtime in the original payroll problem were
changed, from (Hours ≤ 40) to (Hours < 40), would this change the
amount of pay?
b. If Hours is input as a negative amount (say -50 by mistake), is the
output correct except for its sign?
c. Modify the extended pay algorithm of Figure 2.16 to allow for
triple-pay when the hours are greater than 80. Draw the
corresponding graph and flow chart.
Get Spoon
Get Bowl Wash Spoon
Improper
Cereal Pour Cereal
Pour Milk Add Sugar
Eat
San Diego
Vancouver
Out of country
Calgary
8. Energy Rates
a. Not encouraging excessive use
Electrical energy rates are set in such a way that the rates decrease
for higher usage. However, the rates should not encourage
excessive use of energy, so the lower rates apply only to the higher
energy amounts; not all of the energy used is at the low rate.
For example, the rate is constant $4 per unit for the first 4 units and
drops to $3 a unit for more than 4 units. So when 6 units are used
only the last 2 units are at the $3 rate. Energy is a continuous
quantity; it is not used in discrete steps.
(i) Represent, show
Draw a graph showing the price per unit versus the number
of units used.
(ii) Analyze, observe
Create an algorithm to determine the total cost of energy,
given the number of units used. Draw the graph of cost
versus units.
(iii) Extend: grow
Modify this algorithm if the price per unit drops to $2 a
unit for more than 8 units. reuse. Draw the graph of cost
versus units.
(iv) Foolproof, embed, and generalize
Complete this system in any way you see fit and draw the
final algorithm in all of its detail.
(v) Test, evaluate
Select a set of test values to evaluate the final algorithm.
Section 2.9 Problems 71
9. Ideal Weight
A man should weight 106 pounds for the first 5 feet, and 7 pounds for
every inch above that. A woman should weigh 100 pounds for the first
5 feet, and 6 pounds for every inch over that.
a. Create an algorithm in flowchart form that outputs the ideal
weight when input the sex and height (feet and inches).
b. Represent this algorithm as two tables from 5 feet to 6 feet 5 inches.
c. Represent this algorithm in a graphic form, with 2 graphs on one
grid.
Chapter 3 Algorithms
In this chapter, we study algorithms in some depth, discuss their necessary and
desirable properties, provide examples of them and show various ways of
representing them.
Chapter Outline
3.1 Preview....................................................................74
3.2 What Are Algorithms?.............................................75
Algorithm Definition................................................75
General Properties of Algorithms..............................75
Desirable Attributes for Algorithms..........................77
3.3 Different Algorithm Representations........................78
Verbal Representations.............................................80
Algebraic Representations (formulas and
expressions).....................................................82
Tabular Representations (tables, arrays, and
matrices).........................................................86
3.4 Data-Flow Diagrams................................................89
Black Boxes vs. Glass Boxes.......................................89
General Data-Flow Diagrams...................................91
Integer Data-Flow Diagrams.....................................94
Logical Data-Flow Diagrams....................................98
Data Flow Black Boxes.............................................101
More on Data Flow Components and Diagrams...........105
3.5 Flow of Control Diagrams..........................................107
Flowcharts...............................................................107
Larger Flowcharts Using Subprograms......................110
Flowblocks................................................................113
Pseudocode................................................................115
3.6 Review Top Ten Things to Remember........................118
3.7 Glossary...................................................................119
3.8 Problems...................................................................121
74 Chapter 3 Algorithms
3.1 Preview
Our problem solving method requires the development of algorithms as part of
its third step, Solution Refinement. To be able to complete this step, we need to
know a lot more about algorithms. This chapter will help us do just that, for we
will:
• Study algorithms in some depth
• Discuss their necessary and desirable properties
• Provide many examples of algorithms, and
• Show various ways of representing algorithms.
Analgorithm is a plan for performing a sequence of actions on data to achieve an
intended result. To be useful, the algorithm must be precise, unambiguous, and
specify, for all possible cases, a unique and finitesequence of actions that
achieve a predictable result. In addition, an algorithm should be applicable to
a number of problems rather than to a single instance, have a simple structure,
and be easy to use efficiently.
Algorithms can be represented in many different ways. For any algorithm,
there may be many different representations, some much better than others. No
one representation is best for all algorithms. The representations considered in
this chapter are as follows:
• Verbal: The algorithm is expressed in words.
• Algebraic: The algorithm is expressed mathematically with symbols
and formulas.
• Tabular: The algorithm is represented by one or more tables
• Hierarchical: The algorithm is presented as a break-out diagram.
• Data-flow diagram: The algorithm is shown as a set of boxes that
show the actions to be performed. These boxes are linked by lines
showing how data flows from one action to another. This is referred to
as the flow of data.
• Flowchart: The algorithm is represented in the form of a diagram with
action boxes linked by lines showing the order in which they are
executed, or the sequence of actions. This is referred to as the flow of
control.
• Flowblocks: Like flowcharts, the algorithm is represented by action
boxes. Instead of connecting the boxes with lines, the flow of control is
illustrated by stacking boxes on top of each other, or by nesting boxes
within other boxes.
• Pseudocode: The algorithm is presented as a set of instructions written
using a mixture of natural language and mathematical notation. The
Section 3.1 Preview 75
Algorithm Definition
An algorithm is a precise plan for performing a sequence of actions to achieve
the intended purpose. Each action is drawn from a well-understood repertoire
of actions on data. Here are some examples of algorithms:
• Prepare breakfast.
• Decide how much to charge for admission to a cinema.
• Calculate the average of a group of values.
• Change a car tire
• Play a dice game
Notice that each of the above algorithms specify two things.
1. An action specified by verbs such as “prepare”, “change”, and “play”
2. The data to be acted on, specified by a noun or noun phrase such as
“breakfast”, “a car tire”, and “a dice game”.
Many of these algorithms will be considered in detail later, for now it is
sufficient to understand that algorithms are common to everyday life, and do
not necessarily involve computers.
When your get a set of directions that finishes with “You can’t miss
it!”, you know you are in trouble. For starters, in which direction
should we drive on Route 116, north or south? If we had some knowledge
of the area, it might be reasonable to expect us to know. But the
directions, as they stand, are not precise, and do not represent an
algorithm!
• Unambiguous: A set of instructions will be unambiguous if there is only
one possible way of interpreting them. For example, even if we accept
the directions to the pizza parlor as being precise enough, they are still
ambiguous about the direction to turn when we reach Route 9. We can
not assume local knowledge because, if we knew which way to turn, we
would know how to get to Fred’s. The ambiguity can only be resolved by
trial and error. When we get to the junction of Route 116 and Route 9, we
can try going left to see if we find the parlor. If Fred’s is not left, it must
be to the right.
• Deterministic: This third property means that if the instructions are
followed, it is certain that the desired result will always be achieved.
The following set of instructions does not satisfy this condition:
Algorithm for becoming a Millionaire
1. Take all your money out of the bank and change it into quarters.
2. Go to Las Vegas
3. Play the slot machines until you either win four million quarters or you go broke.
Clearly, this “algorithm” does not always achieve the desired result
of becoming a millionaire. It is most likely that you will finish with no
money. However, you just might achieve the goal of becoming a
millionaire, winning four million quarters. The point is that we cannot
be certain what the result will be. This makes the set of instructions
non-deterministic, and thus does not constitute an algorithm.
• Finite: The fourth requirement means that the instructions must
terminate after a limited number of steps. The “algorithm” for
becoming a millionaire fails this criterion too. It is possible that you
will never reach either the stage of having four million quarters or of
going broke. In other words, if you follow the instructions, you might
end up playing the slot machines forever.
The finite requirement not only means termination after a finite number
of steps, it also means that the instructions should use a finite number of
variables to achieve the desired result.
Section 3.2 What Are Algorithms? 77
and L, did not have much place in early counting. They are thought to have
evolved from these counting marks.
Normally, for arithmetic purposes, there is one standard form or notation
(Hindu-Arabic, base 10 form). Unfortunately, in computing, there is no such
standard when it comes to representing algorithms.
Selecting the proper representation for algorithms is not a simple task for there
are no guidelines which we can follow. The only way to determine the best
representation is to try at least two forms and see which one you like the best.
After a few tries, you’ll find a representation that you prefer, or you’ll have
developed your own by combining a couple of the representations introduced
here. In any case, you should develop your algorithms using the representation
that best fits your style.
Without a good representation, it is very difficult to express an algorithm. For
example, we probably know the algorithm for making change for 12 cents when
given a dollar. We would add from the 12 cents up to the dollar. For our
specific example, we would first give 3 pennies (to make 15 cents), then a dime
(to make 25 cents), and then 3 quarters to finally add up to the dollar tendered.
Although we know how to add up to a dollar from 12 cents without the help of
a cash register, we would have difficulty describing how to make change for an
arbitrary amount. To describe this algorithm precisely to a computer would be
even more difficult for us. The point is that knowing how to do something is
very different from being able to describe precisely how to do it! To use the
words of St. Augustine,
“If no one asks me, I know what it is. If I wish to explain it to he who asks, I do not know.”
Verbal Representations
The following figures (3.1 to 3.5) present some very common examples of
algorithms. They appear here in a simple verbal form (representation) and
will be transformed into other forms later. Remember, For any particular
algorithm, one representation may be much better than another; therefore, it is
worth getting familiar with a number of alternative forms.
The algorithm Charge admission, of Figure 3.1, specifies an admission charge
that depends on the age of the person being admitted; it consists of a procedure
to determine the charge and some examples showing the results of applying the
procedure.
For example:
Figure 3.2 shows another algorithm expressed in a verbal form which specifies
a method to determine which years are leap years. It is usually sufficient to
check if 4 divides evenly into the year, but if the year marks a century, then
the algorithm is more complex. For example, the year 1900 was not a leap year,
while the year 2000 will be a leap year.
A leap year is divisible by 4 but, if it is divisible by 100, then it is not a leap year, unless it is
also divisible by 400.
For example:
Our third verbal algorithm example, Dice Game (Figure 3.3), specifies how a
simple game is played, using two dice having one to six dots on each side.
Section 3.3 Different Algorithm Representations 81
Two dice are thrown. If their sum is 7 or 11, you win, and if the sum is 2, 3 or 12, you
lose. If neither rolls come up, remember the sum, the “point count”, and keep throwing
until either:
7 you win
6, 7 you lose
Figure 3.4 shows a fourth example, Ideal weight, which describes one view of
the relationship between height and weight.
A man should weigh 106 pounds for the first 5 feet of height plus 7 pounds for every
inch above that; a woman should weigh 100 pounds for the first 5 feet of height plus 6
pounds for every inch above that.
For example:
Our final example for the verbal representation of algorithms, ISBN, shown in
Figure 3.5, describes the way to determine the last digit for the International
Standard Book Number. Most recent books have on their back covers a special
ten-digit ISBN such as:
0-06-500871-5 (the hyphens are not important)
The first digit, 0, represents the book’s area of origin. 0 means that it was
published in an English-speaking country. The second group represents the
publisher; 06 means that it was published by Harper Collins. The third group,
500871, represents the book’s title and is assigned by the publisher. The last
digit, 5, is a check digit that is computed from the nine preceding digits as
shown in the algorithm.
82 Chapter 3 Algorithms
...so on to ...
If the remainder is less than 10, then the remainder becomes the checksum, otherwise
the checksum is the character ‘X’.
For example:
For example, the “weighted sum” of the first number in Figure 3.5 is...
1 × 0 + 2 × 0 + 3 × 6 + 4 × 5 + 5 × 0 + 6 × 0 + 7 × 8 + 8 × 7 + 9 × 1 = 159
Dividing this sum by 11 yields a remainder of 5, which is the checksum. This
code is used for error checking when ordering a book, for example. If the
computed checksum does not equal the last digit of the ISBN, then an error has
been made in copying this book number. This is a very useful error detecting
method because it detects the most common copying error, that of transposing
adjacent digits.
C = 3 x A + 2 x K where
For example:
C= 3 x A + 2 x K = 3 x 2 + 2 x 3 = $12
T = S + 60 x M + 60 x 60 x H + 24 x 60 x 60 x D
or alternatively
T = S + 60 x (M + 60 x (H + 24 x D)), where
For example:
T = 4 + 60 x 3 + 60 x 60 x 2 + 24 x 60 x 60
= 93 784 seconds
5
C = 9 x (F - 32)
9
F = 5 x C + 32
or alternatively
5
C = ( 9 x (F + 40)) - 40
9
F = ( 5 x (C + 40)) - 40
For example:
For F = 212°F
5
C = 9 x (212 - 32) = 100°C
For C = 20°C
9
F = 5 x 20 + 32 = 68°F
The next example, Figure 3.9, shows two different algorithms that compute the
square of any positive integer number N. In the first formula, the number N is
added to itself N times. Alternatively, in the second formula, the square of an
integer N is determined by summing the first N odd integers. This Square
example illustrates again that there may be many ways to do the same thing.
S = N + N + N +. .. + N (N times)
or alternatively
S = 1 + 3 + 5 + 7 +. .. + (2N - 1)
Square(7) = 7 + 7 +7 + 7 +7 + 7 + 7 = 49
Square(7) = 1 + 3 +5 + 7 +9 + 11 + 13 = 49
Statistical measures like mean and variance are shown as formulas in Figure
3.10. The mean of N given values, M, is found by summing all the values and
dividing this sum by N. For example, here is the Mean of the 4 values 10, 20, 30
and 40:
M = (10 + 20 + 30 + 40) / 4 = 25
Section 3.3 Different Algorithm Representations 85
For other The variance, V, is a measure of the amount of variation of the values about
methods of this mean value. It is computed by taking the average of the square of the
finding the differences of the values from the mean, M, as shown in Figure 3.10.
variance, see
Problem 18 in Figure 3.10 A Mean and Variance formula algorithm
Section 3.8 and
see Chapter 8. M = (X 1 + X2 + X3 +. .. + XN ) / N
V = [(X 1 – M) 2 + (X2 – M) 2 +. .. + (X N – M) 2 ] / N
For example, for the four values 10, 20, 30, 40:
M = (10 + 20 + 30 + 40) / 4 = 25
= 125
N! = N x (N – 1) x (N – 2) x. .. x 2 x 1
For example:
5! = 5 x 4 x 3 x 2 x 1 = 120
approximation. The more terms of the series we use for our computation, the
more accurate the approximation we obtain.
For example:
= 1 – 1/6 + 1/120 – …
= 0.8416
Figure 3.13 shows a formula to convert binary numbers (base 2) into decimal
numbers (base 10). For example, the binary number 11001 can be converted to the
decimal number 25:
(11001)2 = 24 × 1 + 23 × 1 + 22 × 0 + 21 × 0 + 20 × 1
= 16 + 8 + 0 + 0 + 1 = 25
This process can be generalized to any other base B by replacing the base value
of 2 by B. For example, this algorithm can convert octal to decimal numbers
simply by changing the base from 2 to 8.
For example:
(110) 2 =4+2+0=6
(1101) 2 = 8 + 4 + 0 + 1 = 13
(1000000) 2 = 26 x 1 = 64
Month Days
1 31
2 Leap Leap Sub-table
3 31
4 30 Leap Feb
5 31 Year Days
6 30
NO 28
7 31
8 31 YES 29
9 30
10 31
11 30
12 31
For more on the The Charge Admission algorithm, which we have encountered twice
property of previously in Figures 3.1 and 3.6, is shown as a table in Figure 3.15. In this
completeness, algorithm, admission is $3 per Adult and $2 per Kid, some frequent
consult Section combinations of Adults and Kids are computed once and then can be referred to
3.2 under later to save further computation. Although the property of completeness is not
General satisfied (not all combinations are shown), this table is still convenient and
Properties of useful since it specifies the charge for the most common combinations of Adults
Algorithms. and Kids.
88 Chapter 3 Algorithms
Charge Table
in two dimensions
1 0 3
1 1 5 Charge
Kids
1 2 7
1 3 9 Adults 0 1 2 3
2 0 6
This algorithm is 1 3 5 7 9
incomplete: not all 2 1 8
combinations are 2 2 10 2 6 8 10 12
shown here. 2 3 12
3 9 11 13 15
3 0 9
3 1 11
3 2 13
3 3 15
A B C M
0 0 0 0 Majority alternative as
Decision Table
0 0 1 0
0 1 0 0 A 0 0 ? 1 1 ?
0 1 1 1 B 0 ? 0 1 ? 1
1 0 0 0
1 0 1 1 C ? 0 0 ? 1 1
1 1 0 1 M 0 0 0 1 1 1
1 1 1 1
? is for irrelevant
Decision tables are alternative forms of truth tables. They are used in many
business applications that involve complex combinations of decisions because
decision tables provide an easy way to check for completeness and consistency,
since all combinations are listed.
Section 3.3 Different Algorithm Representations 89
A decision table for Majority is shown at the right of Figure 3.16. This table is
smaller than the table on the left of Figure 3.16, because it has only 6 rules
(combinations of the conditions A, B, C). For example, consider the first column
(rule); if A and B conditions are both 0, then regardless of condition C the
Majority action is 0. Often the conditions are labeled with values of Yes and
No, or True and False instead of 0 and 1.
Indices refer to a position in a table. For example, the tables corresponding to
Days in a Month and Leap, shown in Figure 3.14, only have one index each
(Month and Leap Year). The table for Charge Admission, shown in Figure 3.15,
has two indices labeled Adults and Kids. The tables for Majority in Figure 3.16
have three indices labeled A, B, C. Indices are also called subscripts.
Note: In the decision table in Figure 3.16, the “?” indicates a value that
has no effect on the outcome and, therefore, that does not need to be
examined.
Examples of the A Black box describes a system that accepts inputs, and produces outputs, while
“black box” view hiding the internal details of the transformation. This view shows what is
are shown later being done by each box and how the boxes interconnect. It provides a higher
in this section. level “bird’s eye” view, as the low level details are not shown. This is the
“black box” view provided by data-flow diagrams which use arrows to indicate
the flow of data in and out of each box.
A Glass box describes the inner details of a system. This view shows how
Examples of the things are done within a box. It provides a lower level “worm’s eye” view.
“glass box” view This view is represented by flowcharts and flowblocks, with arrowhead lines
are shown in showing the flow of control between various boxes.
section 3.5, using
three different Figure 3.17 Black box vs. glass box
representations:
Flowchart
flowcharts, , or
flowblocks and Glass box
pseudocode.
Divide N by D
Set
Q to 0
R to N
Data flow diagram,
or
Black box True False
R≥D
N D
Black boxes are Divide Subtract Glass boxes are
opaque: all the R Q transparent. We
details are hidden. D from R
can see all the
We can only see details of the
what goes in and operation.
what comes out of Increase
the operation. Q by 1
Q is quotient
R is remainder
It is important to understand that these two views, black box and glass box, are
complementary, and that each has its appropriate place. The black boxes are
generally used first to give an initial, high-level specification of a system.
The black boxes prevent us from filling our minds with details too early. The
glass boxes are used, at lower levels, to deal with the details.
Choosing the right type of boxes to use is not simple. Sometimes it is very
difficult to put an algorithm into one form, yet very easy to put it into the other
form. Sometimes the black box data flow method is best; at other times, the
Section 3.4 Data Flow Diagrams 91
glass box control flow method is best. Sometimes we need to switch back and
forth between these two views.
Top-down break up of systems into boxes is an important process. The larger
boxes (usually black boxes) are broken-out into collections of smaller boxes. The
smaller boxes, in turn, are broken down further until all boxes are sufficiently
simple and can be transformed into glass boxes. Much more will be done with
these two views later.
Black boxes hold a special significance. Each black box may be viewed as a sub-
algorithm with input arrows representing values “passed in” and output arrows
representing some result “passed out”. This allows us to consider some
important concepts without having to get into great detail. For now, the boxes
simply allow us to break out and manage the complexity of systems. Later, we
will explore important concepts like sub-algorithms
+ - /
D = A + B C
A B C
1 2 3
+
7
In Figure 3.19, the arithmetic operators addition and multiplication, are shown
as black box operators with two inputs and one output each. The two values at
the inputs are transformed by the operator into one value at the output. The
“flow” of these values leads to one resulting output value, at the bottom of this
diagram.
The precedence of an operator is a common convention that helps specify the
order in which the operations of an expression are to be performed. This
corresponds to the rule that we learned in high-school: that multiplication
and division are done before addition and subtraction.
Section 3.4 Data Flow Diagrams 93
9 / 5 C + 32 (F - 32 ) (5 / 9)
68 F = 20 C
9 5 C 32 F 32 5 9
20 68
Note that the /
multiplication
and the 1.8 - /
division are
done in the 36 0.5555...
equation: 36
from left to
right. +
68 19.9999...
F C
Figure 3.20 shows the data-flow diagrams for the conversion of temperatures
between Fahrenheit and Celsius scales. The diagram on the left of Figure 3.20
shows the conversion of 20°C to 68°F, and on the right of the same figure, the
conversion of 68°F back to 19.9999…°C! In other words, we did not finish up with
what we started with! This illustrates a problem of possible inaccuracy when
dealing with repeating decimals, such as 5/9 (0.55555555555…). Because it is
impossible to store an infinite number of decimals in a computer, only
approximations to such numbers can be stored and used, which leads to a loss of
precision in the computations.
Polynomials are formulas (arithmetic expressions) that involve a single
variable, say X, taken to certain powers and multiplied by various coefficients
as in the following example:
Y = A + B × X + C × X2 + D × X3 + E × X4
Such polynomials can usually be factored to yield a formula which, in the case
of our example above, will look like this:
Y = A + X × (B + X × (C + X × (D + X × E)))
The first way of writing the polynomial may seem like a natural way to think
about the evaluation of the formula, but it involves much more multiplication
94 Chapter 3 Algorithms
than the second way, which only requires four instances of multiplication. The
difference is shown in the two data-flow diagrams of Figure 3.21. The second
method, shown on the left, has a more “elegant” data flow structure.
E
A B C D E
D ×
× × × ×
+
× × ×
C ×
+
× ×
+
+ ×
B ×
+ +
A ×
This algorithm is more +
elegant since there are
+ fewer multiplications
required than for the
algorithm shown at right. Y
Y
X Y F S
Add Subtract
Z D
A B N D
Multiply Divide
C Q R
In particular, you should note that the division of Integers is different from the
division of Real Numbers. Dividing an Integer N by another Integer D yields
an Integer quotient Q and an Integer remainder R: for example, dividing 23 by 7
yields a quotient of 3 and a remainder of 2. There are two outputs (Q and R)
from Integer division, whereas there is only one output from the division of
Real Numbers. In the case of the division of 23 by 7, the Real Number operation
yields this never-ending, repeating decimal:
23/7 = 3.285 714 285 714 285 714 285 714...
The conversion of any number of grams to the corresponding number of kilograms,
hectograms, decagrams and grams, illustrates the use of Integer Divide data
flow boxes. The various conversion factors are shown in Figure 3.23.
Because the metric system has the same base as our decimal counting system
(base ten), we are able to make conversions between these measures in our head
without difficulty. However, to make these conversions on a computer, we need
an algorithm. Figures 3.24 to 3.26 provide three different ways of expressing
something that we can compute in our heads, as an algorithm.
96 Chapter 3 Algorithms
N D
Divide
Q R
24 Hecto- 3 Grams
grams
10 10
N D N D
Divide Divide
Q R Q R
2 4 0 3
Kg Hg Dg G
Kilograms Hectograms Decagrams Grams
N D
Divide
Q R
3 Grams
240 Deca- G
grams
10
N D
Divide
Q R 0 Decagrams
24 Hecto- Dg
grams
10
N D
Divide
Q R 4 Hectograms
Hg
2 Kilograms
Kg
The second conversion method, Figure 3.25, begins by dividing the number of
grams by 10, yielding a quotient of 240 decagrams and a remainder of 3 grams.
Next the 240 decagrams are divided by 10 again (10 decagrams = 1 hectogram)
yielding a quotient of hectograms (24) and a remainder of decagrams (0).
Finally the 24 hectograms are divided by 10 (10 hectograms = 1 kilogram),
yielding a quotient of kilograms (2) and a remainder of hectograms (4).
98 Chapter 3 Algorithms
N D
Divide
Q R
2 Kilograms
Kg
100
403 Grams
N D
Divide
Q R
4 Hectograms
Hg
10
3 Grams
N D
Divide
Q R
0 Decagrams
Dg
3 Grams
G
Figure 3.26 shows yet another conversion method that works in the opposite
direction from Figure 3.25.
First, it divides the number of grams by 1000, yielding a quotient of 2 kilograms
and a remainder of 403 grams. This number of grams is then divided by 100,
yielding a quotient of 4 hectograms and a remainder of 3 grams. For this
example, the task is already complete at this point and it is tempting to stop
now. However, in general, we need to proceed further. The number of grams is
divided by 10 yielding a quotient of 0 decagrams and a remainder of 3 grams.
Oftentimes, it is possible to solve a problem in many ways. Our rather simple
conversion problem had three different solutions. Larger problems may have
many more solutions. None of the above solutions seem much better than the
others for they all involve three divisions. In some problems; however, the
solutions may be very different and some will be highly preferred over others.
A B P Q X
AND OR NOT
C R Y
A B C P Q R X Y
F F F F F F F T
F T F F T T T F
T F F T F T
T T T T T T
Truth tables for each operation (bottom of Figure 3.27) describe the output
behavior for all given combinations of input values. These truth tables can be
viewed and used as tiny arithmetic operation tables, somewhat like
multiplication tables.
The AND operator, applied to two propositions A and B, has output True when
both A and B are True. Otherwise its output is False. For example:
(2 + 2 = 4) AND (7 is even) is False.
100 Chapter 3 Algorithms
The OR operator, applied to two propositions P and Q, has output True when
either P or Q or both are True. It only has the output False if both P and Q are
False. For example:
(2 + 2 = 4) OR (7 is even) is True.
The NOT operator (or negative), applied to a False proposition, gives True, and
NOT, applied to a True proposition, gives False. For instance:
NOT (7 is even) is True.
Logical operators can be combined to build logical expressions or new logical
functions as shown in Figures 3.28 and 3.29.
K L
OR
NOR operator
NOT
K L K OR L M
F F F T
F T T F
T F T F
T T T F
Figure 3.28 shows the complement (NOT) of the OR of propositions K and L, and
the corresponding truth table. Notice that the resulting output M is True only
when neither K nor L is true; this is called the NOR operator.
Complex logical expressions that involve the negation operator NOT can often
be simplified by the application of DeMorgan’s Laws. DeMorgan’s First Law
has this form:
NOT(P OR Q) = NOT(P) AND NOT(Q)
This states that, to negate the OR of two propositions, you negate each
proposition and change the OR to an AND. Consider this statement:
I will go out, if it is not raining or freezing.
This is equivalent to
I will go out, if it is not raining and not freezing.
As another example of DeMorgan’s First Law, let’s take the negative of an
expression involving a baseball game with inning I and scores S1 and S2:
NOT {(I ≤ 9) OR (S1 = S2)}
This is equivalent to
Section 3.4 Data Flow Diagrams 101
P Q P Q
P Q Left Right
OR NOT NOT F F T = T
= F T F = F
NOT AND T F F = F
T T F = F
R R The results
are the same
in all cases.
A proof of the first law is given at the right of Figure 3.29; the logical
expressions corresponding to the diagrams at the left and right are the same in
all four possible cases.
DeMorgan’s Second Law is:
NOT(P AND Q) = NOT(P) OR NOT(Q)
This law will be further discussed in Chapter 5.
7 4 3 4 50 10
X M X Y H R
Square Days Max2 Gross Pay
Y D M G
49 30 4 550
1 0 1 13 5 2 1 3 11 7
A B C N D A B C N D
Maj3 Divide Sort3 Mod
M Q R L M S R
1 2 3 3 2 1 1
3 4
X X
Square Square
Y Y
9 16
Add
25
Square
Root
N D Q R
Divide
R Q
18 Q Quarters
2
10
N D
Divide
R Q
8 D Dimes
1
5
N D
Divide
R Q
N Nickels
1
P Pennies
3
We would not normally use such an algorithm for making change because the
division is too difficult. We would probably choose to make change by
avoiding even subtraction. We often do things differently than computers.
Notice too that this Change Maker algorithm could be represented as a black
box with two inputs and four outputs (as shown in Figure 3.33, a slight variation
from what we saw in Figure 3.30).
Change Maker
2 1 1 3
Q D N P
Section 3.4 Data Flow Diagrams 105
A B C
Sort3
L M S
Sum Min
6 5 3
14 3
Add Subtract
11 2 11 2
Divide Divide
5.5 5.5
M M
The left side of Figure 3.34 shows an algorithm that begins by sorting the three
exam grades X, Y, Z into order with the largest labeled L, the middle value
labeled M and the smallest called S. Then the highest two values L and M are
added, and this sum divided by 2 to get the resulting mean M.
The Forgiving Mean algorithm at the right of Figure 3.34 finds the sum of the
three grades as well as the minimum value of the grades. It then subtracts the
minimum from the sum and divides this result by 2 to get M, the resulting mean.
At this point, it is not important to recognize which of these two methods is
preferable. However, it is important to realize that there are often a number of
ways to do anything. The first method may seem simpler, but it may be slower
or more costly. The choice between methods depends on more knowledge of cost,
speed, availability, and so on. These topics will be discussed in detail later in
this book.
In computer science, concurrency is the ability of actions to be done at the same
time, or in parallel. Data-flow diagrams often reveal the potential for
concurrency. For example the operations of Sum and Min in Figure 3.34 could be
done at the same time. Most of our present machines and languages do not take
advantage of this; they wait for one to be done before doing the other. In the
future, our systems may find this parallelism to be useful and efficient.
106 Chapter 3 Algorithms
Figure 3.35 shows two more data-flow diagrams, Base Conversions, that
represent the algorithms for converting a number from binary (base 2) into
decimal (base 10), and then back into binary again.
N D
Divide
8 4 2 R Q
1
5 4
Mult Mult Mult
N D
Divide
8 4 0 1 R Q
1
1 2
Add
N D
Divide
R Q
0
13
The two algorithms in Figure 3.35 are described from left to right, as follows:
• Binary to Decimal: The algorithm at the left of Figure 3.35 shows how
a four-bit binary number (1101) is converted to a decimal value by
multiplying the left-most digit by 8, the next digit by 4, the next by 2
and the right-most digit by 1. Summing these values gives the decimal
value of 13.
For longer binary numbers, the leftmost digit is multiplied by successive
powers of 2. For example, if the binary number was (11101), the
leftmost digit would be multiplied by 16 or 24.
Instead of speaking of the left-most digit of a number, we refer to it as
the most significant digit. The term “significant” is used here in the
sense that since the left-most digit has the greatest value, it is the
most significant digit in computing the value of the complete number.
For example, in the decimal number 1234, the 1 has value one thousand,
the 2 has value two hundred, and so on. Similarly, the right-most digit
is referred to as the least significant digit.
• Decimal to Binary: The data-flow diagram at the right of Figure 3.35,
shows how the decimal value of 13, obtained from the left, is converted
back into the binary form by successively dividing by 8 then 4 then 2
Section 3.4 Data Flow Diagrams 107
and so on, to arrive at the original binary sequence 1101. In general, the
first value to be used as the first divisor must be the largest power of
two (2, 4, 8, 16,…) that is just less than the decimal number. For
example, since the decimal number in Figure 3.38 is 13 and since 8 is the
largest power of two that is just less than 13, 8 is used as the first
divisor.
Flowcharts
Flowcharts are one of the most common ways of showing the sequence of actions
in an algorithm. They consist of boxes joined by lines with arrows showing the
flow of action sequences. The boxes are of different shapes depending on
whether they represent actions, decisions or assertions:
• Actions denote processes (such as input, output, calculate) and are
represented as rectangular boxes, as shown in Figure 3.36. Actions may
change the value of the data on which they operate. For example, the
action of incrementing a counter changes the value of the counter by
adding 1 to it.
The actions that can be performed on data depend upon what kind of
data are involved. For example, Real Numbers may be added,
subtracted, multiplied and divided to yield Real Numbers. On the
other hand, the logical operators, AND, OR and NOT do not apply to Real
Numbers or Integers; they only apply to logical quantities which have
the value of True or False.
• Decisions usually take the form of tests or questions such as “Age < 12?”
or “Color?” that have two or more results (mostly, but not always True
or False), depending upon the values being tested. Decisions are
represented by diamonds or boxes with pointed ends. Each decision box
must have an outgoing arrow labeled for every possible result, as shown
in the examples of Figure 3.37. These arrows lead to the next action or
decision to be performed. If the possible results are True and False, you
might find it easier to follow a certain convention, like having a True
result always take the left path out of the decision box as we do in our
flowcharts.
108 Chapter 3 Algorithms
Age ≥ 12 Increasing
(A < B)
Age < 12 Color and
(B < C)
Invocation Forms
is still owed, the actions are repeated once for each month. Only after
the Balance has been finally reduced to zero is this loop terminated.
This form is referred to as a loop because if you look at the lines that
indicate repetition, you will see that they resemble a loop. The
condition “Balance>0” is referred to as the termination condition. The
action of making the payment and reducing the Balance is known as the
body of the loop. We will see the details of the actions within this
loop later.
• Invocation: Each of the three above examples could be put into a box
and labeled for future reference. These boxes are referred to as sub-
algorithm, and they can be invoked whenever needed. The lower part
of Figure 3.38 shows the invocation of the three corresponding sub-
algorithms above. A sub-algorithm is marked as a box with double
lines on each side. The invocation of a sub-algorithm is considered a
single action within a flowchart.
The examples of Figure 3.38 illustrate the Four Fundamental Forms: Sequence,
Selection, Repetition, and Invocation, which constitute the basic building
blocks from which all algorithms can be made.
Notice that each of these four forms have a single entry and a single exit.
Remember, we are representing flow of control here, not data flow. In data-
flow diagrams, multiple entries and exits are possible for data, as we have seen
for instance in the Change Maker algorithm of Figure 3.33.
Figure 3.39 shows a slightly more complex algorithm, Charge More. It is an
extension of the previous Charge algorithm, shown in Figure 3.38, used to
calculate the price of admission to a movie. The old algorithm has been
modified to include a third category: persons over 21 years old. Notice that
the previous Charge algorithm is embedded in this larger algorithm and is
shaded. An assertion is delineated by a dotted box.
110 Chapter 3 Algorithms
Subtract
True False D from R
Age < 12
Increase
Charge $2 Charge $3 Q by 1
end end
At the right of Figure 3.39 is another algorithm, Divide, that shows how
computers can be used to divide positive integers in a way that is very different
from how we do division. Since we plan to revisit this algorithm later, you
may wish to avoid it for now.
Divide, the algorithm at the right of Figure 3.39, divides one Integer (N, the
numerator) by another non-zero Integer (D, the denominator) to produce a
quotient Q and remainder R. This is done in a loop where each time the loop is
traversed, an iteration, 1 is added to the quotient, Q, and the divisor, D, is
subtracted from the remainder, R. This continues until R is less than D.
The body of the loop comprises the actions of subtracting the divisor from the
remainder and adding 1 to the quotient. The condition “R ≥ D” is the loop’s
terminating condition: when it is no longer true, the loop terminates.
Before the loop begins, the quotient Q is set to 0 and the remainder R is set to N.
This is called initializing the loop. This verbal description is very concise, but
is not as descriptive as the graphic flowchart. However beware! If your
flowcharts are not properly structured, they may also be confusing.
Days
Input Month Leap
Input Year
Month is 400
April, June divides
True Sept, Nov False True Year False
100
Month divides
True Year False
True is Feb False
4
True divides False
Output Year
30 Leap
This Days Days is an algorithm that determines the number of days in any month. It does
algorithm was this first for all the months except February. Finding the number of days in
previously seen February requires determining whether a leap year is involved. Since this is a
in Figures 3.2 fairly complex operation, this part of the Days algorithm is separated from
and 3.14. the main algorithm as a sub-algorithm named Leap. The Leap sub-algorithm
is broken out at the right of Figure 3.40.
Leap decides if a year is a leap year by determining if the year can be divided
evenly by various numbers (400, 100 and 4). Notice that the sub-algorithm Leap
may seem more complex than the “main” algorithm Days.
Decomposing, or breaking up this algorithm into two parts— a main algorithm
connected to a sub-algorithm— is not necessary in this case because the
algorithm is simple. However, adopting this break-out habit early, will be
beneficial when you attempt to develop more complex systems.
Let’s develop an algorithm to play the simple dice game introduced in Figure
3.3. Here are the rules for this game:
The two dice used for this game have each side marked with 1 to 6 dots. When
the two dice are thrown, the resulting sum of dots is a value between 2 and 12.
112 Chapter 3 Algorithms
The flowchart of Figure 3.41 describes this game. Notice that “point count” is
referred to by the variable Point.
MAIN SUB-
algorithm algorithm
Dice
Point is
4, 5, 6, begin
begin More
8, 9, 10
Throw Sum
Throw Total
Sum is
True 7 or 11 False (Total≠ 7)
True and False
(Total≠Point)
Sum is
True 2,3,12 False Throw Total
Set Point
Win Lose to Sum Total = 7
or
Total = Point
True Total = 7 False
More
Lose Win
end
end More
The main algorithm describes the first throw and the sub-algorithm More
describes all subsequent throws (if any). A third sub-algorithm, Throw, is used
several times and is shown in Figure 3.42.
Section 3.5 Control Flow Algorithms 113
Roll Die D1
Sum = D1 + D2
Flowblocks
Flowblock diagrams are an alternative to flowcharts as a way of representing
the flow of control in an algorithm. Flowcharts can be useful when creating and
communicating algorithms; however, flowcharts often do not flow! The lines
joining each box often meanders in complex paths. This makes an algorithm
difficult to understand which destroys the simple beauty of the graphic form.
Also, when creating flowcharts, many dangling lines or arrows can easily get
connected to the wrong boxes, resulting in error-prone algorithms.
Flowblocks (or Nassi-Shneiderman diagrams) are graphic alternatives to
flowcharts. They consist of a series of rectangular boxes which are easier to
draw than flowcharts. The boxes can be placed (connected) only in certain
patterns (usually one above the other so the single exit of one is the single entry
of another), thus preventing the creation of bad structures. So, flowblocks flow!
Figures 3.43 to 3.45 show algorithms illustrating the four basic flowblock forms
of Sequence, Selection, Repetition and Invocation. They are shown next to their
equivalent flowcharts for comparison.
Average Average
Output result
Output the result
114 Chapter 3 Algorithms
Maximum Maximum
Max is X Max is Y
Max is X Max is Y
Output Max
Output Max
True False
R≥D Repetition R≥D
Subtract Decrease R by D
D from R
Increase Q
Increase Q
Pseudocode
Another way of representing the flow of control in an algorithm is
through pseudocode, a mixture of natural language and mathematical
notation independent of any programming language. Figure 3.46 shows
a comparison between the flowblock representation of an algorithm and
its pseudocode equivalent using the Dice Game algorithm as an
example.
116 Chapter 3 Algorithms
More
Win Lose Throws Throw Total
T Total = 7 F
Lose Win
Dice Game
Throw two dice and get Sum
If Sum = 7 or 11
Win
Else
If Sum = 2, 3, or 12
Lose
Else
Pseudocode Set Point to Sum
representation Throw two dice and get Total
While (Total ≠ 7) and (Total ≠ Point)
Throw two dice and get Total
If Total = 7
Lose
Else
Win
End Dice Game
Note: In both Figure 3.46 and 3.47, the vertical lines in the pseudocode are
not essential. They are merely present to help us notice the levels
of indentation (nesting) of the algorithm.
Section 3.5 Control Flow Algorithms 117
Hours ≥ 0
T Hours > 7 × 24 F
T Hours > 60 F
Hours ≤ 40
Set Pay to T F
40 × Rate +
Output 1.5 × 20 × Set Pay to
Error Rate + 2 × Set Pay to 40 × Rate +
Message Rate × Rate × Hours 1.5 × Rate ×
(Hours − 60) (Hours - 40)
Output Pay
Payroll
Input Hours, Rate
While Hours ≥ 0
If Hours > 7 × 24
Output "Error"
Else
If Hours ≤ 60
If Hours ≤ 40
Set Pay to Hours × Rate
Else
Set Pay to 40 × Rate + 1.5 × Rate × (Hours – 40)
Else
Set Pay to 40 × Rate + 1.5 × 20 × Rate +
2 × Rate × (Hours – 60)
Output Pay
Input Hours, Rate
End Payroll
118 Chapter 3 Algorithms
3.7 Glossary
Action: operation or process. Flow of control: sequence of the
actions of an algorithm.
Algorithm: a plan to perform some
actions on some data. Flowblock: a diagram to represent
the flow of control of an algorithm.
Array: a collection of memory cells to
store some data. Flowchart: a diagram to represent
the flow of control of an algorithm.
Assertion: a statement which is
either true or false. Generality: a quality of algorithms
that are applicable to a class of
Black box: the representation of problems.
what a process does, the input(s) it
takes and the output(s) it produces, Glass box: a representation showing
while hiding the internal details of the inner details of a system.
the process.
Hierarchical: a presentation of an
Complete: a property of algorithms algorithm in the form of a breakout
specifying that all actions must be diagram.
precisely defined.
Integer: whole number.
Data type: a description of the kind
of data including the values and the Logical expression: an expression
operations that can be used on them. involving quantities that can have
only two values, True or False.
Data-flow diagram: a diagram
representing the flow of the data Operand: the data element on which
through various processes. is applied an operator.
Decision table: a table listing all the Operator: a symbol describing the
possible combinations of the various operation to apply to one or several
conditions in a problem. operands.
Unambiguous: a property of
algorithms requesting that there is
only one possible interpretation for
the algorithm.
3.8 Problems
3. Time Base
Draw a data-flow diagram showing how to break up a Military time
into hours and minutes past midnight, and then convert this into
minutes after midnight. Military time is in 24 hour notation, where
1430 means 2:30pm. Use Divide, Multiply and Add data flow
components. For example, the military time 1430 is:
14x60 + 30 = 870
or 870 minutes after midnight.
5. Octal Numbers
Octal numbers have a base of 8, with digits 0, 1, 2, 3...7.
Convert the following octal numbers to decimal:
a. 11 b. 23 c. 132
122 Chapter 3 Algorithms
6. Hex Numbers
Hexadecimal numbers have a base of 16, with the values being 0, 1, 2, 3,
4, 5, 6, 7, 8, 9, A, B, C, D, E, F (where A is 10, B is 11, .. F is 15).
Convert the following hex values to decimal:
a. 11 b. CC c. F00
7. Other Bases
Other bases have been used, including 3 (ternary), 5 (quinary), 12, 20,
and 60 (sexagesimal). Where and why would they have been used?
8. Bad Min
What is wrong with the following definition of Min, the minimum of
two values X and Y?
If X is less than Y then Min is X and
if Y is less than X then Min is Y.
9. ISBN Check
Check whether the following ISBN numbers are proper numbers:
a. 0-387-90144-2 b. 0-13-215871-X
c. 0-574-21265-4 d. 0-88236-115-5
e. 3-540-90144-2 e. 1-1-1111111-1
F = 95 C + 32
Chapter Outline
4.1 Preview....................................................................128
4.2 Building Blocks for Structured Programming...............128
The Four Fundamental Forms.....................................128
Connecting Several Forms Sequences and Nests..........131
Deep Nesting............................................................133
4.3 Different Algorithms, Same Problem.........................135
Equivalent Algorithms..............................................135
Alternative Algorithms............................................137
4.4 Top-down Algorithm Design......................................140
Job Description Example............................................144
Change Maker Example............................................145
A Game Example, Fifty.............................................148
4.5 How Data and Algorithms Fit Together....................152
Structured Data........................................................153
Chili Recipe Example...............................................155
Card Trick Example..................................................158
Binary Conversion Example.......................................159
Guessing Game Example............................................160
4.6 Review Top Ten Things to Remember.........................164
4.7 Glossary...................................................................166
4.8 Problems...................................................................167
128 Chapter 4 Algorithm Structure
4.1 Preview
Now that we have just finished learning what algorithms can look like
(chapter 3), you may feel you are ready to begin solving problems by writing
algorithms. However, before you can do that, you need to learn more about the
structure of algorithms.
Structured Programming is a method of building algorithms from a small
number of different basic blocks (or forms) with simple interconnections.
The Four Fundamental Forms (called Sequence, Selection, Repetition and
Invocation) are the building blocks from which all well-structured algorithms
are constructed. Initially, we will use flowcharts to describe these structures;
however, the emphasis will soon shift to flowblocks and then pseudocode.
These last two representations make it impossible to create poorly structured
algorithms.
Top-Down Design is another significant concept that is introduced in this
chapter. It is the process of creating algorithms in stages, by successively
refining them into smaller sub-algorithms, each refinement providing more
details.
The D a t a and the Actions described by our algorithms in this chapter are
common to everyday experience which shows that algorithms need not involve
computers or mathematics. In the chapter that follows this one, computing
algorithms (or programs) will be considered and their data (numbers) will
actually be simpler than the “common” data treated here. For this reason, we
make our data very detailed and explicit here.
A A
A
B
B B
True False C
C T F If C
D
Else
D E D E E
After the actions on either path have been performed, the two paths
rejoin to provide a single exit from the form. This form is sometimes
called the if-then-else form because it is expressed in many
programming languages as:
IF C THEN D ELSE E.
repetition stops and the form is exited. This form is also called the
While-loop form for it is expressed in many programming languages as:
WHILE G DO H.
G
True False
G While G
H
H H
Forms other than these basic four are possible and are sometimes useful, but
they are neither necessary nor fundamental as they can be built from the four
basic forms. These additional forms will be introduced in the next chapter.
mentioned above with another form. Thus, interconnection of the four forms is
possible using one of the following two methods:
• Serial, where one form follows another, like simple actions, or
• Nested, where one form is within the other.
Such interconnections yield a composition where all blocks have a single entry
and a single exit.
Of these two methods for combining forms, the method of nestingis the more
complex. Figures 4.5 through 4.8 show different nests as both flowblocks and
pseudocode. These different nests can easily be identified because the inner
form is shaded in each figure.
Available Service
T F
If Available
Get in line Get in line
While not at head of line
Not at head Wait
Go away Get served
Wait Else
Go away
Get Served
End Service
In Figure 4.6, if the service is available, then the following sequence of actions
are performed:
• Get in line.
• While its not your turn, wait (Repetition form).
• When its your turn, get served.
If the service is not available, the action is to go away.
The Guess algorithm of Figure 4.7 determines an unknown value by a series of
guesses, each guess getting closer to the final correct result. It illustrates a
Selection form nested within a Repetition form. This guessing method will be
used later in the Bisection or Binary Search algorithm.
The Pay algorithm, shown in Figure 4.8, illustrates a deeper level of nesting,
where a Selection contains a Selection within a Selection.
Section 4.2 Building Blocks for Structured Programming 133
T H > 7 × 24 F
Pay
H > 60 If Hours > 7 × 24
T F Error
Else
H > 40
T F If Hours > 60
Double Pay
Else
If Hours > 40
Extra Pay
Else
Regular Pay
End Pay
Deep Nesting
When complex algorithms are represented as either flowblocks or pseudocode,
they are easy to split into their nested components. Figure 4.9 shows an
example algorithm of moderate complexity, represented as a flowblock
diagram with its pseudocode equivalent. We are only concerned here with the
structure of the algorithm and not with the details of the actual conditions or
actions. We have therefore symbolized them by single letters, (A, B, C,…, G)
for the actions and (P, Q, R) for the conditions. Both representations show two
nested components in shaded areas.
T P F If P
A
R
T F While Q
A
B
Else
D
Q If R
C C
Else
B E D
E
G
G
134 Chapter 4 Algorithm Structure
Each of these shaded areas could be given an action name, say W and X, and be
shown as simple actions. This makes for a less complex representation of the
algorithm, as in Figure 4.10.
P If P
T F
R A
T F
W
A
Else
If R
C X C
W Else
X
G
G
T P F If P
Y
Y Z Else
Z
G G
A
A
P
P
T F
B C
B C
Q
Q D
D T F
X D E
R
E F G
Equivalent Algorithms
Before going any further, its is important to realize that two algorithms may
behave the same way, but be structured differently. For example, consider the
problem of determining whether or not a given year is a leap year.
The algorithm Leap1 was considered previously in Figure 3.40, and is shown in
Pseudocode 4.1. It begins with a Selection asking if the year is divisible by 400.
The algorithm has two other Selections nested within it.
All paths in this algorithm can be tested by the four test cases: 2000, 1900, 1984,
and 2001. For example, the year 2001 follows the Else path at each of the three
136 Chapter 4 Algorithm Structure
Selections. The paths taken by the four test cases are indicated by the
assertions at the right of the pseudocode.
The algorithm Leap2, shown in Pseudocode 4.2, works in the opposite direction
to Leap1. It begins with the Selection asking if Year is divisible by 4. Notice
that in this version, the year 2001 requires only one Selection. The assertion on
the right show where each path for the four test cases finish.
These two algorithms (Leap1 and Leap2) are identical in behavior because
they produce the same results in all possible cases. In other words, they are
equivalent. They are, however, different in structure as is shown by the fact
that the same test cases encounter different numbers of selections in the two
algorithms. Which algorithm do you prefer?
The important thing now is not which one you prefer, but that you have a
choice of one or the other. If two algorithms are equivalent in one sense, this is
an opportunity for selecting the optimal one in another sense. The selection
depends on your goals.
For efficiency reasons (minimizing time by having fewer Selections), you might
prefer Leap2 because in most common cases (when the year is not divisible by 4
Section 4.3 Different Algorithms, Same Problem 137
which occurs 75% of the time), the number of Selections is smaller. Only one
Selection is encountered in Leap2, compared to three Selections in Leap1.
Efficiency, or speed, is not always the best goal. Other goals include
convenience, elegance, ease of communication, robustness and some others that
will be considered in later chapters.
We can define yet another algorithm that is equivalent to the Leap1 and
Leap2 algorithms. Pseudocode 4.3 illustrates such an algorithm, Leap3, which
begins with the Selection checking if the year is divisible by 100. The structure
is quite different from the others, because all test cases go through exactly two
Selections; there are no short paths here.
There are still more algorithms that determine whether or not a year is a leap
year, some of these will be considered later. For now, the important idea is not
to concentrate on optimization, but simply to realize that there can be many
different ways of writing an algorithm to solve the same problem.
Alternative Algorithms
There are often alternative ways of creating algorithms, some ways more
convenient or better than others. Figure 4.13 illustrate algorithms that are not
equivalent. Alternative algorithms are not equivalent when the output is not
the same for all possible cases.
138 Chapter 4 Algorithm Structure
A B
C Isosceles
Non-triangle
Right-
isosceles
Isosceles
Triangle
Triangles of various kinds are shown in Figure 4.13. From the non-triangle, we
can see that a triangle is formed only if the sum of the two shorter sides exceeds
the longest side. If the sides are given in increasing order (say A ≤ B ≤ C ), the
condition for a triangle is:
(A + B > C )
Similarly, for an equilateral triangle, the general condition is:
(A = B) AND (B = C)
But if A, B, and C are in order, this condition becomes simply:
(A = C)
For an isosceles triangle, the general condition is:
(A = B) OR (B = C) OR (A = C)
which becomes the following when sides are ordered:
(A = B) OR (B = C)
The point is that if the data values are structured, then this structure could be
used to simplify the algorithm. In the triangle example, if the data has the
structure of being ordered, then simpler tests can be used. There are various
ways to put A, B, and C in increasing order.
One way is to request that the values be entered in increasing order, but we
would have to check to see if these values were entered as instructed, and we
Section 4.3 Different Algorithms, Same Problem 139
would have to repeat this process until the values are entered correctly.
Another way would be to create a sub-algorithm that puts any three input
values into increasing order. We will use the latter method.
Two alternative algorithms for classifying the triangles are shown in
Pseudocode 4.4 and Figure 4.14. In each, the action of sorting the three numbers
A, B, C is labeled as:
Sort sides so that A ≤ B ≤ C
This algorithm, also called Sort3, will be developed later.
The algorithm in Pseudocode 4.4 tests first for the equilateral property, and if
it holds, terminates without indicating that the triangle is also isosceles
although all equilateral triangles are isosceles. In the other cases, the
algorithm checks for the isosceles property, and then for the right triangle
property.
The second Triangle Classification algorithm, shown in Figure 4.14, appears in
two representations: a flowblock diagram and pseudocode to remind us of the
equivalence of these two notations. This algorithm first tests for isosceles
triangles and, if successful, tests for the equilateral property. Therefore, an
equilateral triangle will be shown as having both the isosceles and equilateral
properties. This may be redundant, but sometimes it is clearer than having to
recall that one property implies (or covers) another property.
140 Chapter 4 Algorithm Structure
Input Sides A, B, C
Sort sides so A ≤ B ≤ C
Triangle Classification 2
T A+B≤C F Input sides A, B, C
A ×A+B×B=C× C Sort sides so A ≤ B ≤ C
T F If A + B ≤ C
Output "Not a triangle"
Output Else
"Right" If A × A + B × B = C × C
Output "Right"
(A=B) or (B=C) If (A= B) or (B = C)
T F Output "Isosceles"
Output
If A = C Notice the
Output "Isosceles" Output "Equilateral" two different
"Not a triangle" Else outputs if
once again,
Output "T riangle" an equilateral
A=C
T F End Triangle Classification 2 triangle is
encountered.
Output Output
"Equilateral" "Triangle"
Top-down
Algorithm
Design
Job Computer
Explanation Description Examples
Example
This chart, Figure 4.15, was built top-down: we started with the section title,
then decided that we needed an explanation of the main concept, Explanation,
an illustration that uses a general description of a person’s job Job Description
Example, and some computer-related examples.
The explanation itself was defined as including two small examples, Change
Tire and Compute Pay, and a general view. As you can see, the top-down
approach is useful for planning a solution to any problem. When it comes to
creating algorithms (the Solution Refinement step of our problem-solving
method), we use a similar approach.
Although there are two general approaches to algorithm design, top-down and
bottom-up, we will focus on the top-down approach.
Top-down is an important method for designing algorithms. Simply stated, it
starts at the top, with the most general view—a bird’s-eye view—and then
proceeds to lower levels by successively splitting the larger blocks into smaller,
more manageable blocks. Finally, at the lowest levels it treats the fine
details. The motto of this process is Divide and conquer.
Conversely, the Bottom-up method starts at the bottom with the details—the
worm’s eye view—and then proceeds to higher levels by combining smaller
blocks. Unfortunately, by concentrating on the details first, without the context
provided by the bird’s eye view, the building process may quickly become mired
in the details and unmanageable.
Other names for top-down design are: stepwise refinement, iterative multi-
level modeling and hierarchical programming. It is often pictured with break-
out diagrams as shown in the Figures 4.16 to 4.19.
Tip Use the top down approach to create algorithms. Start from the
general view and progressively refine this view until the level of
detail becomes simple.
Design begins at the top as a single action. Then, the action is broken out or
refined into a small number of sub-actions. These sub-actions are independent of
one another and are not very detailed. This process continues by further
refining each sub-action into sub-sub-actions, gradually including more details.
For example, Figure 4.16 shows the single action Change Tire, broken into the
following three sub-actions:
• Set-up,
• Exchange Tires, and
• Clean Up.
142 Chapter 4 Algorithm Structure
Secure Get the Get Jack Remove Remove Remove Put on Replace Replace Jack car Put away Put away
the car tools spare car up hubcap nuts tire spare nuts hubcap down tire tools
3. Divide each smaller action into even smaller actions, making each
action at this level more precise than those at above levels. Continue
this until you arrive at a complete solution.
At the third level, each of the previous sub-actions are refined further. If any
of these smaller actions were seen as being too complex to be understood, they
too could be broken out into further details. Ultimately, a stage is reached
where every action is small enough to be understood without any further
simplification: this is the complete solution.
Figure 4.17 shows a more computer-oriented example, Compute Net Pay. Once
the last stage of stepwise refinement is reached, we are ready to express the
algorithms in pseudocode, and from there, in some programming language.
Compute
Net Pay
Determine
Find Gross Pay Deductions
The two diagrams shown in Figures 4.16 and 4.17 have been drawn as “true” top-
down diagrams—they start from the top and, as one moves down the page, they
become more detailed. They are just as much break-out diagrams as are the
left-to-right versions. The orientation is incidental; clarity is the real
criterion. In Figure 4.18, we have reverted to the more familiar left-to-right
form to illustrate the top-down design method in a generic manner.
Section 4.4 Top-down Algorithm Design 143
sub-sub-action 1
2
What
sub-sub-action 3
sub-action 1
4
Main 2
Action 5
sub-action n
sub-sub-action z
The Goal Why
z+1
z+2
The above figure illustrates the general break-out process and shows how
answers to four important questions (what, how, when and why) are found using
break-out diagrams:
• What main action is being done? This is shown furthest to the left.
• How is an action done? This is shown broken out at the right of an
action.
• When are the actions done? This is specified by the sequence along the
far right of the diagram.
• Why is a sub-action done? This is found to the left of the action.
Although, sometimes, only the step-by-step sequence of actions is required (the
When at the right), it is important to see the rest of this structure. It is also
very important to realize that each level drawn on the break-out diagram must
be complete. This means that at each level drawn, all of the sub-actions (or
sub-sub-actions) must be present.
Make each level of your break-out diagram complete. If, for example, you
decide to only develop it two levels deep, make sure that the second level
contains all of the actions necessary (even if they are very general) to solve the
problem posed. For example, in Figure 4.17, if we were to only have the first 2
levels, we would need both definitions Find Gross Pay and Determine
Deductions to make the BOD complete.
Don’t leave out any actions at any of the levels of the break-out diagram. In
Figure 4.17, notice that the word “etc.” at the right indicates that this break-
out diagram is incomplete!
The next few pages contain different examples of algorithms created using top-
down design.
144 Chapter 4 Algorithm Structure
Level 0 Job
All customers
Level 1 helped
T F
Clean Attend to
up Customer
Attend to Customer
Take Order
Handle payment
Level 3
Customer accepts
suggestions Takeout Make Change
T F T F
Level 1, in Figure 4.19, is a high level that shows no details, but gives a general
view of how to proceed and refers to the sub-block Attend to Customer at a
second lower level. Then, Attend to Customer is further broken down into three
sub-blocks (or sub-algorithms) Take Order, Fill Order, and Handle Payment.
Finally these three sub-blocks are refined in level 3.
If the detail is still not sufficient, then more levels must be created. For
example, the last sub-algorithm, Handle Payment, refers to another sub-
algorithm Make Change, which could be further refined at level 4 (not shown
in Figure 4.19). To reveal how the change would be made, this Make Change
sub-algorithm will be discussed in detail later.
The top-down method forces us to devise a general overview of a system before
getting into its details. It also shows the segmenting of a larger system into
smaller, independent modules such as Take Order, Fill Order, and Handle
Payment. It is this segmenting that makes the complexity more understandable
and manageable.
Note that an The order-taker algorithm of Figure 4.19 referred to the sub-algorithm Make
algorithm similar Change which, as the name suggests, makes change for a customer. We will
to Make Change further illustrate the top-down algorithm design process, by developing this
was previously Make Change sub-algorithm using only pseudocode. Notice that the difference
shown in between an algorithm and a sub-algorithm is slight; a sub-algorithm is simply
Chapter 3 an algorithm that can be invoked by other algorithms.
(Figures 3.32 and The sub-algorithm, Make Change, will make change from an amount tendered
3.33). for an item whose cost is given in cents. At the very top level, there is a simple
action Make Change.
By itself, this does not help very much, but it does provide a start from which
to develop the next level, which consists of a sequence of two sub-actions. The
next step is to expand these two sub-actions. As indicated by their names,
Compute Change computes the amount to be returned to the customer and Give
Change produces the proper coins. Expanding Compute Change is easy and
shown in Figure 4.20.
146 Chapter 4 Algorithm Structure
Compute Change
Input Cost
Input T endered
Set Remainder to T endered – Cost
Make Change End Compute Change
Compute Change
Make Change Give Change
End Make Change Give Change
While Remainder > 0
Output a penny
Decrease Remainder by 1
End Give Change
The rest of this section will be used to develop the Give Change algorithm, as
there are many ways to solve this problem. One way, shown in the shaded box
in Figure 4.20, is to output Remainder all as pennies. If the cost is 1 cent and the
amount tendered is a dollar, this means that 99 pennies are output! This is one
solution that works, is correct, complete and short.
This solution is, however, not practical or convenient because giving a customer
change in pennies creates “ill will”. This means that Pseudocode 4.8 must be
replaced with a solution more beneficial to the customer.
Another common way of making change involves adding up coins from the
amount Cost up to the amount Tendered. This method is often preferred by
people who wish to avoid computing the remaining amount because they prefer
not to subtract. This method will be treated in Chapter 5.
Yet another way of making change is to modify the first solution in Pseudocode
4.8. The modified version is shown in Pseudocode 4.5.
Since we wish fewer coins to be output, we first consider large coins, quarters,
followed by dimes, nickels and then pennies. What we do for each coin is a
detail not considered at this level. The sub-actions will be “opened up” at the
next lower level.
Assertions are very useful to list along with algorithms, here (Pseudocode 4.5)
they are shown in braces at the right of the algorithm. For example, at the
Section 4.4 Top-down Algorithm Design 147
The sub-actions from Pseudocode 4.5 are broken down in Pseudocode 4.6 as
follows:
• Give Quarters, the first sub-action, is broken out into a Repetition form,
because more than one quarter may be output. While the Remainder is
greater than 25, a quarter is output and the remainder is decreased by
25. This continues until the Remainder is less than 25 as indicated by
the assertion {Remainder < 25}.
• Give Dimes, the second sub-action, is broken out in a similar way to
Give Quarters. When its actions are done, Remainder is less than 10 as
shown in the assertion.
• Give Nickels, the third sub-action, is slightly different from the
previous two because at most one nickel can be output. If Remainder is
greater than 5, a nickel is output and Remainder is decreased by 5.
• Give Pennies, finally is done with a Repetition similar to the first two
sub-actions, because more than one penny may be output.
148 Chapter 4 Algorithm Structure
To show the equivalence in the behavior of these two versions, assertions are
also indicated. Initially the Remainder is less than ten. Considering the
Repetition form (right), if Remainder is not greater than or equal to 5, then
nothing is done. When you apply this same condition to the Selection form,
nothing is done as well. This means that when Remainder is not greater than
or equal to 5, then both forms are equivalent.
If Remainder is greater than or equal to 5 (and less than 10 as the assertion
states), then the body of the Repetition is performed (a nickel output and
Remainder decreased by 5). Once the Repetition form has been performed once,
the new value of Remainder is now less than 5, so no further Repetition is
possible. This again is equivalent in behavior to the Selection form at the left.
Hence these two sub-algorithms, in the context given by the assertions, are
equivalent in behavior.
As with all algorithms, modifications to the Make Change algorithm are
possible. For example, it could be generalized by allowing the input of any
amount to be tendered rather than at most a dollar—this is assumed by the fact
that no bills are considered in the change making.
This algorithm could also be extended to more denominations (fifty-cent coins,
dollar and two-dollar bills), and it could be made foolproof by testing that the
input values are in the proper range (cost is positive, and amount tendered is
greater than or equal to the cost). Notice that the block form suggests that
modifications can be done by inserting or substituting blocks, which encourage
“modular” design. More of these equivalent substitutions will be considered in
later chapters.
Games may involve chance (using dice, cards, pebbles, and so on) or they may
involve skill (using balls, bats, arrows, targets, and so on) or both. Here we will
concentrate on a simple game involving dice. Dice games have a long history;
they have been found in ancient Egyptian tombs dated 1500 BC. The earliest
dice were probably a cube shaped bone, the astragalus, from the ankle of a
sheep.
Dice usually consist of cubes (of bone, ivory, sugar, etc.) made with 1 to 6 dots on
a face, so that opposite sides add up to 7. When a die is rolled, each face has
an equal chance of landing face up. When two dice are thrown, some sums are
more likely than others. For example, a sum of two can be formed in only one
way (1 + 1), whereas the sum of 7 can be formed in many ways (1 + 6, 2 + 5,
3 + 4, ...).
Fifty is a dice game played by two people with two dice. It is described in
Figure 4.21.
Set up initializes the scores, Play goes through a game and Evaluate decides
the outcome. These three sub-actions are explained as follows:
• Set up simply sets the two scores Score1 and Score2 to zero. Notice
that the order of playing is not important; the player who goes first
does not have an advantage, since both players get a turn during every
round. In other games, the setup is often more complex.
150 Chapter 4 Algorithm Structure
• Play loops through a round during which each person gets a turn, and
this continues as long as neither player has a score of 50 or more.
• Evaluate will choose the winner. It first determines whether there is a
tie. If there is no tie, then at the next level, the winner is determined.
At the second level of development, the algorithm is shown in Pseudocode 4.9.
The sub-algorithm Turn of Player must also be broken out further into the
following stages or levels:
• First, the dice are thrown to get DiceA and DiceB using the Throw sub-
algorithm.
• Then, a Selection determines whether there are any Doubles. For
example, if the scores DiceA and DiceB are equal, another sub-
algorithm determines whether they are a Good Double or not.
At this level, the sub-algorithm Turn of Player is shown in Pseudocode 4.10.
The sub-algorithm Doubles may then be expanded according to the rules of the
game so that the sub-algorithm Turn of Player becomes Pseudocode 4.11.
The only other sub-algorithm left to be expanded is No-Tie and, when this is
done, Evaluate becomes the sub-algorithm in Pseudocode 4.13.
We now have all the parts of algorithm Fifty and we can produce the final
solution by putting them all together. The algorithm, fully expanded, is shown
in Pseudocode 4.14.
Note: Whether you are a beginner or not, you will always need method.
Incidentally, the top-down method did not come into being with computers. It
has been known for hundreds of years. René Descartes, the French philosopher
and mathematician, wrote in 1637 in his Discourse on Method,
Divide each difficulty into as many parts as possible
so that it may be overcome more easily.
Starting with the simplest and easiest to understand,
consider things in order, moving by degrees
to the most complex.
Structured Data
Emphasis so far has been on the flow of control, or sequence of actions and the
structure of this flow. Our data have been simple Integers or Real Numbers, but
data can also be structured. As with algorithms, structured data can be
described by break-out diagrams.
Section 4.5 How Data and Algorithms Fit Together 153
Ace
Suit 2
3
clubs
4
diamonds
hearts
spades
10
Jack
Queen
King
In Figure 4.24 we show again how a year can be split up into months, which are
split into days and then into hours. Since there is not a constant number of days
in each month— it varies from 28 to 31— the last number in the second level is
represented by an “n”.
154 Chapter 4 Algorithm Structure
Jan Month
Feb
day 1 Day
Mar
day 2
hour 1
. 28 - 31 2
. 24
Dec hour 24
n
Organization First
Initial
person 1
Last
person 2
person 3 Person Number
street
name Name
city/state
person k address
country
attributes
code
person n
Id number Year
birth Month
seniority Day
vehicles
sex
Structured data of the type in Figure 4.25 can also be represented in a linear
form using indentation. Each level is indented from the preceding level, as
shown in the representation of the previous example in Figure 4.26.
Section 4.5 How Data and Algorithms Fit Together 155
Person 1:
Name
FirstName : John
Initial : M
LastName : Motil
Address
Street : 1234 Main Street
City/State : Northridge, CA
Country : USA
Code : 91330
Attributes
IdNumber : 123-45-6789
Birth
Year : 2000
Month : Feb
Day : 29
3 pounds beef
Secret Sauce 2 pounds beans 2 pounds of tomatoes
Place all ingredients in large bowl 2 teaspoons salt 2 teaspoons salt
_1 teaspoon paprika
Mix thoroughly 4
_1 teaspoon cayenne
1 cup Secret Sauce
End Secret Sauce 8
6 whole cloves
2 bay leaves
Chili recipe 2 tablespoons chili powder
Wash beans
Add 2 quarts water
Soak overnight
Add salt
While not tender
Simmer
{finished simmering}
Drain the water
Brown the meat
Add Secret Sauce
Simmer 1 hour
If too dry
Add water
End Chili recipe
water salt
wash
mix
soaked
beans soak
add
tenderize
brown drain
combine
water simmer
add
To understand an algorithm, you might find that sometimes the flow of actions
is more useful, while at some other times, the flow of data is more important.
In this example, we have overemphasized the data to remind you that the role
of data in an algorithm is of equal importance as the role of actions. Our next
examples will be more action oriented, but we will define their data as well.
For more Now, let’s look at an algorithm that uses structured data. This example
information on involves a card trick.
arrays, see 21 playing cards are placed face-up in 7 rows and 3 columns, as shown in Figure
Chapter 8. 4.29. Such a data structure is often called an array. The cards in any column are
overlapped to maintain their order, and to make a column easy to pick up
quickly.
Once the cards have been arranged in this manner, perform the following steps:
1. Ask someone to select one of the 21 cards, without picking it up.
2. Without pointing at the card, have the person indicate the column that
contains the selected card.
3. Pick up the columns in this order:
• A non-indicated column,
• The indicated column
• The other non-indicated column
4. Deal out the cards in its familiar 7 rows by 3 column structure, row by
row!
5. Repeat steps 2 through 4, twice.
6. Finally, count off 10 cards. The 11th card will be the card that the
person selected.
This process is entirely described by Pseudocode 4.15. Try it. Notice that it
does not take any knowledge or skill on your part, just the ability to follow
directions.
Section 4.5 How Data and Algorithms Fit Together 159
For example, let us convert the decimal number N = 13. Figure 4.30 contains a
representation of the variable N (left) showing its successive values as the
algorithm is performed (right).
6
2
= 3 with remainder (output) of 0
N = 13 6 3 1 0
3
1
= 1 with remainder (output) of 1
1
2
= 0 with remainder (output) of 1
As Figure 4.30 shows, the binary equivalent of 13 is 1101, or the value of the
outputs taken in reverse order.
There are many methods to convert decimal numbers to binary. Notice that this
method (Pseudocode 4.16) is very different from a previous method used in
Chapter 3, which divided the number N by successively smaller powers of 2 (8,
then 4, and finally 2).
Note: This method of halving the correct range of values at each try is
called Bisection or Bracketing. It will also be useful later in solving
equations, and efficiently searching through data.
The algorithm Guesser, Figure 4.32, describes one systematic way of making
guesses, and could be followed by the player trying to guess the Challenger’s
Section 4.5 How Data and Algorithms Fit Together 161
number (between 0 and 100). It simply keeps track of the high and low values
that were guessed, and chooses the middle value as the next guess. The middle
value is the average of these two values. Depending on the outcome of the
guess, one of the limits is changed (to this middle value).
1. Number = 31
2. Count = 1
3. High = 100
4. Low = 0
5. Try = (High + Low)/2 = 50
6. Guess = 50
7. Guess ≠ Number
8. "High"
9. Count = 2
10. Try is not correct
11. Try is high
12. High = 50
13. Try = (50 + 0)/2 = 25
14. Guess = 25
15. Guess ≠ Number
16. "Low"
17. Count = 3
18. Try is not correct
19. Try is low
20. Low = 25
21. Try = (50 + 25)/2 = 37
22. Guess = 37
23. Guess ≠ Number
24. "High"
25. Count = 4
26. Try is not correct
27. Try is high
28. High = 37
29. Try = (37 + 25)/2 = 31
30. Guess = 31
31. "Congratulations"
32. "Count = 4"
In the above figure, the number was discovered in just 4 guesses. In general, it
would have taken at most 7 guesses. This is because the right answer always
lies between the values of High and Low, this is the “Range”. The Range starts
at 100 and is halved each time a guess is made. After seven tries, the range
will be 1, which must be the right answer. Often, the right number will be tried
before seven guesses. The algorithms will terminate earlier. In n tries, this
bisection algorithm can select between 2n numbers. So in ten tries, it can guess
any number between 0 and 1023. Using this technique, if the Challenger
selected a number between 0 and 1 000 000, the Guesser would take at most 20
tries to find it!
Section 4.6 Review: Top Ten Things to Remember 163
9. Actions and Data are both considered in this chapter, but the emphasis
is on the structure of actions (control flow). To keep the two in
perspective, stepwise refinement can also be applied to data with
break-out diagrams.
10. Data-flow diagrams emphasize data rather than actions and provide
another approach to the design of solutions. They are a complement of
the control flow diagrams (flowblocks and pseudocode).
Section 4.7 Glossary 165
4.7 Glossary
Abstraction: A method of conceptual Modular design: Software design
simplification through the where the program is divided into
suppression of details that are separate sections or modules that are
irrelevant to the application of the relatively independent so that any
abstraction. modifications to the program tend to
be confined to only a few modules.
Action: some small process applied to
some data. Nesting: The inclusion of a given
form into another.
Array: A data organization by rows
and columns. Record: An aggregate of data values
of possibly different types arranged
Assertion: A statement that is either in a hierarchical manner.
true or false.
Repetition: One or more actions
Binary search: A search algorithm repeatedly performed a number of
that repeatedly halves the area of times. One of the Four Fundamental
search until it is reduced to one Forms.
element, the object of the search or it
is found that the item is not present in Selection: A condition or decision
the data being searched. which chooses an action to be
performed. One of the Four
Bisection search: Synonym for Binary Fundamental Forms.
search.
Sequence: One of the Four
Data: Something given or measured. Fundamental Forms.
Data Structure: Organization of data Structured programming: A technique
elements grouped for a given purpose. for organizing programs by building
Divide and Conquer: A method to them from a few basic blocks like the
break the complexity by considering Four Fundamental Forms.
small parts of a problem. Structured Data: data made of
Four Fundamental Forms: The several parts.
Sequence, Selection, Repetition and Top-down: A way of defining things
Invocation forms; each of which has starting at a general level and
a single entry point and a single exit descending gradually into details.
point. These four forms together are
sufficient to build all programs.
4.8 Problems
1. Change Change
The change-making program of Pseudocode 4.6 can be modified in many
ways. One way is to anticipate problems in the input values and act
accordingly. For example, the input cost may be negative, or it may be
more than the amount tendered (one dollar in this case). Draw a
flowblock diagram to take this situation into account.
2. Friendly Time-out
The following algorithm accepts input of a time in 12-hour digital form
as hours H (ranging from 1 to 12) and minutes M (ranging from 0 to 59). It
outputs the time in a friendly form as shown on the following flowblock
diagram. However, there is an error in this algorithm; it does not work
for some values. Test this algorithm and find the error.
Problem 2
Input H, M
True False
Output H " O'Clock" M=0
True False
Output "Half past " H M = 30
True False
Output M " minutes after " H 0 < M < 30
3. Dispense 15
The given flowchart describes a machine that accepts a sequence of
input coins (nickels and dimes only) and outputs a 15-cent item and the
appropriate change of 5 cents, or zero.
This algorithm consists of a “complex” nest of Selection forms. Draw
this in the form of a flowblock diagram. Then create another simpler
algorithm by using a Repetition form.
Problem 3
Input C
True False
C=5
Input C Input C
True False
C=5
Output Output
Item Item
Output
Item
Output
Change
4. Chili Block
Convert the Chili recipe pseudocode, in Figure 4.27, into a flowblock
diagram.
5. Convert
Convert the pseudocode for the Triangle Classification 1 algorithm
shown in Pseudocode 4.4 into a flowblock diagram.
168 Chapter 4 Algorithm Structure
6. More Compare
Extend the Compare algorithm of Figure 4.5 so that it indicates also
whether the input values are constant, non increasing (for example 3, 2,
2), non decreasing, increasing then decreasing (like 1, 3, 2), decreasing
then increasing.
8. More-Time
Create an algorithm to convert a given number of seconds S (say one
million) into the equivalent number of days D, hours H, minutes M and
seconds S. Represent this algorithm in two different ways, in
pseudocode similar to Make Change and as a data-flow diagram.
9. Pints
Create an algorithm to convert a given number of pints into its
equivalent number of gallons, quarts and pints. Note: 4 quarts = 1
gallon, 2 pints = 1 quart.
10. Romanums
Create an algorithm to convert Arabic numbers (ordinary positive
integers) into their corresponding Roman numbers. Assume inputs less
than 300 at first, then extend to 3000.
a) if, at most, four consecutive occurrences of a single symbol are
allowed, where 4 is IIII, 90 is LXXXX and 1984 is
MDCCCCLXXXIIII.
b) if, at most, three consecutive occurrences of a single symbol are
allowed where 4 is IV, 90 is XC and 1984 is MCMLXXXIV
Note: I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000
Hint: See the Change Maker problem.
Section 4.8 Problems 169
11. Dispense 7
Create an algorithm to dispense items costing 7 cents. The inputs are
sequences of nickels or pennies only, with only one coin entered at a
time. The outputs are an item and appropriate change.
Dice Problems
Create algorithms (top-down and structured, of course) describing the following
dice games. The problems involving archery and darts are really disguised dice
problems. The dice problems could also be translated into similar games of skill
rather than games of chance.
170 Chapter 4 Algorithm Structure
17. Dice 21
The game of Dice 21, or dice blackjack, is played with one die and any
number of players. Each player in turn rolls the die until the
accumulated sum is 16 or over. If the sum is over 21, the player “goes
bust” and is eliminated from the game. The winner is the player (or
players) whose score is closest to 21 after all players have had a turn.
The players shoot one arrow each. The one who comes closest to the
center becomes the “stopper”, and the other becomes the “scorer”. They
then take turns, each shooting three arrows per turn. The stopper aims
to close a sector by hitting it. The scorer aims to get as many points as
possible, before all sectors are closed. When all sectors are closed, the
players swap roles. The winner is the player who scores the highest.
172 Chapter 4 Algorithm Structure
19. Darts
Create an algorithm describing the following simple dart game. It
involves two people throwing darts at a circular target that is divided
into different scoring areas. The first turn goes to the player who
throws a dart closest to the center of the target. Each player throws
three darts in a turn, starting with a given score (say 101) and attempts
to reduce the score exactly to zero by subtracting points corresponding to
where the darts land. If a player’s score would take the player past
zero, the score does not change. The first player to reach zero wins.
Section 4.8 Problems 173
174 Chapter 4 Algorithm Structure
Chapter Outline 175
Chapter Overview
5.1 Preview....................................................................176
5.2 Programs...................................................................176
Data for Programs.....................................................176
Actions In Programs...................................................179
5.3 Sequence Forms..........................................................182
More Programs Using the Sequence Form.....................183
5.4 Selection Forms.........................................................185
Simple Selection Forms.............................................185
Proofs of Equivalence for Simple Selection Forms........187
Larger Selection Forms..............................................189
Proofs of Equivalence for Larger Selection Forms.........192
Nested Selections......................................................194
Logical Conditions....................................................198
Using Logical Conditions to Simplify Selections.........201
5.5 Repetition Forms.......................................................203
The Repeat-Until Form.............................................203
The Disadvantages of Using the Repeat-Until Form..206
The While Loop Form...............................................209
Getting Insights Using Traces and Invariants............212
5.6 Invocation Forms.......................................................219
Seconds Example.......................................................221
De-militarize Time Example.....................................222
5.7 Improving Programs..................................................224
Nested Loops and Selections......................................224
Using Invariants.......................................................229
5.8 Review Top Ten Things to Remember........................234
5.9 Glossary...................................................................235
5.10 Problems...................................................................236
176 Chapter 5 Algorithm Behavior
5.1 Preview
In order to concentrate on the algorithm actions, we will now view d a t a
uniformly as boxes containing the various kinds of values, like Integers, Real
Numbers, Logical values, and so on. Actions, including arithmetic operations,
input and output operations, and assignments, will be limited to manipulations
of these simple data values.
The Four Fundamental Forms (Sequence, Selection, Repetition and Invocation)
will be considered here in more detail, from a behavioral point of view. This
means that we will concentrate on the dynamic aspect of an algorithm. In other
words, what happens in the computer as it carries out or executes the
algorithm. This dynamic view of an algorithm is in contrast to the static view,
which corresponds to the algorithm on paper or on the computer screen.
As we study the behavior of an algorithm, we will be concerned with all
possible paths that can be followed through its actions. We will show and
prove the equivalence of behavior of certain algorithms.
Although very simple, the Sequence form is extremely important, and will be
considered again briefly.
Selection Forms, which we have already introduced, will be reviewed in this
chapter and the equivalence of several different selections will be studied and
verified using symbolic logic truth tables.
The behavior of Repetition Forms is considerably more complex than other
forms. In fact, Repetition Forms are the most complex form. We will describe
them using two-dimensional traces, so as to yield insight into their dynamic
behavior. Certain assertions about the state of a program are not changed by
executing the body of a loop; these are known as loop invariants and are briefly
introduced. Later in this chapter, we will use loop invariants to improve
programs.
We can view Invocation Forms as data-flow diagrams or black boxes, in order to
provide an easy and early introduction to an otherwise complex mechanism.
Here, we limit our consideration of nested forms to simple nests. In the
subsequent chapters we will consider larger programs and their design.
5.2 Programs
21 Age
-500 Balance
0 Count
0205080057 ISBN
1984 Year
123456.78 Quantity
0.125 Rate
• Our next data type, the Character type is used in the process of
communication. A character is any single letter, digit, punctuation, or
other symbol from a keyboard. The character type would correspond to
a box, holding only one single symbol selected from dozens on the
keyboard as shown in Figure 5.4. Character values will be indicated
within single quotes, to eliminate confusion between values (such as ‘A’)
and identifiers (such as A).
'A' grade
'J' Initial
'.' Period
Section 5.4 Selection Forms 187
Equivalent
At the left and right of Figure 5.15 are two algorithms involving two Selections
based on age and sex. There are three actions Aged, Boy, and Child
corresponding to three categories with the same names. These algorithms could
be used within a larger algorithm where Aged, Boy, and Child are actions that
update counters. For example, every girl could cause a Children variable to be
incremented, and every boy could cause both the Boys and Children variables
to be incremented.
These two algorithms can be proved to be equivalent in behavior by creating a
table of all possible combinations of conditions, and testing if the resulting
actions are the same for both algorithms.
The truth table in the center of Figure 5.15 shows the table of combinations
corresponding to the two algorithms. In all four cases the two algorithms
behave identically, and are thus equivalent. Either one of these algorithms
could be substituted for the other.
You may have noticed the difference between the two algorithms: the first one
uses nested Selections while the second one uses a sequence of two Selections.
Which algorithm should we prefer? The answer is not always clear.
Sometimes sequential Selections are preferred over nested Selections. Figure
5.16 shows another example where nested Selections are compared with
sequentially connected Selections.
F F 18 none none
If Age < 12 If Age < 12
Increment Low F T 25 High High
Else Increment Low
If Age > 21 If Age > 21
T F 10 Low Low Increment High
Increment High
T T ?? ??? ???
Equivalent
188 Chapter 5 Algorithm Behavior
The table at center of Figure 5.16 shows all four combinations of the possible
conditions. The first combination includes all ages from 12 to 21 inclusive,
while the second includes all ages greater than 21, and the third includes all
ages less than 12. The last combination, however, (Age < 12 and Age > 21) can
have no age that satisfies it; this logical combination is not physically
possible and cannot happen, so it need not be considered. All of the other
conceivable combinations are possible, and produce identical results, so the
algorithms are equivalent.
The test values shown are 18, 25, and 10, and are sufficient to trace all three
paths through these two algorithms (Increment Low, Increment High, do
nothing) to prove their equivalence. Other test values could also be used. For
example, the test value of 18 corresponds to the condition where (Age < 12) is
False and (Age > 21) is also False, or to the equivalent condition where (Age ≥
12) and (Age ≤ 21) is True. So, any age between 12 and 21 inclusive can replace
the test age of 18. Similarly, the test value of 25 can be replaced by any value
larger than 21 and the test value of 10 can be replaced by any value smaller
than 12 (but not by a negative age!).
F F none none
If Cond1
If Cond1
Action1 F T Action1 Action1 Action1
Else
If Cond2 If Cond2
T F Action2 Action2 Action2
Action2
T T Action1 Action1,Action2
Not Equivalent
Figure 5.17 shows yet another set of examples that have a form similar to the
examples in Figure 5.16. Nested Selections are compared with two Selections
connected sequentially. The two pairs differ, however, in their conditions. The
table of combinations, at the center of Figure 5.17, shows one combination (the
last) where the behaviors differ. This one case is sufficient to prove that they
are not equivalent.
All the above examples involved only two Selections, so at most four
combinations needed to be tested. If an example involved three such conditions,
then there would be eight combinations to test. We will consider such an
example next.
True and False, or Yes and No. Let’s define an algorithm to act on three binary
variables A, B, and C (each having the value 0 or 1) and to output their
majority value. A table describing the Majority algorithm is shown in Figure
5.18.
I A B C M
0 0 0 0 0
1 0 0 1 0
2 0 1 0 0
3 0 1 1 1
4 1 0 0 0
5 1 0 1 1
6 1 1 0 1
7 1 1 1 1
We first In the above table, the combination of values (1, 0, 1) corresponds to the third
encountered this line from the bottom of this table, which has an index number of 5. There are at
algorithm in least six possible algorithms that can produce the results specified by the
Chapter 3, table. These algorithms are shown below in Pseudocode 5.3 through 5.8,
Figure 3.16 Majority Method 1 through Majority Method 6.
This second version simply accumulates in variable Sum the number of times
the value of 1 appears in the three cases. Then, if the value of Sum is greater
than or equal to 2, the value of Majority is 1, otherwise it is 0.
This third algorithm is shorter and simpler. It has a single but complex
Selection, which asks if the sum (A+B+C) is greater than or equal to 2 and if so,
the Majority is set to 1, otherwise it is set to 0.
Section 5.4 Selection Forms 191
The fourth method (Pseudocode 5.6) involves three Selections. The numbers in
the assertions show the indices of the 8 combinations indicating the paths
taken. Take note that all paths are not equally likely; half of the
combinations take the path that includes the last pseudocode statement.
The fifth method involves nested Selections, all testing for the equality of
variables. Essentially, if any two of the three values are equal, then the value
of Majority is that value.
This last algorithm, Majority Method 6, is the simplest. It first asks if A=B,
and if so, the value of Majority is A (or B). Otherwise A and B “cancel one
another” leaving C to determine the Majority.
The table in Figure 5.19 contains a column labeled Left, which shows the values
of Majority evaluated by the algorithm on the left. Similarly, a column
labeled Right shows the values assigned by the algorithm at right. If these
two “output” columns had the same value for all combinations, then the two
algorithms would be equivalent.
However, they behave differently in one case (shown shaded), and that is
sufficient enough to disprove the equivalence of these two algorithms. In fact,
only one of the two algorithms of that figure (the one on the left) is actually a
Majority algorithm. Notice that it is a modification of Majority Method 4
from Pseudocode 5.6.
The algorithm in Figure 5.19 involves three binary variables and requires 23
rows in the table. An algorithm which involves n binary variables, requires 2n
rows. So for 10 binary variables, we would need 1024 rows and for 20 variables,
over a million rows. When the number of variables becomes large, this
exhaustive method is exhausting!
Figure 5.20 shows two algorithms for computing the Maximum of three values
X, Y, and Z. Let’s check if the two are equivalent. If the values of X, Y, and Z
are limited to binary values, then eight combinations would be required for the
proof of equivalence. However, if X, Y, and Z are integers, it seems as though we
would need to test for all possible combinations of three integer values—an
infinite number—to show equivalence. Luckily, since we are only interested in
relative values, we can show equivalence by taking all possible orderings for X,
Y, and Z. Assuming that the three values are all different, there are only six
possible conditions, as shown in the table in Figure 5.20. Evaluating both
algorithms for all of these combinations yields an identical behavior.
Another, less abstract, proof of equivalence can also be given using six sets of
test values. We have chosen 1, 2, 3 as test values. Any other set of test values
would have been just as good.
For example, the combination 10, 20, 300 gives the same results as 1, 2, 3, as does
any other increasing sequence of three values. A proof of equivalence is given in
the following table:
194 Chapter 5 Algorithm Behavior
If the problem specification allowed for some of the values to be equal, then
more sets of combinations should be tested (such as 2, 1, 1 or 1, 2, 1, and so on).
Can you guess how many?
Nested Selections
In the previous sections, we saw a few examples of nested Selections. Let’s look
closer to more examples of nested Selections in order to understand them better
and to see if it’s possible to simplify them.
The following Grades algorithm, which assigns grades to students based on
their percentage scores, might not be the best way to assign grades, but is a good
example to illustrate many nesting concepts. The specification for the Grades
algorithm is as follows:
Grades:
The following algorithms, (Pseudocode 5.9 to 5.12) solve this problem in four
different manners (Grades 1 to Grades 4).
The first method, Grades 1, tests the largest percentage range first, and tests
each range in descending order until the proper range is found. Once the proper
range is found, the corresponding grade is output.
Section 5.4 Selection Forms 195
Unlike the previous three methods, which involve nested choices, the fourth
method (Grades 4 in Pseudocode 5.12) involves no nesting but a series of choices.
This method is often simpler to program in older programming languages which
have a limited IF structure. Notice that this method requires the assignment of
character values, while none of the other methods uses assignments.
The four methods given here are not all the possible methods for the Grades
algorithms; at least two other different structures are also possible.
Whenever we define an algorithm, we should test it. This is in fact step 4 and
For more details part of step 5 of our problem solving method. Testing algorithms is extremely
on the problem important as errors can creep up even in simple algorithms like our Grades
solving method, algorithms, and in fact, there is an error in one of them.
see Chapter 2,
Section 2.2. Our testing strategy is always to include a test value in each of the possible
ranges as well as “limit” values. Here, the ranges are defined by the five
Section 5.4 Selection Forms 197
grades and suitable test values would be 95, 85, 70, 50, and 25. Examples of limit
values are 89, 90, and 91.
A good testing strategy will also include extreme or out of range values, like a
negative grade, or a grade that is greater than 100. Using these values, you
will find that the algorithm Grades 3 (Pseudocode 5.11) contains an error for
grades higher than B! Constant 30 in the last subtraction should be 10!
These Grades algorithms could be improved so that the grade boundaries (50,
60, 80, 90) may be more easily altered. The constant values representing these
boundaries could be replaced by other symbolic values (LowD, LowC, LowB, and
LowA), to which are assigned the constant values at the beginning of the
algorithm. Then, if the grading “boundaries” change, they could be easily
modified in one place, at the beginning of the algorithm, rather than at various
places throughout the algorithm.
The efficiency of algorithms describes the speed of their operation. This speed,
or time to execute an algorithm, could be determined by counting the number of
operations (such as Selections). For example, the last algorithm outlined in
Grades 4 always requires four Selections; every path through this algorithm
must go through every Selection. The other three algorithms require four
Selections only in the worst case. In general they involve fewer Selections.
Therefore, the fourth algorithm is less efficient than the others.
An analysis of efficiency also depends on the input values provided. For
example, given an input value of 95, Grades 1 requires only one Selection,
whereas Grades 2 requires four. Such an analysis should not be done for just one
value, but for a collection of values. For example, if the grade distribution is
high, then Grades 1 would be faster on the average. On the other hand, if most
grades were around 65, a better algorithm for such a distribution would test first
for C grades.
198 Chapter 5 Algorithm Behavior
Logical Conditions
For more The conditions we have used in our Selections are usually called Logical
information on conditions because they can only be true or false. The conditions we have used so
Logical far were simple, but we can define more complex conditions by using the three
conditions, see main connectives AND, OR and NOT, which we already encountered in
Logical Data- Chapter 3, Figures 3.27 and 3.29. Their behavior is specified by the truth
Flow Diagrams in tables of Figure 5.21.
Section 3.4. De
Morgan’s First Figure 5.21 Truth tables
and Second Conjunction Disjunction Negation
Laws are also AND OR NOT
mentioned
P Q C P Q D P N
there.
F F F F F F F T
F T F F T T T F
T F F T F T
T T T T T T
Rule 2
P Q P Q
OR NOT
R R
DeMorgan’s Rules can also be used to negate a formula. To negate the AND of
two variables, you simply OR the two negated variables. You can see this at
the bottom of Figure 5.23. For example, the condition for remaining in a loop is
the opposite of that for leaving a loop. In the simple Dice game of Chapter 3
(Figure 3.41), this was the condition for looping (and throwing again):
(Total≠7) AND (Total≠Point)
The assertion after leaving the loop was just the opposite:
(Total=7) OR (Total=Point)
This results directly from DeMorgan’s second rule as the condition for leaving
the loop is the opposite (negation) of the condition for looping:
200 Chapter 5 Algorithm Behavior
F F T T T F T
F T T F F T F
T F F T F T F
T T F F F T F
Equivalent
In this figure, the four rows correspond to the combinations of the possible truth
values of P and Q. The demonstration proceeds column by column (in the
numbered order). Finally columns 3 and 5, corresponding to the left and right
sides of DeMorgan’s first rule, are seen to be identical.
Logical conditions which involve n logical variables can be proven equivalent
by truth tables which contain 2n rows. For example, let us consider the
following logical distributive law:
A AND (B OR C) = (A AND B) OR (A AND C)
As these formulas involve three logical variables, there are 23 or 8 possible
combinations. The left side and right side of the expression are evaluated, and
found identical in all cases as shown in Figure 5.25.
A B C Left Right
F F F F = F
F F T F = F
F T F F = F
F T T F = F
8 possible combinations
T F F F = F
T F T T = T
T T F T = T
T T T T = T
Notice that this distributive law for logical operations is equivalent to the
distributive law of algebra:
Section 5.4 Selection Forms 201
a(b + c) = ab + ac
There are two possible paths through this algorithm leading to a leap year:
when Y is divisible by 400, or when Y is not divisible by 100 and is divisible by
4. Putting this symbolically leads to one larger condition we will call C1 where
the condition “Y D 4” means that Y is divisible by 4.
C1 = (Y D 400) OR (NOT(Y D 100) AND (Y D 4))
True False
C B
The body of the The body of the
loop may never loop is executed
B at least once.
be executed, not True False
even once. C
Notice that the body of the Repeat-Until loop is always executed at least once,
and that the same is not true for the While loop. Another difference between
the two forms is that the condition for termination of the Repeat-Until loop is
the negation of the condition for termination of the While loop. The reason for
that difference is simple: the While loop condition is a condition for looping,
and the Repeat-Until condition is a condition for terminating the loop
To show the closeness of these two forms, we could build a Repeat-Until loop
from the body of the loop and a While loop connected sequentially, as in shown
in Pseudocode 5.18.
204 Chapter 5 Algorithm Behavior
The Repeat-Until loop always performs the actions in the body at least once,
this makes it well adapted to specific situations. However, the While form
makes it possible for the body of the loop not to be executed if need be and this
added control is usually preferred.
The behavior of a While loop is dynamic or moving as the actions of the loop
body are executed repeatedly, whereas its structure is static. We will
illustrate this difference in Figure 5.27. The pseudocode demonstrates the
static form of an algorithm to calculate the remainder Rem of the integer
division of a numerator Num by a divisor Den. To the right of the pseudocode,
the behavior of the While loop is shown as a series of actions forming a trace.
The numbers 14 and 4 were arbitrarily assigned to Num and Den to demonstrate
this trace.
The loop body Set Rem to Rem – Den is repeated while the condition Rem ≥
Den is True and the repetition ends when this condition becomes False. This
algorithm is generally known as the modulus operation.
Modulus
Input Num Num = 14
Input Den Div = 4
Set Rem to Num Rem = 14
We will refine our traces to more convenient two-dimensional trace tables that
will prove to be extremely useful.
Divide Num = 14
Input Num Div = 4
Input Den
Set Rem to Num Rem = 14
Set Quot to 0 Quot = 0
14 ≥ 4 10 ≥ 4 6≥4 2≥4
While Rem ≥ Den loop T T F
T
Set Rem to Rem - Den Rem = 10 Rem = 6 Rem = 2 Rem = 2
Output 3
Output Quot
Output 2
Output Rem
End Divide
Iteration 1 Iteration 2 Iteration 3
Figure 5.28 shows the Divide algorithm introduced in Figure 3.45, which
divides a numerator Num by a divisor Den, yielding a quotient Quot and a
remainder Rem. The trace shows how 14 divided by 4 yields a quotient of 3 and
a remainder of 2.
This algorithm first inputs the values for Num and Den and then initializes
Rem with the value of Num and Quot to zero. The loop subtracts Den from Rem,
counting the number of times it does this in Quot until Rem is less than Den.
Finally, Quot and Rem are output.
Trace tables, as shown in Figures 5.27 and 5.28, are very useful ways to study the
dynamic behavior of algorithms. A trace table is a two-dimensional
arrangement of boxes set up at the side of an algorithm in either pseudocode or
in flowblock form. For each iteration, the loop creates a stack of boxes showing
the effect of the actions performed. This two-dimensional trace can then be
viewed both horizontally and vertically, as will be shown in the following
sections.
The Divide algorithm described here differs from the division operation
available in most programming languages. First, the division of two Real
Numbers (written X/Y) yields another Real Number expressed with a decimal
point. Second, the division of two Integer values usually yields only the
quotient, while the remainder can be obtained from the Modulus operation just
described.
This algorithm, Pseudocode 5.19, does not use the fundamental While loop form
but instead uses the Repeat-Until form, where the test for termination is made
after executing the loop body. Now, let’s see the unfortunate consequences of
delaying the test until after the body has been executed!
This algorithm works well for most values, but not if Y is initially 0. In that
case, Y is first decreased to -1, then Y is tested to see if it reached 0. But since Y
has already passed 0, the algorithm keeps looping, and Y keeps decreasing
forever! This is called an infinite loop and is a very common programming error.
The revised version of Product A “fixes up” the infinite loop by leaving the
loop when Y is less than or equal to zero (Pseudocode 5.20). This way, it does not
loop forever, but it still does not compute the correct result for the case where
Y=0. For that case, the algorithm first sets Product to zero and then
immediately increases it by X and halts. So using this algorithm to multiply
any value by zero does not yield a zero!
In Pseudocode 5.21, Product B has been patched-up to handle the case where Y
is zero by first testing for it, and immediately circumventing the loop. But
Product C still has a problem! By using variable Y as a counter, it destroys its
original value. This side effect may not always be harmful. But if Y is to be
used again later in the program that uses Product C, its value will have been
changed to 0.
For example, suppose Y represents a constant rate of pay— say $10 per hour—
that is to be multiplied by various numbers of hours X on successive invocations
of Product C. The first execution of Product C will yield a correct result but the
value of Y will be set to 0. Thus, all subsequent products of any X with Y will
yield zero.
Pseudocode 5.22 finally fixes this side effect in Product C by first placing a
copy of Y into the variable Count, and using Count, instead of Y, as a counter.
This algorithm finally works, but it is more complex and messy than it should
be. It is called a “kludge”1—something that works for the wrong reasons.
There is certainly no elegance here!
This process of trial and error followed by many fix-ups and more errors is
entirely unnecessary. Some prior planning and refinement, using the Four
Fundamental Forms, could yield a better algorithm as shown in Figure 5.29.
Initialize P
C - counter
D - dummy
Better Product If X < Y
Add D to P Set Multiplier to X
Add D to P Set Multiplier to Y Set Multiplicand to Y
Set Multiplicand to X Else
Add D to P Set Multiplier to Y
Set Product to 0 Set Multiplicand to X
While Multiplier > 0
Set Product to Product + Multiplicand
Add D to P Set Multiplier to Multiplier – 1
Add D to P End Better Product Optimized portion
of Better Product
The development of the algorithm, in Figure 5.29, starts out at a very primitive
level by planning how the algorithm is to execute—essentially by writing a
trace of the execution of the algorithm. This “planing trace” starts by setting
up not only a counter C equal to the multiplier (the number of additions to
perform), but also a “dummy” variable D equal to the multiplicand (the value
to add), and a product P that is initially zero. Then the successive additions
are shown as a series of accumulations.
A simple refinement of this is done by replacing the sequence of additions in the
plan with a loop. This is shown in the pseudocode at the center of Figure 5.29.
Note that some more descriptive names have been given to the variables,
Multiplier and Multiplicand. This could be the final algorithm; there is
nothing more to it! By using the proper structures in the proper way we have
created a better Product. In fact, since we avoided wasting time fixing and
patching, we could take some time to optimize the finished product.
The further refinement on the right of the figure shows an optimized Better
Product, where the counter Multiplier is first chosen to be the smaller of the
two values X and Y. This way, the algorithm loops the fewest number of times.
Time is saved for the machine, but not necessarily for the human programmer.
Further optimization of this Better Product algorithm is possible, and we will
discuss it at the end of this chapter.
numbers and conditions have been chosen for our convenience in making the
trace. Later, when using a computer, we can be more realistic (with 72 monthly
payments).
After making the payments for Period years, there is still an amount to repay
at the end; this amount is called the balloon payment, because it “balloons”
into a much larger amount than we expect if the monthly payment is too low.
The problem is to compute the balloon payment. You may wish to guess the
value before reading on.
Input Amount
Set up Amount, Input Duration
Payment, Input Payment
Loan Duration, Input Rate
Rate, Balance, Set Balance to Amount
Set up Time Set Time to 0
Loop While time is not up
Set Interest to Rate × Balance
Output Compute Interest Chop Interest
NewBalance Set Balance to Balance +
End Loan Increment Time Interest – Payment
Output Balance Set Time to Time + 1
While Time < Duration 0<6 1<6 2<6 3<6 4<6 5<6 6<6
T T T T T T F
Set Interest to
Rate Interest = 600 560 516 467 414 355
× Balance Chopped
Set Balance to
Balance = 5600 5160 4676 4143 3557 2912
Balance
+ Interest
– Payment Time = 1 2 3 4 5 6
Increment Time
Output Balance 2912
End Loan
initial final
state state
(before) (after)
and Time. These two variables are essential to the algorithm; should the
process be interrupted at any stage, it is possible to continue it if only these two
variables are known.
Num = 6
Input Num
Output
Output Output Square 36
at every
between any stage
two iterations
Horizontal View Vertical View
2
OddNum = 5 + 7 OddNum = OddNum + 2 9 OddNum = 2 × CountNum - 1
OddNum = 1 3 5 7 9 11 13
Count = 1 2 3 4 5 6 7
Vertical views consider each stage separately and show all the variables at
each iteration, as shown in Figure 5.35.
OddNum = 1 3 5 7 9 11 13
Count = 1 2 3 4 5 6 7
It is important to realize that an assertion may not be true at a point part of the
way through the execution of a loop body. The reason for this is because only
214 Chapter 5 Algorithm Behavior
some of the variables used in the assertion may have been changed. Once the
body has been completely executed, the assertion is true again; the relationship
among the variables is constant, or invariant.
For example, in the above loop, the assertion is no longer true after the first
statement in the loop body has been executed. It does not become true again
until after the third statement has been executed.
Further observation of the trace of Figure 5.33 yields two more formulas that
hold at every stage, giving us three invariants for the same loop:
• Square + OddNum = Count × Count
• Square = (Count - 1)2, and
• OddNum = 2 × Count - 1.
This last relation between OddNum and Count suggests that the use of both of
these variables is not necessary. In fact a simpler algorithm with only one of
these variables, Count, is possible. Try it.
In the Odd Square example there were many invariants, and they were rather
easy to observe. In general, loop invariants are not always easy to find and
there is no foolproof technique for finding them. Loop invariants are very
important because they precisely describe the action of the loop in which they
appear. Sometimes, they provide the essential piece of information that
allows us to understand the action of the loop. As an example of this, let’s look
at the Go Stone game as described in Figure 5.36.
Section 5.5 Repetition Foms 215
Each iteration of the loop reduces the number of stones in the box by one. The
loop will terminate when there is exactly one stone left in the box. The question
for you to answer is: by counting the number of black and white stones in the box
before the algorithm is executed, is it possible to know the color of the final
stone that will be left in the box when the loop terminates? Before reading on,
try to solve this problem yourself.
Let us examine the way in which the number of stones is reduced:
• If a matching pair of black stones is removed, then one black stone is put
back into the box, the number of black stones is reduced by one and the
number of white stones stays constant.
• If a matching pair of white stones is removed, a black stone is put back
into the box, the number of black stones is increased by one and the
number of white stones is reduced by two.
• If a non-matching pair is removed, a white stone is put back into the box
and the number of white stones remains unchanged while the number of
black stones is reduced by one.
Thus, the number of black stones always changes by one at each iteration while
the number of white stones either remains constant or is reduced by two. This
means that, if we started with an even number of white stones, there will
always be an even number of them; if we started with an odd number of white
stones, there will always be an odd number of them.
216 Chapter 5 Algorithm Behavior
In other words, the parity of the number of white stones is invariant; this is our
loop invariant. The only way that we can finish with a single white stone—an
odd number of white stones—is if we start with an odd number of white stones.
If we start with an even number of white stones, the last stone will be black.
The only way that we can understand the loop well enough to make this
statement is through the use of the loop invariant.
Later, in Section 5.7, we will show how we can use loop invariants to improve
algorithms. Finally, note that loop invariants are also used to formally prove
the correctness of algorithms.
Fact1 N=5
Input N Fact = 1
Set Fact to 1 Count = 1
Set Count to 1
1≤5 2≤5 3≤5 4≤5 5≤5 6≤5
T T T T T F
While Count ≤ N
Fact = 1 2 6 24 120
Set Fact to Fact × Count
Count = 2 3 4 5 6
Increment Count
Output
Fact1, of Figure 5.37, initially sets Fact and Count to 1, and then loops as long
as Count is less than or equal to the input value N. In the loop body, Fact is
multiplied by the value of Count and Count is incremented. When Count is
incremented past N, the loop is terminated and the final value of Fact is output.
Section 5.5 Repetition Foms 217
The trace shows this computation for an input value of N = 5. You will quickly
notice that as Count increases gradually, the value of Fact increases
dramatically. Just doubling the value of N to 10 would produce an output value
of 3 628 800. Such a computation can quickly exceed the bounds of any computer,
so we must beware of computing the factorials of large numbers.
If we observe this trace and extend it, the following two loop invariants become
apparent:
• Count! = Fact × Count, and
• Fact = (Count - 1)!
These two relations can be combined into a third relation:
• Count! = Count × (Count - 1)!
This is a definition of factorial in terms of itself. Such a definition is called a
recursive definition and will be discussed in Chapter 7.
Fact2 N=5
Input N Fact = 1
Set Fact to 1 Count = 5
Set Count to N
5>0 4>0 3>0 2>0 1>0 0>0
T T T T T F
While Count > 0
Fact = 5 20 60 120 120
Set Fact to Fact × Count
Count = 4 3 2 1 0
Decrement Count
Output
Output Fact 120
End Fact2 Loop Invariant: Fact Count! = N!
The algorithm Fact2, of Figure 5.38, proceeds in the opposite way from Fact1.
It starts the Count at the value of N, and loops, decreasing this value until it
reaches zero. During each loop, it multiplies Fact by the decreasing value of
Count. Figure 5.38 presents a trace of this algorithm as well.
Observing this trace, we see what at each stage the following invariant holds:
N! = Fact × Count!
Note: It is interesting that since the loop invariant holds true even when
Count = 0, the factorial of 0 must be 1.
218 Chapter 5 Algorithm Behavior
Notice that this loop invariant for Fact2 is very different from the previous
invariant for Fact1. This is normal since different ways of computing the same
value may lead to different loop invariants.
If the condition Count > 0 were incorrectly written as Count ≥ 0, the output of
Fact2 would be zero because Fact is finally multiplied by the lowest value of
Count, which in that case would be zero. This is the error of one iteration too
many, and is usually called a one-off error. Slight errors like this one can result
in much larger errors in the final results. Tracing helps find these errors. The
one-off error is one of the most common errors in programming.
Two-dimensional tracing is useful in many ways:
• Tracing yields insight into the dynamic behavior of algorithms.
• Tracing detects errors (such as the one-off error just mentioned).
• Tracing yields interesting relations among variables.
• Tracing suggests alternative algorithms.
Max
In this view, a black-box view, we show all that is needed in order to be able to
use Max—we see that it takes in two data values and passes out the maximum
of these two. In the following small piece of pseudocode (Pseudocode 5.24), the
two values X and Y are input, the sub-algorithm Max is invoked to find the
larger of X and Y, this value is assigned to Bigger and, finally, Bigger is output.
Section 5.6 Invocation Forms 219
Figure 5.40 shows the data-flow diagram and the pseudocode for an algorithm
that makes use of sub-algorithm Max three times to find and output the
maximum of four input values A, B, C, D.
The version in Pseudocode 5.25 is much more complex. Here, the reader must
examine the details carefully to see that the same method is used each time to
find the maximum of two numbers. If such a degree of simplification can be
achieved for such a trivial sub-algorithm as Max, imagine the improvement in
clarity that can be obtained when a complex sub-algorithm is involved! This
process of reducing the complexity by hiding the details is called abstraction.
Seconds Example
Suppose you were asked to convert a given number of seconds (say Time = 1 000
000 seconds) into days, hours, minutes and seconds. You could proceed as follows:
1. Divide Time by the number of seconds in a day (86 400), yielding a
quotient, the number of Days, and also yielding some remaining number
of seconds in Seconds.
2. Then this remainder is divided by the number of seconds in an hour
(3 600), yielding the number of Hours and some remaining Seconds.
3. Finally, the above remainder is divided by the number of seconds in a
minute (60), yielding a quotient that is the number of Minutes and a
remainder that is the number of Seconds.
Section 5.6 Invocation Forms 221
Figure 5.41 Data-flow diagrams for the Div and Mod sub-
algorithms
Numerator Divisor Numerator Divisor
Numerator ≥ 0 Divisor > 0 Numerator ≥ 0 Divisor > 0
Div Mod
Quotient Remainder
To do this, we make use of two sub-algorithms, Div and Mod, which are defined
by the data-flow diagrams shown in Figure 5.41. Note the assertions about the
data values that Div and Mod work with. In both cases the Numerator and
Divisor must be positive integers. In addition, the Divisor cannot be zero
because of the mathematical commandment:
“Thou shalt not divide by zero!”
222 Chapter 5 Algorithm Behavior
Div
Minutes = 46
Mod
Seconds = 40
The algorithm Convert Seconds of Figure 5.42, shows a data-flow diagram and
corresponding pseudocode for the algorithm just described. Remember that
products such as 60 × 60 × 24 need not be evaluated by us; computers can do that.
representation for a number that is not pure base 10. We would have a similar
problem if we tried to represent a person’s height by the integer 511 instead of
5’ 11”.
If each of the military times is converted to minutes past midnight, then these
numbers of minutes can be subtracted. An algorithm to compute this military
time difference is shown in Figure 5.43. It includes Invocations of a conversion
sub-algorithm that is similar to the Convert Seconds algorithm we have just
seen.
Absolute Multiply
Difference Value
Add
1060 1230
Difference Minutes
If what we really want is the minimum difference between any three military
times, we can proceed as indicated on Figure 5.44. We use TimeDifference as a
sub-algorithm that we invoke three times, after which we invoke a sub-
algorithm, MinDiff, to find the minimum of three values.
MinDiff
224 Chapter 5 Algorithm Behavior
Note that TimeDifference is invoked with three variables, the last one being
used to return the result of the sub-algorithm execution.
Output Y Output 37
End GCD
Section 5.7 Improving Programs 225
The result and the trace of the Greatest Common Divisor algorithm are also
shown in Figure 5.45. One use of the Greatest Common Divisor is for sharing or
partitioning two kinds of “whole” items, such as pebbles or cans of goods, that
cannot be split further. For example, if we have 111 cans of one kind of item and
259 cans of another kind, then the largest number of identical piles of cans
equals the Greatest Common Divisor, which is 37. Each of the 37 piles would
have 3 cans of one type (111/37 = 3), and 7 cans of the other type (259/37 = 7).
There are many other uses of the Greatest Common Divisor, but they are
usually more complex.
Our next example is an algorithm that converts decimal integers into their
equivalent binary form. Figure 5.46 shows this conversion algorithm together
with its trace. We can see, for example, that it converts the decimal number 13
into the binary number 1101.
Figure 5.47 shows the multiplication algorithm for two integers that may be
positive or negative. In this example we can find two While loops nested in the
two parts of a Selection. The trace illustrates the dynamics of the Else part of
the Selection since the first value to multiply is negative. As in the preceding
conversion algorithm, we use an extra variable, Temp, to avoid modifying the
original value of variable X.
Change may be made in many ways, illustrating many combinations of forms. In
See Pseudocode Chapter 4 we designed an algorithm to Make Change. Let us consider now a
4.10 for a slightly modified version of Change Maker, which provides a count of the
detailed Make quarters, nickels, and pennies in exchange for a dollar when buying an item for
Change
Cost cents. In this version we chose to have no dimes or half-dollars involved.
algorithm.
Section 5.7 Improving Programs 227
The algorithm in Pseudocode 5.27 uses the method of subtraction and is very
similar to the previously described method of Chapter 4. It consists of a series
of loops, starting at the higher denominations (quarters), and subtracting away
these denominations, counting as it proceeds.
Let’s look now at another version of Change Maker.
The second algorithm, Pseudocode 5.28, is still based on the method of division.
It makes use of the fact that a division of integers gives an integer quotient.
This version of Change Maker is essentially the same as the previous method.
It simply recognizes that the previous method was really doing division in
disguise.
The next version we will develop will be based on addition and close to the
actual method used by cashiers.
228 Chapter 5 Algorithm Behavior
The third version in Pseudocode 5.29 corresponds to the way people usually
prefer to make change, for it involves only addition. Here, the algorithm
starts with the value Cost and the lower denominations; pennies are first
added until Sum is a multiple of 5. Note that the test for Sum to be a multiple
of five makes use of the Mod function of Figure 5.41 which gives the remainder
when Sum is divided by 5. When this remainder is zero, Sum is a multiple of
5. Then nickels are similarly added until Sum is a multiple of 25. Finally,
quarters are added until Sum reaches a dollar.
Let’s rewrite our Change Maker algorithm one more time using a different
combination of forms; this time with Selections nested within a Repetition.
Section 5.7 Improving Programs 229
Using Invariants
We have seen earlier that loop invariants were any assertions (relations,
conditions, equations, etc.) whose truth is unaffected by the execution of the
body of the loop. We will use loop invariants here to try and improve the
speed of algorithms.
Note: Loop invariants are the same before and after loop execution, but
not necessarily during.
The loop invariant in the Positive Product algorithm of Figure 5.48 is:
(1) X × Y = Product + Multiplier × Multiplicand
This invariant has an intuitive meaning here. The product of X and Y at any
point is determined by summing the partial Product and the remaining portion
Multiplier × Multiplicand that is yet to be added into Product. This
breakdown into two parts (an already computed part, and a part yet to be
computed) is often useful for determining invariants.
A significant aspect of loop invariants is that the actions within the body of a
loop do not change the invariant. For example, these are the actions within
the loop:
Add Multiplicand to Product
and...
Decrement Multiplier.
These two actions could just as easily have been written as follows:
Set Product to Product + Multiplicand
and...
Set Multiplier to Multiplier - 1
Substituting these two into the original relation produces what is shown in
Pseudocode 5.31.
Section 5.7 Improving Programs 231
This yields again the original invariant! The invariant holds at the beginning
of the body of the loop, and also at the end of it. In other words, this relation
remained invariant after execution of the complete body of the loop. The
adjective “complete” is important here, since the invariant relation is not
necessarily true part way through the execution of the loop body. This point is
extremely important in the following discussion.
Note In this example, both assignments must be added to the loop body
together and in order for the invariants to hold. You can’t add one
without the other.
Given the invariant relation (1), it is interesting to see whether we can find
other assignments that could be added to the body of the loop and that would
keep the given relation invariant. Here is one such pair of assignments:
Else
Set Multiplicand to
Multiplicand + Multipli- Multipli-
Multiplicand cand = 12 cand = 24
Note that we have written the original two actions in a slightly different (but
equivalent) way. Also, the doubling of Multiplicand was done by an addition
so as to be more efficient, and above all so as to avoid using the product we are
defining! A slightly more efficient algorithm is given in Figure 5.50, where we
double and halve during every iteration.
Section 5.7 Improving Programs 233
5.9 Glossary
number x in the range 1.0 ≤ x ≥ 10.0
Character: A data type whose and a multiplier that is some power
values are textual symbols such as of 10, for example, the speed of light
letters, digits, punctuation marks is 3.10×1010 centimeters per second;
together with other symbols used to expressed in many programming
control spatial arrangement or text, languages as 3.0E10.
such as tabs and end of page.
Side effect: A consequence, frequently
Identifier: A symbolic name that is unwanted and unexpected, of an
used to refer to a programming entity action in a program that is not
such as a sub-program or variable. connected with the goal of the action.
Infinite Loop: A repetition form A common example is the change in
whose condition is never met: the the value of a variable within a sub-
loop keeps looping. algorithm resulting from assignments
outside the sub-algorithm.
Instruction: A single action in a
program. State trace: A trace where the values
shown are restricted to as few as
Iteration: A single execution of the possible to show the program’s
body of a repetition form. action.
5.10 Problems
Mid: The Middle Value
The middle value of an odd number of different values is that value which has
as many values lower than it, as it has higher than it. It is not the average
value. For example, the middle value of the three integer values 3, 6 and 5 is 5.
There are many ways of finding the middle value; some of these ways follow.
Problem 1
A B B C C A A B B C C A
Max min
M1 M2
2. Mid Tree
The given tree corresponds to a nasty nest of Selection Forms. Fill out
boxes at the right so that M is assigned the middle value of the three
values A, B, C.
Show assertions at branches of the tree.
Section 5.10 Problems 237
Problem 2
False True
A<B
3. More Mids
Create an algorithm (flowblock diagram, pseudocode, and so on) that is
simpler than the tree of Problem 2, having fewer nests (only 3 simply
nested), but involving more complex conditions.
Create another Mid3 algorithm from flowblocks by using Sum and
Difference blocks also.
4. Others
Redo the tree of Problem 1 to find the maximum of three values, and
then redo it again to find the minimum of three values. Finally, redo it
to sort three values.
How many tests are necessary to prove the equivalence of the Mid of
five different values?
How many tests are necessary if some of the five values could be the
same?
a. A ← A + B b. A ← A − B c. A ← A − B
B ← A+ B B ← A− B B←B−A
C← A+ B C← A+ B C← A× B
238 Chapter 5 Algorithm Behavior
6. More Sequences
Describe briefly what the following algorithms do (but not how they
do it).
a. A ← 2 b. E ← A c. Z ← A
B ← A+ A A← B Z←B+ Z+ Z
C← B + B B←C Z←C+ Z+ Z
D←C+ C C← D Z← D+ Z+ Z
E← D+ D D←E Z←E+ Z+ Z
7. Charge Again
Create an algorithm to compute a charge C, given by the formula:
C=4× K + 6× A
for A adults and K kids, without using multiplication and without any
looping. Do this in two ways, using a different number of additions
each time. Hint: The charges are Integers.
8. Verification of Sequence
Prove (or disprove) that the following two Sequence algorithms are
equivalent in producing the same output E. Draw the data-flow
diagrams.
a. C ← A × A b. C ← A + B
D←B×B D ← A− B
E←C− D E←C× D
9. Logical
If the two logical values are represented by the numbers 0 and 1 (F=0,
T=1), then prove the following equivalencies, which are in terms of
arithmetic operations:
a. NOT(P) = 1 – P
b. P AND Q = P × Q
c. P OR Q = P + Q – P × Q
Section 5.10 Problems 239
Problem 11
If P If P and Q
If Q X
X Else
Else If R
Y Y
Else Else
If R Z
Y
Else
Z
Problem 12
If P If Q
If Q If R
If R W
W Else
Else If P
X X
Else Else
X Y
Else Else
If Q If P
If R X
W Else
Else Z
Y
Else
Z
240 Chapter 5 Algorithm Behavior
Problem 13
If P If P
If Q X
X Else
Else If Q
Y If R
Else X
If Q Else
Y Y
Else Else
Z Y
Problem 14
If B < C If C < A
If C < A If B < C
X X
Else Else
Z Y
Else Else
If A < B If A < B
Y Y
Else Else
Y Z
16. Complements
Prove (or disprove) that the given two conditions are opposite
(complementary) in behavior.
(X ≤ 30) AND ( (X > 20) OR (X ≤ 10) )
(X > 10) AND ( (X > 30) OR (X ≤ 20) )
Section 5.10 Problems 241
Problem 17
If A If A and B If A or C
If B X If A and B
X Else X
Else If A or C Else
Y Y Y
Else Else Else
If C Z Z
Y
Else
Z
18. Convert
Trace the following algorithm for X = 13, and describe its general
behavior briefly. Assume Integer values.
Problem 18
Input X
Set Y to Chop X / 2
While X ≠ 0
If (Y + Y) = X
Output "0"
Else
Output "1"
Set X to Y
Set Y Chop X / 2
Problem 19
A1 B1 C1
Min Max
Min
A2 B2 C2
20. Pow!
Trace the following algorithm for X = 13 and Y = 2. What does this
algorithm do in general? Choose a better set of names for the variables.
Problem 20
Input X
Input Y
Set C to X
Set D to Y
Set P to 1
While C > 0
If C is odd
Set P to P ×D
Set C to C–1
Else
Set D to D ×D
Set C to C/2
Output P
21. Pi Square
Trace the following algorithm, which computes the square of π, and
indicate what formula it computes (but do not work out the arithmetic).
Also describe briefly how it works.
Section 5.10 Problems 243
Problem 21
Set N to 7
Set F to 0
Set P to 0
Set Index to 1
While Index ≤ N
If F = 0
Set P to P + 1 / (Index × Index)
Set F to 1
Else
Set P to P – 1 / (Index × Index)
Set F to 0
Set Index to Index + 1
Set S to 12 × P
Problem 22
Input X
Set P to 0
Set Index to 2
While Index < X
If Mod(X, Index) = 0
Set P to 1
Set Index to Index + 1
If P = 1
Output "Not Prime"
Else
Output "Prime"
24. Power
Create an algorithm to find the Nth power of any number X, where N is
a non-negative Integer. Then modify this algorithm to work for any
integer N.
25. Fibonacci
One simple model of population growth (of rabbits) is given by the
series:
1 1 2 3 5 8 13 21 34 55 89 ...
where the new population P at one month is determined by summing the
previous two months’ populations (called latest L and second latest S).
Create an algorithm to determine the population at month M, where M
> 2.
29. Expo
Create an algorithm to compute the exponential function from the first
N terms of the following series:
x2 x 3 x 4
Expo(x) = 1+ x + + + +…
2! 3! 4!
30. Log
Create an algorithm to compute the natural logarithm function (base e)
by the following series approximation (for 0 < x ≤ 2 ):
Section 5.10 Problems 245
31. Sine
Create an algorithm to compute the trigonometric sine from the first N
terms of the following series (where angle X is in radians). Recall that
the sine is positive in the first two quadrants.
x3 x5 x7
Sine(x) = x − + − …
3! 5! 7!
32. Score
In some sporting events, a number of judges each gives a score. The
overall score is determined by dropping the highest and lowest scores
and averaging the remaining scores. Create a data-flow diagram to
determine the score for an event, having five judges, giving 5 grades
(each having values ranging from 0 to 10).
Problem 44
Cube First Second
Input N Set B to 50 Set N to 7
Set A to 0 Set J to 1 Set C to 0
Set B to 1 While B < 300 Set S to 1
Set C to 1 Set B to B + B / J While C < N
Set D to 1 Set J to J + 1 Set C to C + 1
While D < N End First Set S to S + C + N
Set A to A + 6 Set N to N – 1
Set B to A + B Output S
Set C to B + C End Second
Set D to D + 1
Output C
End Cube
Chapter Overview
6.1 Preview....................................................................252
6.2 Using External Data and Files...................................252
End-Of-File Markers.................................................255
6.3 More Building Blocks................................................259
The Select Form........................................................259
The For Form.............................................................262
6.4 Using the For Forms in Nests......................................265
Nesting Fors in Fors...................................................265
Nesting Selections in Fors..........................................269
Creating Plots with For Nests....................................273
6.5 More Data Types.......................................................275
The Character Type..................................................275
The Logical Type......................................................279
6.6 Some General Problem-Solving Algorithms................281
Bisection Finding Values..........................................281
Maximum Power Optimizing Power Output...............284
Solver Solving Equations..........................................287
6.7 Review Top Ten Things to Remember........................290
6.8 Glossary...................................................................291
6.9 Problems...................................................................292
252
252 Chapter 6 Bigger Blocks
6.1 Preview
So far, we have limited the data we used in our examples to a few fixed number
of values. All of these values were part of the algorithms and stored inside the
computer. Here, we will extend the data we will use to include any number of
values, as well as data stored outside the computer.
We have already seen several examples of mixed forms, especially involving
both repetitionsand selections, and in this chapter we will see more of these
including slightly more complex algorithms and some useful paradigms and
applications.
We will also extend the fundamental Selection form to include a more general
Select (or Case) form, where any number of choices can be made. The Repetition
form will also be extended to include a For loop(or loop-and-count).
In accordance with our problem-solving method, we will stress, which makes it
possible to develop in a number of stages. Each stage is simple because it
usually involves only one repetition or selection form. The various stages may
lead to deeper nesting of loops and selections.
But the bigger structures introduced in this chapter are not necessarily always
better! For example, while the For and Select Forms may sometimes be more
convenient than the simpler While and Selection forms, they are not as general
and have limitations.
This chapter will help you synthesize a little better what you have learned in
the previous chapters, with some emphasis on top-down design. This chapter
comprises again a good number of examples that illustrate the various ideas
discussed.
Find Mean 1
Set Num to 4 Sum 0 20 30 70 100
Set Sum to 0 Mean 25
Add North to Sum Data
Num 4 not external
Add South to Sum North 20
Add East to Sum South 10
Add West to Sum East 40
Set Mean to Sum / Num West 30
Output Mean
Find Mean 1
Algorithm Internal Data External data
Notice: no external
data are used.
First, the number of values to be averaged, Num, is set to a value of 4 and the
variable Sum is initialized to a value of zero. Then each value is accumulated
into Sum. Finally, Sum is divided by the value of Num, to determine the Mean
value.
Find Mean 2
Set Num to 4 Sum 0 20 30 70 100
Set Sum to 0 Mean 25
Input Value Num 4
Add Value to Sum Value 20 10 40 30
Input Value
Add Value to Sum 20
10
Input Value Data
Add Value to Sum 40
Not in 30
Input Value Memory
Add Value to Sum
Set Mean to Sum / Num
Output Mean
End Find Mean 2
Algorithm Internal Data External Data
This method can be modified by keeping the data values external, and reading
in each of these external values, one at a time, into a single internal variable
Value, which is added into Sum. This method simplifies the internal data
structure, but makes the algorithm longer, as shown by Find Mean 2 in Figure
6.2. Here we are faced with the ever present dilemma in computing; if we
254 Chapter 6 Bigger Blocks
simplify the data, then the algorithm becomes more complex, if we simplify
the algorithm then the data becomes more complex.
If we are dealing with only a few values, either of the preceding methods (Find
Mean 1 or Find Mean 2) could be used. But if there are many values, it is
crucial that we find the best method. The preceding program may be further
generalized to average any number of values by first reading in the number of
values to be averaged, and then by replacing the series of input-accumulate
actions with a loop, as shown by Find Mean 3 in Figure 6.3.
Find Mean 3
Set Sum to 0 Sum
Input Num Changed from
Set Count to 0 Mean previous version
While Count < Num
Input Value Num 4 4
Set Sum to Sum + Value 20
Set Count to Count + 1 Value 10
Set Mean to Sum / Num
40
Output Mean
Count 30
End Find Mean 3
Algorithm Internal Data External data
The number of values to average could be stored with the external dataas the
first item and input into Num. The algorithm then includes a variable, Count,
which starts at 0 and is increased once for each input value, until it reaches the
value in Num and stops the looping. We will further refine the Find Mean 3
algorithm in the next section.
You may wish to try to refine the algorithm in Figure 6.3 first before reading
any further, for there are a number of ways to refine it.
The external datacan be input in many ways. In the early days of computers,
the values were punched into cards that were read by card readers. Nowadays,
the values may be input from a keyboard, one value at a time. Yet another
common method, described below, uses files.
Files are a means of storing data external to the computer on physical devices
such as tapes and disks. Many of these devices are based on magnetic
phenomena, but these physical aspects are not important to know at this time.
In fact, files can be viewed as collections of data. The data values that are
stored in a file may easily be retrieved, input to a program, changed, stored and
output again to form a modified or updated file. So files can provide another
source of input to programs. They can also be used to pass data from one program
to another.
All of this makes it possible to separate the data from the program, thus
making the program more general, and applicable to many sets of data.
Section 6.2 Using External Data and Files 255
End-Of-File Markers
Our Find Mean 3 algorithm can be refined in a number of different ways. We
will present and discuss two such refinements that involve different ways of
indicating when all the data has been processed.
The problem with the general method of Figure 6.3 is that the value Num must
be determined externally before the computation begins. If the number of data
values is large and a human is to count them, there could easily be an error.
Furthermore, humans should not need to do the mundane job of counting when a
computer can do the job so much better.
The first way of refining Find Mean 3 is to use the algorithm to count the
number of values as they are input, as shown on Figure 6.4. This is done by
placing a special “terminating” value after the last input value. The
terminating value(or end-of-file markeror sentinel value) is a value that is
different from all possible data values. When it is input, it causes the looping
to stop. Of course, this terminating value is not counted or included in the
average.
The value used to mark the end-of-file depends on the data because it must be
distinct. For example, if all values were percentages (ranging from 0 to 100),
then a terminating value could be any number outside of this range (say 101 or
500). Similarly, if all values were positive numbers, then any negative number
could be used as a terminating value. Sometimes a computer supplies its own
end-of-file marker, often called EOF.
If the nature of the data changed so that the value –999 were now a legitimate
data value, another terminator would have to be chosen and the program in
Figure 6.4 would have to be modified. To avoid modifying the program, the
second refinement, shown in Figure 6.5, provides the terminator as the first
piece of data and tests for its occurrence as the last piece.
The two terminator values in Figure 6.5 “sandwich” the data. Now the Find
Mean 5 program averages any kind of numerical values except for the value
entered as the terminator. terminating “sandwich”
Note: Putting the terminating value at both the beginning and the end of
the external data list makes the program easier to maintain.
When this value is changed, only the data list must be changed.
Program reusability is the main reason for selecting the last refinement. It
allows us to view the program as a black box. When there are some changes to
the data ranges, we only need to make changes to the data and not the program;
we can use our program as is on the new data.
As we have seen so far, many algorithms can produce the same results.
However, some of these algorithms can be more easily extended than others,
which makes them more interesting to use. For example, there are two ways to
find the maximum value of two variables A and B, as shown in Pseudocode 6.1.
The two Pseudocode 6.1 Two ways to find the maximum of two values
algorithms Maximum 1 Maximum 2
Maximum 1 and If A > B Set Max to A
Maximum 2 Set Max to A If A < B
were introduced Else Set Max to B
Set Max to B Output Max
in Figure 5.14.
Output Max End Maximum 2
End Maximum 1
Deep
The first thing Loop Max does is read in the terminating value. Then, the first
of the numbers to be compared is input and is immediately assigned to be the
maximum, Max. Once this is done, Loop Max successively inputs values and
compares each value to the maximum, Max, updating it if necessary, as long as
the input value is not the terminating value. Finally the maximum is output.
Notice that this algorithm assumes that at least one value is given between
the terminating values. If it is possible that no values be given (other than the
two terminating values), then the algorithm must be modified by testing before
the first assignment to Max.
This Loop Max algorithm could be extended in many ways. For example, it
could find not only the largest but also the second largest value. Try it! It could
also be extended to find the minimum value, to count the number of values, to
sum all the values, to compute averages, to give running averages, variances,
ranges, the number of values greater than a given value, as well as perform
many other computations.
Each of these computations usually involves an initialization of values, then
some extension to the body and finally some output at the end. You may
recognize this pattern for it was used in both Loop Max and Find Mean 5. This
pattern is illustrated in Pseudocode 6.3.
Section 6.2 Using External Data and Files 259
Input Terminator
Initialize
Typical pattern
Input Value
for algorithms While Value ≠ Terminator
inputting Perform Computation
external data Input Value
These computations may also be done using arrays, as we will see in Chapter 8.
The n conditions shown are tested in order (Cond1 then Cond2, and so on) until
the first condition that holds is found, and the corresponding set of actions is
performed. If none of the conditions from Cond1 to Condn are True, then all the
actions represented by Actionsn+1 are performed.
260 Chapter 6 Bigger Blocks
The Grades 1 The form in Pseudocode 6.5 is much simpler to understand than the Pseudocode
algorithm was 6.4 which uses only Selection Forms. To fully illustrate the difference between
first introduced these two forms, Figure 6.7 shows the Grades 1 algorithm expressed as a nested
in Chapter 5, set of Selection forms (left) and as a single Select Form (right). This figure also
Pseudocode 5.9. shows how the value of Percent selects the grade for output.
Notice that, as with the nested Selection template (Pseudocode 6.4), once a
condition has been satisfied, we are not limited to a single action as Actionsn
stands for one or a group of actions. For example, if Grades 1 were also required
to count the number of As, Bs, Cs, and so on, the algorithm in Pseudocode 6.6 could
be used.
Section 6.3 More Building Blocks 261
Let’s illustrate further the Select Form with an algorithm for determining the
unit price, depending upon the quantity ordered, shown in Pseudocode 6.7.
In this algorithm (Pseudocode 6.7), the conditions are all simple comparisons of
a variable to various constants. This allows us to express the algorithm in a
shorter variant of the Select Form know as the Case Form, shown on the right.
262 Chapter 6 Bigger Blocks
In the Case Form, we name the variable being used for the comparison at the
head of the form and the constant values are listed, separated by commas ,as
the conditions. The Case Form is a special instance of the Select form where
the conditions test for equality to constants.
Figure 6.8 illustrates the difference between While and For loops by showing a
variation of one of the algorithms for calculating a product that we studied in
Chapter 5. Here, the product X × Y is calculated by summing values of X, Y
times. On the left of Figure 6.8, a standard While loop is used while on the
right the same algorithm is expressed using the For loop.
This new notation decreases the complexity of some algorithms since the full
counting mechanism is specified in the statement at the head of the loop
instead of having it stated in three separate statements as illustrated in
Pseudocode 6.8.
The For form is so powerful that it is used very often, but it is often also misused
for it requires a counter and such a counter may not be necessary or natural for
some applications!
Finally, the following two pseudocode fragments compare the pseudocode forms
for the While loop and the For loop (Pseudocode 6.11).
264 Chapter 6 Bigger Blocks
There are many limitations of the For form, which may make this form
unsuitable in some cases. For example, in most programming languages, the
initial value and the final value of the counter, which could both be given as
expressions, are evaluated only once on entry to this form, and thus should not
be changed inside the loop. Also, the counter should not be modified in the
body of the loop, since this would change the number of repetitions.
Additionally, in some programming languages, the initial, final and increment
values may not be zero or negative or of Real Number type.
Finally, after the loop terminates, the value of the loop counter (or loop control
variable) may be undefined! The While loop has no such restrictions, so you
may always use it in cases where these restrictions would cause problems to a
For loop.
Note the While loop is more general than the For loop. When in doubt,
you can always use the While loop.
See Figures 3.6 Pseudocode 6.12 shows two forms of an algorithm with doubly nested counting
and 3.15 for the loops. It is a version of an algorithm we have discussed in various forms in
verbal Charge Chapter 3, and that computes the total admission Charge if Adults pay three
algorithm along dollars each and Kids pay two dollars each. The algorithm creates a table of
with its table of charges for one to two adults and zero to three kids. On the top of the figure, is
charges. a version based on While loops. Because it is written using nested While forms
with all the counting mechanisms visible, the algorithm appears complex.
Section 6.4 Using the For Forms in Nests 265
On the bottom of Pseudocode 6.12, the same algorithm has been rewritten using
For loops. Notice that this notation hides most of the details. This version,
consisting of only three parts, two loop headers and a body, is much simpler
than the original one that has seven parts (two initializations, two tests, two
increments, and a body). We will prove that with the traces of the two
algorithms.
Set Adults to 1
While Adults ≤ 2
Set Kids to 0
While Kids ≤ 3
Set Charge to 3 × Adults + 2 × Kids
Output Charge
Increment Kids
Increment Adults
The first trace, shown on Figure 6.9, illustrates the execution of the algorithm
at the top of Pseudocode 6.12. The large amount of detail increases the
complexity of the trace, and this can be avoided, as we will see in the next
figure. In a trace all of the detail is needed for understanding how the
266 Chapter 6 Bigger Blocks
For Adults = 1 to 2 by 1
For Kids = 0 to 3 by 1
Set Charge to 3 × Adults + 2 × Kids
Output Charge
In Figure 6.10 we can see the trace of the algorithm at the bottom of Pseudocode
6.12. The two traces in Figures 6.9 and 6.10 are traces of equivalent algorithms.
However, we can see that the second trace is much simpler than the first one. It
simply lists all combinations of the loop control variables. The inner loop
control variable, Kids, changes more rapidly compared to the outer loop control
variable, Adults. The resulting Charge is also listed completing the entire
table of charges. Because the details are all hidden, the trace is much simpler!
Many algorithms involve loops directly nested within others, like the Charge
algorithm. Such algorithms have a similar behavior; they cycle through all
combinations, like a big counter, as illustrated by the following examples. This
cycling could be compared to that of a digital clock or a mileage odometer.
Let’s develop a timer, using a top-down approach, as shown on Figure 6.11. The
minutes counter loops from 0 to 59, and for each minute, the seconds counter also
loops from 0 to 59. The body of the seconds loop consists of a delay of one second
and a display of the minutes counter and of the seconds counter. Notice that the
inner loop counter (seconds) changes faster than the outer loop counter (minutes).
At the bottom of the figure, the nested loops are combined and shown in a single
piece of pseudocode.
Section 6.4 Using the For Forms in Nests 267
Hour Timer
Combining
these two
Hour Timer
For Minutes = 0 to 59 by 1
For Seconds = 0 to 59 by 1
Wait a Second
Output Minutes
Output Seconds
Pseudocode 6.15 shows how binary numbers can be generated in increasing order.
Its output is as follows:
000, 001, 010, 011, 100, 101, 110, 111.
This Binary Counter algorithm could be used to generate all of the possible
Those combinations to test the Majority algorithms seen in Chapters 3 and 5.
combinations
could then be Going one level deeper, Pseudocode 6.16 illustrates the For forms for a mileage
tabulated, as odometer.
seen in Figure
5.24. Pseudocode 6.16 Nested For forms for a mileage odometer
For Hundreds = 0 to 9 by 1 The outermost counter
For Tens = 0 to 9 by 1 changes most slowly.
For Units = 0 to 9 by 1
For Tenths = 0 to 9 by 1 The innermost counter
Output Hundreds changes most quickly.
Output Tens
Output Units
Output '.'
Output Tenths
Pseudocode 6.16 shows how four nested loops generate all decimal values from
000.0 to 999.9. Notice the order in which the values of the variables change.
Hundreds, the control variableof the outermost loop, changes the slowest
while Tenths, the control variable of the innermost loop changes the most
rapidly, just as they do on the odometer of an actual car.
Finally, Pseudocode 6.17 shows the Clock algorithm.
The nesting of many such loops is convenient and can be elegant, but not all
nestings are so well structured. In the following section we will look at more
examples of nested forms.
Calculate Pay
Get Hours
Set Regular to 0
Set Extra to 0
For Days = 1 to 7 by 1
Sum Regular and Extra hours
The development of the Fair Pay algorithm, in Figure 6.12, shows the nesting of
two Loops and a Selection, done in three stages. It describes the solution to a
pay problem where overtime is paid for all hours over eight worked in a day.
The first stage (or top level) consists of a single loop repeated for each Person;
first Get Hours is invoked and then the pay is calculated.
The second level, Get Hours, is then considered by itself, looping over the seven
days of the week to accumulate the number of hours (both regular hours and
270 Chapter 6 Bigger Blocks
extra hours). The accumulation of these two sums is then broken out at yet
another level, as a Selection form.
Similarly Calculate Pay could be broken down further. If all of these stages
were combined into one large stage, then the nesting might appear complex.
However, viewing them as stages, as done in Figure 6.12, makes the whole
algorithm seem simpler.
Notice that this example (Figure 6.13) involves four very different entities:
years, departments, employees and production. When four such diverse entities
are mixed in an algorithm, the result could be great confusion. Creating the
program in stages will help us minimize this confusion.
Figure 6.14 shows a trace of the input of the production data for a given year,
and of the corresponding result. Notice its structured form (with indentation),
Section 6.4 Using the For Forms in Nests 271
which reflects the structure of the data. Actually such large amounts of data
would not usually be input in such a “conversational” mode from where the
computer prompts you, but from a data file stored on tapes or disks.
Stage 1: Production
Set up
For Year = First to Last by 1
FindMaxProduction
PrintReport
Set MaxProd to 0
Set BestDept to 0
For Dept = 1 to N by 1
FindTotal Prod
CheckMax Prod
Output Year
Output BestDept
Output MaxProd
These three stages could be “pushed together” into a single big algorithm, but
this would hide its basic simplicity. Also, when an algorithm is kept in the
form of sub-algorithms, it is simpler to modify. For example, we could modify
Production to find the maximum departmental average production per person
by simply comparing the ratio TotalProd/Count in the Selection form of
CheckMax. Similarly, we could count the total number of people, accumulate
the total production and compute the best average production per person over
all the years (not just for each year). Such modifications are often made after a
program is written, so it helps to write the program keeping possible
modifications in mind!
Yint
8
X 0 1 2 3 4 5 6 7 8 9
10
0 * Y
6
1 *
4 2 2
Y=X *
3 3 *
2
4 *
X 5 *
1 2 3 4 5
X
In this sideways plot, each row contains only one mark (an asterisk * in this
case). We will view the printer head (or cursor) as “advancing” row by row
from top to bottom, and in each row from left to right. You may note that the
asterisks are placed into a grid of X versus Yint (and not Y), where Y int
represents the integer portion of Y.
X 1 2 3 4 5
1 4 16 25
Y 3 3 3 3 3
Y int 0 1 3 5 8
The table of Figure 6.18 shows how the values of the output Y are rounded into
integers Y int.
Plot
Print a line for Y int
For X = 0 to 5 by 1
Compute Y For Position = 0 to 10 by 1
Set Y int to Y If Position = Y int
Print a line for Y int Output "*"
Else
Output " "
274 Chapter 6 Bigger Blocks
On the left of Figure 6.19 is the top view of the graph-plotting algorithm. It
loops through the various values of X, first computing Y, then rounding it to Yint
and then printing a line corresponding to that value.
The sub-algorithm that prints a line is then refined and shown at the right of
the figure. The printing head advances, stepping Position from 0 to 10. If
Position equals Yint , then a mark is output, otherwise a blank is output.
Such a plot may be extended by displaying headers, marking the axes, and even
“scaling” any given values to fit onto a page or a screen. It can also be extended
to plot two functions as shown in Figure 6.20. Here, the Plot algorithm is
modified to compute a second value Zint , and the Print a Line sub-algorithm is
modified to output either an asterisk for the first function, a plus for the second
function or a blank. Further extensions to plot three or more functions are done in
a similar manner.
For Position = 0 to 10 by 1
f(x) If Position = Y int
Output '*'
Else
Y=X×X
If Position = Zint Extension for
Output '+' the plot of 2
Else functions
Z = K× X
Output ' '
x
Sum. When the input is terminated, the algorithm uses the Mod function to
find the Remainder of the division of Sum by 11. If that Remainder is 10, then
the check symbol is ‘X’. Otherwise, the check symbol is the Remainder itself.
For the truth Operations on Logical type variables include the assignment operation, the
table for the conjunction operation (AND), the disjunction operation (OR), and the negation
AND, OR, and operation (NOT). Pseudocode 6.21 illustrates a few examples of logical
NOT operators, assignments.
consult Figure
3.27. Pseudocode 6.21 Examples of Logical assignments
Set Male to True
Set Over21 to (Age > 21)
Set Danger to (Divisor = 0)
Set Done to (Counter = Last)
Set Triangle to ((Small + Mid) > Large)
Set Right to ((X × X + Y × Y) = H × H)
Set Close to (Abs(X - Y) < 0.001)
The conjunction operation is called AND. The conjunction of two logical variables
P and Q is written “P AND Q” and is true when both P is True and Q is True.
Some examples of the use of AND are shown in Pseudocode 6.22.
The disjunction operation is called OR. The disjunction of two logical variables
P and Q is written “P OR Q” and is true when either P is True, or Q is True (or
both are True). Some examples of the use of this “inclusive” OR are shown in
Pseudocode 6.23.
Section 6.5 More Data Types 279
The negation operation is also called NOT, and simply reverses the truth
values, changing True values to False and vice versa. Pseudocode 6.24 shows
some examples of its use.
See Figure 4.13 Algorithms involving complex combinations of Selection forms can often be done
for more details in a simpler manner by using Logical expressions. For example, triangles can be
on the different classified by the following series of Logical assignments (assuming angles
types of triangles A ≤ B ≤ C). Pseudocode 6.25 gives some examples of using Logical expression in
possible. place of Selection forms.
Note: Remember that True=1 and False=0. Hence, since 1>0, then
True>False.
• Column 1 shows the operation “P ≤ Q”, where the relation “less than or
equal to” is applied to Logical values. In symbolic logic, this operation
is the conditional connective called implication, usually denoted by the
symbol “P ⊃ Q”, which is read “If P then Q”. This conditional
connective is often used in logical deduction, where it is sometimes
noted as “P ⇒ Q” or “P → Q”.
• Column 2 shows the operation “P = Q” (the Biconditional connective).
It is read as “P if and only if Q” and is also noted in logic as “P ≡ Q” or
“P ⇔ Q”.
• Column 3 shows the operation “P ≠ Q” (the “exclusive or”) which is
True when one and only one of the values is True. It is sometimes noted
as “P <> Q”.
• Column 4 shows the operation “P > Q” (sometimes called the inhibit-
and) where the value of P is inhibited by Q.
Other Logical operations exist, for instance P < Q and P ≥ Q.
By refining this guessing algorithm for the particular problem to solve, this
bisectiontechnique can be applied to many problems, such as calculating the
square root of some number, X. This particular refinement is shown on the right
of Pseudocode 6.26. The behavior of this algorithm will be better understood by
looking at Figure 6.25, where the algorithm is used to find the square root of 24.
First, a High limit of 24 and a Low limit of 0 are set. The mid-point between
High and Low, 12, is chosen as a first guess at the square root of 24 and is set in
SqRoot. Since this guess is too high (12 × 12 > 24), the higher limit is lowered
to the middle value, SqRoot.
If the guess was too low, the lower limit would have been raised to the same
middle value. This same process is now repeated for the new limits. This
repetition continues until the two limits narrow down (or bracket) the solution
to the perfect match (SqRoot × SqRoot) = X, which corresponds to SqRoot, High
and Low having the same value.
282 Chapter 6 Bigger Blocks
SqRoot = 12 High = 12
This perfect match might prove elusive, and algorithms dealing with Real
Number results usually introduce the concept of precisionto determine whether
a result is acceptable or not.
For example in our SquareRoot algorithm, this would mean that the looping
continues as long as the square of the guessed root of X differs (in absolute value)
from X by more than some very small constant, the desired Precision. This
constant of Precision is initially chosen to be some small value, such as 0.1 or
0.00001. The smaller the value, the more looping is required to attain that
Precision.
Symbolically, the loop condition could use the absolute function value of the
difference and be written as
|SqRoot SqRoot – X| > Precision
instead of
(SqRoot SqRoot) X.
Let’s modify our SquareRoot algorithm along these lines, using function Abs to
obtain the absolute value.
Figure 6.26 shows a trace of the new SquareRoot algorithm computing the
square root of 24. Notice that this method of bisectionis not limited to just
square roots! It can equally compute the cube root by simply changing the loop
terminating condition to compare the cube of the current approximation with
the value X. The Bisection Method can also be used to find the roots of
equations.
Section 6.6 Some General Problem-Solving Algorithms 283
Input X X = 24
Bisection is a very general method for finding values, that will be useful later
in many problems. For example, we will use it again in Chapter 8, to search
quickly through a sorted list.
Circuit Relations
+ RS = 6
R = RS + RL
VS = 120 RL I = VS / R
P = I2 RL
Relations among the variables are given by the formulas on the right in Figure
6.27 (determined from knowledge of Ohm’s law and Kirchoff’s laws).
The behavior of such a system, given in Figure 6.28, shows how the power P (in
watts) varies, depending on the resistance RL of the load (in ohms). From this
graph, we see that the best value RLbest of the load resistor RL is 6 ohms (same
value as the series resistor RS), resulting in a maximum power PMax of 600 watts.
Power (watts)
P
800
200
Load (ohms)
RLbest = 6
10 20 30 RL
RLlow = 1 RLhigh = 34
The Process sub-algorithm could also find the half power points; those two
values of R L (say, R Llow and R Lhigh ) at which half power is sent to the load.
Those two values are shown on the plot of Figure 6.28 as being 1 ohm and 34
ohms. Any load value between these two would result in more than half power
being delivered. Notice that the half power points are not equally distant
from the maximum power point R Lbest. It is also possible to create an
algorithm that plots the power P versus the load resistor R L . Such a plotting
algorithm would be similar to the ones developed in Section 6.4 (Creating Plots
with For Nests).
In this case, the values of the load resistor R L were systematically selected in
increasing order, from 0 to some positive final value (which is 40 in this
example).
This example application gives us a model that we can apply to analyze other
engineering systems. For example, we may wish to find the optimal angle to
shoot some object so that it goes the farthest distance. Or we may wish to
compute the best combinations of selections to make optimal profits.
Sometimes, with some extra knowledge, we can avoid having to write an
algorithm to analyze a system. For instance, in the case of our example above,
we could have proven, by using calculus, that the maximum power occurs when
the load resistor R L equals the series resistor R S. However, in cases where the
systems are more complex (say nonlinear), then computer methods may be better
than analytical methods.
F (x)
y
6 Error Equations:
(of 4.0)
for F(x) = x2
4 x = 2.0
G(x) = 2 - x
Solutions:
2
x = +1.00
x x = -2.00
G (x)
-4 -2 0 2 4
For example, consider the following functions F(x) and G(x) shown in Figure
6.30:
The algorithm to apply this method, Solver, is shown in Figure 6.31. It consists
of a large loop that tries many values of x (say 200). Within this loop, for each
value of x, it invokes sub-algorithm Update Best that computes both functions,
finds their difference and keeps track of the smallest error and the
corresponding best x. Here are sample outputs for various executions of this
algorithm:
6.8 Glossary
system software, to indicate the end
Case Form: A variation of the Select of a set of values.
Form.
Terminating value: See Sentinel
Control Variable: See Loop Control value.
Variable.
6.9 Problems
1. Monthly Calendar
Create an algorithm top-down in pseudocode form to output a monthly
calendar given the number of days N in a month and the first day F
(where F=1 on Sunday, F=2 on Monday, etc.).
An example of a calendar follows for a month with N = 31 days having
a first day occur on a Saturday, so F = 7. Notice that such a month
requires 6 weeks!
Problem 1
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
2. Plot up
Create an algorithm top-down in pseudocode form to plot some function
F(x) vs. x, with the y-axis vertical and the x-axis horizontal. Use as an
example the previous plot of y = x2 / 3 for x varying from 0 to 5 and y
varying from 0 to 8 producing an output as shown below.
Problem 2
8
7
*
6
5 *
4
3 *
2
1 *
0 * *
0 1 2 3 4
5
292 Chapter 6 Bigger Blocks
3. Sine Function
The trigonometric sine of an angle x given in radians can be determined
from the first N terms of this series:
x3 x5 x7
Sine(x) = x − + − …
3! 5! 7!
Create an algorithm top-down to compute this sine function. Attempt to
improve upon this algorithm.
5. Second Max
Modify the Big Max algorithm in Figure 6.6 to find the second highest
value S, assuming that all values are different.
6. Many Max
Modify the Big Max algorithm to find the number of values N which
are maximum (when some values may be repeated).
7. MaxMin
Modify the Mean program (with sandwich in Figure 6.5) to compute
both the maximum and minimum values.
8. Quadrant
Create an algorithm that accepts the coordinates X and Y of some point
and indicates which quadrant (1, 2, 3 or 4) the point falls into. If the
point falls on an axis, the quadrant should be indicated as value zero.
9. Gas
Create an algorithm that inputs sequences of two values Miles and Gals
representing the odometer mileage and the gallons of gas at a succession
of refills of gas tank. The algorithm is to compute and output the
Section 6.9 Problems 293
INPUTS OUTPUTS
Miles Gals Short Long
1000 20
1200 10 20 20
1500 20 15 16.67
... ... ... ...
10. GPA
The grade point average GPA of a student is computed from all the
course grades G and units U. Corresponding to each grade is a numeric
value (where A has 4 points, B has 3 points, etc.) The products of each
grade point and its number of units are then summed. This sum is
divided by the total number of units, to yield the grade point average.
Create an algorithm to compute the grade point average for a sequence
of pairs of values G, U (ending with negative values to terminate).
11. Speed
Create an algorithm to analyze the speed during a trip of N stops. At
each stop, the distance D and time T from the previous stop are
recorded. These pairs of values are then input to a program which
computes each velocity (V = D/T) and outputs it. It also ultimately
indicates the maximum speed on the trip, and the overall average
(total distance divided by total time).
SAMPLE RUN (N = 5)
D T V
45 1 45
100 2 50
55 1 55
120 2 60 Avg = 380/8 = 47.5
60 2 30 Max = 60
294 Chapter 6 Bigger Blocks
Problem 13
Input N
Set S to 0
For I = 1 to N by 1
For J = 1 to N by 1
Set S to S + 1
Output S
14. Disproof
Show that the following two pieces of algorithm are not equivalent.
Problem 14
While A While A AND B
While B C
C
15. Expo
The exponential function Expo(x) can be computed from the first N
terms of this series:
x2 x 3 x 4
Expo(x) = 1+ x + + + +…
2! 3! 4!
a. Create an algorithm to compute this, assuming that Fact and Power
are available as sub-algorithms.
b. Create another algorithm that does not call any other sub-
algorithms, and also does not keep recomputing the factorial or
power (but uses previously computed results, such as 5! = 5×4!).
Section 6.9 Problems 295
18. Thanks
Create a general algorithm which outputs “THANK YOU” for a total
of N times (where N is input). This greeting is printed three times per
line (possibly less on the last line). There is a blank line after every
group of twelve greetings.
21. Binconvert
Create an algorithm to convert a sequence of binary input characters
(not integers) into their corresponding decimal values. For example,
1101 is the decimal 13.
a. Write the algorithm, if the input is read from left to right (ending
with a period).
296 Chapter 6 Bigger Blocks
b. Write the algorithm, if the input is read from right to left (ending
with a blank).
23. XOR-cise
Prove (or disprove) the following cancellation property for the usual OR
and the exclusive-or, XOR.
a. If (A OR B) = (A OR C)
B=C
b. If (A XOR B) = (A XOR C)
B=C
24. Translate
Convert the following conditions into Logical statements (using ANDs,
ORs and NOTs).
a. Neither A nor B.
b. Either A or else B.
c. Exactly two of the three variables A, B, C are True.
d. An odd number of the three variables A, B, C is False.
Section 6.9 Problems 297
298 Chapter 6 Bigger Blocks
Chapter Outline 299
Chapter Outline
7.1 Preview....................................................................300
7.2 Subprograms.............................................................300
How to Simplify Large Programs...............................300
What are Parameters?..............................................305
Data Space Diagrams...............................................309
7.3 Parameter Passing.....................................................312
Passing Parameters In and Out...................................312
Special Cases............................................................316
Some Examples.........................................................321
7.4 Bigger, Leaner, and Meaner Programs.........................329
Using Structure Charts..............................................329
Contour Diagrams.....................................................333
Parameter Crossing A Common Mistake....................336
Minimizing Coupling, Maximizing Cohesion..............338
Deeply Nested Subprograms......................................340
Dates Example..........................................................341
7.5 More Types of Subprograms........................................343
Recursion Self-Referencing Subprograms...................343
Functions...................................................................345
Modules....................................................................346
7.6 Review Top Ten Things to Remember........................348
7.7 Glossary...................................................................350
7.8 Problems...................................................................351
300 Chapter 7 Better Blocks
7.1 Preview
We have already used some simple subprograms or sub-algorithms, glossing
over the manner in which data are passed to them and how results are obtained
from them. Data transfers between program and subprograms is the subject of
this chapter.
We will first consider subprograms, functions and block structurefrom three
viewpoints:
• Control flow,
• Data flow,
• Data space (introduced for the first time here).
To pass data into and out of subprograms, a special kind of variable called a
parameteris used. Parameters are considered in great detail in this chapter, in
particular the way in which they are used to pass data. There are two
methods by which data are passed through parameters:
• by value, and
• by reference.
Recursion, the ability for a subprogram to call itself, is also briefly introduced
here as another control structure.
A number of examples of some small and simple blocks are given, along with
some larger examples: a payroll program and a change maker program.
Although the full power of subprograms is mostly felt with large programs, the
smaller programs of this chapter make it possible to illustrate them in a
convincing manner.
The chapter ends with the idea of modules, or pieces of a program that are
written separately, compiled separately, and that are later linked together to
form the complete program.
7.2 Subprograms
Actions
Temp
Action Group A Global data are
still accessible
to all of the actions.
Action Group B
Problem: communication
between pieces Action Group C Data
is too complex.
Action Group D
Actions
The program Split Structure, shown in Figure 7.2, has been split into groups
shown as Action groups A, B, C and D. In practice, there would be many such
groups, possibly hundreds, in a large program. There is considerable
302 Chapter 7 Better Blocks
communication between the action groups; not only are they linked by flow of
control but they also have access to the same set of global data, which may
have thousands of separate items.
This means that the teams responsible for the different groups need to know
what the other teams are doing –the communication between the pieces of a
program is reflected in the communication between the teams. Also, any piece
of program may access any data, so the sharing of data, a form of
communication, becomes complex.
For example, two different teams may be using the same variable, Count, in two
different ways and incrementing it for different reasons at different, possibly
incompatible time. They might also be using the same “temporary” variable
Temp and have to coordinate their uses to avoid clashes.
Clearly, this semi-structured way of breaking down a program is not ideal. On
a larger scale, most programs that are structured in that way will fail because
of the complexity of communication between the teams working on the various
pieces of the programs.
Hidden Data
These local
Global data
data are not available to
accessible by
any other all parts of
the program
subprograms
but this one.
In Figure 7.4, there still remains some global data accessible to all subprograms,
but fewer of them. These data are mainly used for communication between the
subprograms. This kind of structuring allows programming teams to be more
independent because they have more control over the data that they alone need
to know about.
Best program
structure: it uses a
minimum amount of
communication
between parts.
Local data
Parameter
X Y If X > Y
Pass-in X , Y
Set M to X
Max Max Else
M
Pass-out M Set M to Y
parameters
The data-flow diagram shown on the left of Figure 7.6 gives an external view of
the subprogram Max which we already encountered in Chapter 3. In this view,
Max is seen as a black box with two inputs X and Y and one output M , the
maximum of the two values X and Y.
Another external view of Max is shown in the middle of the same figure by
another black box called Max, having three variables X, Y and M . These three
variables are parametersand are used for communicating data with the
programs that use Max. This view, like the one on the left, shows nothing of
the way in which M is derived from X and Y.
Finally, at the right of the Figure 7.6, the subprogram Max is defined
completely with all its detail as a glass box. Here we can see exactly how the
value of M is obtained from X and Y.
Although X, Y and M are all parameters of the subprogram Max, X and Y serve a
different function from M . X and Y transfer information from the caller into the
subprogram and are called input parameters. The parameter M works in the
opposite way, it transfers the result of the computation out of Max, back to the
caller. It is called an output parameter. The definition of the number of
parameters, their data type and whether they are input or output, form the
subprogram’s interface specification.
Parameters are subprogram variables used to communicate data between the
subprogram and either the main program or another subprogram.
Section 7.2 Subprograms 305
Figure 7.7 Data-flow diagram for Max3
A B C
subprogram X Y
parameters Max Max3
M Input A, B, C
E Max( A , B , E ) program
Max(E, C, L) arguments
X Y
Max Output L
M End Max3
To see how such a subprogram is used, let’s look at a program to find the
maximum of three variables. At the left of Figure 7.7, the data-flow diagram
of the program Max3 shows how we can obtain the maximum of the three
variables by interconnecting two of the Max subprograms. The right side of
Figure 7.7 shows the inner workings of Max3. As we could have guessed from
the data-flow diagram, the subprogram Max is invoked(or called) in the
following two ways:
• In the first call, Max (A, B, E), Max3’s variables A, B and E are
connected to Max’s parameters X, Y and M . The values of A and B are
transmitted to X and Y, the input parameters. The result of the
calculation, the maximum of the two value X and Y, is transmitted
through M , the output parameter, to E
• Similarly, in the second call, Max (E, C, L); Max3’s variables, E, C, and
L, are connected to Max’s parameters X, Y and M . The values of E and C
are transmitted to X and Y, the input parameters. The result of the
calculation, the maximum of the two values X and Y, is transmitted
through M , the output parameter, to L.
In the first call, A, B, and E, and in the second call E, C, and L, are said to be
arguments. Thus, in a subroutine call, a connection is established between the
caller’s arguments and the subprogram’s parameters and the values are
transmitted through this connection.
Let’s look at a non-computer example from everyday life to help us understand
this “connection” between arguments and parameters: bungee-jumping. Here
is a program which, if followed, would make sure a person had an exciting day.
306 Chapter 7 Better Blocks
Pseudocode 7.1 Program for an exciting day of bungee-
jumping
Pr ogram Excitement
Get up at dawn.
Go do some bungee-jumping .
Tell all your friends how exciting it was.
Go to bed.
In both cases, most of the steps in Program Excitement remain the same. Only
the name of the sport varies: we call bungee-jumping or sky-diving in the
program. If we take a closer look at the line Go do some bungee-jumping, we
notice that it refers to more instructions.
Actually, the line Go do some bungee-jumping is a subprogram invocation. It
calls SubProgram Go do some dangerous sport and performs its instructions by
replacing dangerous sport with bungee-jumping each time dangerous sport is
written. We call dangerous sport the subprogram’s parameterand bungee-
jumping the main program’s argument. This program and subprogram are shown
in Figure 7.8.
Program Excitement
Get up at dawn. argument
Go do some bungee-jumping.
Tell all your friends how exciting it was.
Go to bed.
Notice that the subprogram is general enough so that is may be used for just
about any risky sport: bungee-jumping, sky-diving, heli-skiing, and so on. Its
parameter remains the same for each of them. However, as the sport practiced
changes, so does the main program’s argument. If you preferred to go sky-
diving, as mentioned above, only the argument bungee-jumping would need to
be changed. The rest of the program (including the subprogram) would remain
as is. Figure 7.9 shows our Excitement program modified for sky-diving.
Program Excitement
Get up at dawn.
Go do some sky-diving.
Tell all your friends how exciting it was.
Go to bed.
To see these To introduce the concept of a data space diagram, let’s consider again the
algorithms in Divide subprogram. We already saw Divide in Chapters 3 and 5, and used it in
more detail, see many algorithms such as Change Maker, Convert Grams, and Decimal to
Figures 3.32, 3.24, Binary. A particular version of the Divide subprogram is shown in Figure 7.10.
3.25, 3.26 and
3.35.
308 Chapter 7 Better Blocks
Figure 7.10 A version of the Divide subprogram
Local variable
Numerator Divisor Num Count
Denom
Divide ( Num, Denom, Quot, Rem )
Num Denom Set Rem to Num
Divide Set Count to 0
While Rem ≥ Denom
Quot Rem
Set Count to Count + 1
Set Rem to Rem – Denom
Quot Set Quot to Count
Quotient Remainder Rem End Divide
Parameters
On the left of Figure 7.10, there is a data-flow diagram of Divide, showing that
it has four parameters. Two of them, Num and Denom, are passed in and the
other two, Quot and Rem, are passed out.
On the right of the same figure, the corresponding data space diagram shows
the actual space occupied by the variables associated with the subprogram.
Also shown here is the pseudocode of the subprogram, from which we see that
Divide makes use of a temporary variable Count in the course of performing the
division. Count is private, or local, to Divide. Programs that make use of
Divide do not need or have access to Count.
In the pseudocode for the subprogram (Figure 7.10), the title line shows the
names of the subprogram’s parameters, Num, Denom, Quot and Rem. The
underlining of the names of two of the parameters, Quot and Rem, denotes that
their values will be passed out of the subprogram.
Figure 7.11 presents a general example of a data flow and data space diagram
for a subprogram Sub with five parameters. The data space diagram at the
right of the figure also shows the connections between arguments and
parameters for this invocation of Sub:
Sub(A, B, C, Y, Z)
In such a call, the arguments are enclosed in parentheses and separated by
comas.
The subprogram Change, shown in Figure 7.12, has six parameters: an amount
tendered T and a cost C, which are passed-in, and the number of quarters Q,
dimes D, nickels N, and pennies P that form the change, which are passed-out.
There is also a local variable R, representing the remaining money at each
stage during the computation of the change.
A+B 2
inputs
1 2
Num Count Divide ( Num, Denom,
Num Denom Denom
Quot, Rem )
Set Rem to Num
Divide Set Count to 0
Actions While Rem ≥ Denom
Quot Set Count to Count + 1
Quot Rem Rem Set Rem to Rem–Denom
Set Quot to Count
3 4 End Divide
outputs
C D
Our program Average Example is shown in Figure 7.15 and uses this same
subprogram Divide to find the average of two values A and B. It also displays
“Exactly” when the computed average is exact. Otherwise, it displays
“Approximate”.
We will use our Average Example program to describe in detail what happens
when a subprogram is invoked. The statement that invokes the Divide
subprogram is the same as before:
Divide(A + B, 2, C, D)
Executing this invocation causes the following sequence of actions:
1. The point of return in AverageExample is immediately noted. The
point of return is the point to which control will return after Divide has
completed its work. Here, the point of return is the statement: Output
C.
2. The variables for the input parameters of Divide and the local
variable are set up. We prepare memory space to hold the values for
Num, Denom, Count. Note that no memory space is reserved for the two
output parameters Quot and Rem. Remember from the last section that
only solid boxes take up memory space.
3. The links between the Average Example program and the Divide
subprogram are established by setting up a correspondence between the
arguments in the invoking statement Divide(A + B, 2, C, D) and the
parameters shown in Divide’s header Divide(Num, Denom, Quot,
Rem)
a. The expression A + B is evaluated to 7 and that value is copied
into Divide’s variable Num.
b. The value 2 is copied into Divide’s variable Denom.
c. The name of AverageExample’s variable C is linked to Divide’s
parameter Quot so that Quot acts as an alias for C.
d. The name of AverageExample’s variable D is linked to Divide’s
parameter Rem so that Rem acts as an alias for Average Example’s
variable D.
324 Chapter 7 Better Blocks
As soon as a positive Value is entered, the loop terminates. The subprogram
then assigns that positive Value to the output parameter Result, setting the
value of Age and thenHeight in the main program. Using Result as an output
parameter like this allows the subprogram EnterPos to be recycled. EnterPos
can be used over and over to enter values into many different variables (such as
Age and Height in the Opinion Poll program shown in Figure 7.31).
MainPay
Set Total to 0
Input Num
For EmpNum = 1 to Num by 1
NetPay(Total)
Output Total
End MainPay
NetPay(Amount)
GrossPay(Gross)
Deductions(Gross, Deduct)
Set ActualPay to Gross – Deduct
Output ActualPay
Set Amount to Amount + ActualPay
End NetPay
The algorithms and sub-algorithms that comprise MainPay are shown in Figure
7.33 as break-out diagrams of pseudocode, with the dotted lines representing
the flow of control when subprograms are called. The program MainPay inputs
the number of employees Num, and then executes a loop Num times, once for
each employee. The body of the loop calls NetPay with Total as an argument,
so that it can update the total pay as each employee’s pay is calculated.
Finally, MainPay outputs the Total amount paid out.
326 Chapter 7 Better Blocks
Subprogram NetPay calls subprograms GrossPay and Deductions to be able to
calculate the Actual Pay and output it, and Actual Pay is also used to update
the Total in MainPay. The GrossPay subprogram computes the gross Pay in the
usual way. Subprogram Deductions obtains the miscellaneous deductions Misc
by calling GetMiscDeductions, and adds this to the Tax, which is a simple
percentage Rate of the Gross pay. All these variables are either local or
global and we will use a data space diagram to show where they belong.
Deductions(Gross, Total)
Amount Gross Tax
Misc
Rate
Total
The data space diagram of MainPay, in Figure 7.34, shows how data are
distributed among the subprograms. Notice first that the main program
requires only three variables of its own (the count Num, the loop control
variable EmpNum, and the amount Total), and need not have access to other
variables at lower levels! Notice also that the gross pay appears three times
in three different subprograms:
1. The actual gross pay is first computed in subprogram GrossPay and
assigned to parameter Pay which is passed by reference.
2. Because the parameter Pay is an alias, this computed gross pay is in
fact assigned to variable Gross in subprogram NetPay (the GrossPay
call argument).
3. The same gross pay is also passed to subprogram Deductions as a value
parameter where it is used to initialize Deductions’ parameter Gross.
Notice that, although both NetPay and Deductions have variables
called Gross, they are quite distinct and occupy separate storage.
It is important to see that subprogram Deductions did not get the gross pay
directly from subprogram GrossPay, but indirectly through subprogram NetPay
at a higher level. This sub-dividing and hiding of data spaces is very
significant in large systems. It localizes the various data values, and respects
the hierarchy of subprograms defined by the structure chart for a system like
Figure 7.35.
Section 7.4 Bigger, Leaner, and Meaner Programs 327
Figure 7.35 Structure Chart for Main Pay
MainPay
NetPay
GrossPay Deductions
GetMiscDeductions
This subdivision of the data space is extremely helpful when you are trying to
find and correct an error in a large program. It reduces the amount of program
that you must read and understand before you make a change. Making a local
change without really understanding all its ramifications is not good enough.
Even though the program may appear to work after the modifications have
been made, it may not have been properly tested. The subdivision of the data
space clearly defines the boundaries of possible ramifications. The big picture
of the system offered by the structure charts helps to see this.
We will have yet another look at the MainPay example by means of a data-
flow diagram, as shown in Figure 7.36. That figure shows how the external
data flow in and out of the program, as well as how the data flow between the
subprograms through arguments and parameters. The external inputs are the
Hours, the pay Rate, the miscellaneous deductions Misc, and the number of
employees Num. The external outputs are the ActualPay and the Total amount
paid.
The hiding and sharing of data, when done properly, leads to a simplification
of the building of the program with minimal interaction between the
constituent subprograms. Each subprogram communicates only with its superior
in the structure chart. Ideally, each subprogram is provided with only what it
needs to perform its function:
• At lower levels, the system components need individual details of
hours worked and rate of pay.
• At higher levels, the system components do not need the same details
but need instead the total number of employees and the total amount
paid.
328 Chapter 7 Better Blocks
Figure 7.36 Data flow of Main Pay and its subprograms
GrossPay
Misc
Actual Pay Total
Number of Gross
Employees
For instance, the Deductions subprogram needs the value of the gross pay, to use
but not modify, in its computation. However, it does not need the net pay or the
number of employees.
The interconnection of programs with many subprograms is often shown by trees
or contour diagrams. Those are considered next.
Contour Diagrams
Contour diagrams are similar to the data space diagrams we saw earlier in
Section 7.2. They are made up of blocks—each representing a piece of program
with its own data space. The blocks are nested one within another, showing
the hierarchy of the program. A contour diagram of the Main Pay program is
shown in Figure 7.37.
Notice that there are three types of information shown:
• The program or subprogram names
• Local variables
• Parameters passed in and passed out of the subprogram
As we can see, information can both be shared between blocks, and hidden from
other blocks. Block-structured languages (like Algol 60, Pascal, Modula-2, C,
and Ada) take advantage of this sharing/hiding of information.
Section 7.4 Bigger, Leaner, and Meaner Programs 329
Figure 7.37 Contour diagram of Main Pay
MainPay Num
EmpNum
NetPay(Amount) Gross Total
Deduct
ActualPay
GrossPay(Pay) Break 40
Hours
Rate
Pay
Total
Amount
The variable access rules introduced in Section 7.3 apply directly to the blocks.
Let’s see how the rules apply to Figure 7.37:
• Rule 1: A (sub)program cannot access the local variables of any
subprograms nested within it.
Here, subprogram NetPay cannot access (use) the local variables Break,
Hours, Rate, Rate, Tax, Misc, since the subprograms GrossPay and
Deductions are nested within it. We could say that these inner
variables are kept protected from the outside world. (You will note
here that there are 2 separate variables named Rate in our program,
each referring to something different. The one in GrossPay refers to an
hourly rate of pay whereas the other in Deductions refers to the tax
rate.)
• Rule 2: A (sub)program can access a variable that is local to itself.
Here, subprogram NetPay can access its local variables Gross, Deduct,
and ActualPay.
• Rule 3: If a variable does not appear in a subprogram, a search is made
in the enclosing subprograms. This search is continued until either:
• The variable is found, or
• The main program is reached.
If the variable is not found in any of these nests, then the variable is
undefined and there is an error in the program.
Here, subprogram NetPay can access the variables Num, EmpNum, and
Total (as well as its own local variables, as we saw in Rule 2). We can
see this by “looking out” of NetPay to the next higher level(s). In our
case, there is only one higher level: the main program. This rule of
“looking out” is also called the “most-closely-nested binding rule”,
where the term bindingrefers to the relations between variable names
and data spaces.
330 Chapter 7 Better Blocks
Another useful term to know is the scope of a variable. This refers to the part of
a program over which a particular name is “known”, or may be referenced. In
our example, the scope of Num is the whole program. This comes about because
it is defined in MainPay and nowhere else—by the application of Rule 3. The
same is true of EmpNum—they are both global variables.
However, this is not true of Total, the third variable defined in MainPay,
which is also defined with a different meaning in Deductions. Thus, the scope
of Total defined in MainPay is the whole program except for Deductions. This
illustrates the dangers of Rule 3 and how careful we must be in our program
design to avoid accessing the wrong variable.
Tables of bindingshow how variable names relate to the data spaces of various
blocks. A table for Main Pay is shown in Figure 7.38. There is one row for each
variable or parameter name, and one column for each (sub)program block. The
table is filled as follows:
• If a given name is accessible in a block, the corresponding entry shows
either “Defined” or “Access”.
• If the name is inaccessible the entry is empty.
• An entry like “Defined” indicates the name is defined in the block
either as a variable or as a parameter.
• If the entry is “Access” the name is accessible.
• When there is more than one definition, the definitions and accesses
are numbered to show what name is accessible.
Variables only defined in the MainPay block are global and can be accessed
from all the subprograms. Such global variables may seem useful. For example,
the number of the employee EmpNum could be accessed directly from the
NetPay subprogram (without passing it as a parameter) and output onto the
Section 7.4 Bigger, Leaner, and Meaner Programs 331
paycheck. However, this variable EmpNum could also be changed by accident
in any of the subprograms. This kind of error could be very hard to find.
Tip: Reference only those variables that are defined in the subprogram
in which you are working. Any time you think that using a global
variable would be simpler, look instead to see how the program’s
design could be improved to avoid it. A global variable’s potential
for causing trouble is much greater than the simplification it can
bring to the program. Access to all variables that are not local
should be done only through parameters.
GrossPay
MainPay NetPay
Deductions
The couplings between the four blocks of Main Pay are shown in Figure 7.40.
There are essentially only four interactions, each shown by a line connecting the
blocks. These respect the hierarchy established by the structure chart of Figure
7.35. Most interactions in the figure are through parameters passed by
reference, which implies a two-way communication, and only one is through a
value parameter (one-way). Since all the interconnections are through
parameters, we say that these blocks are loosely-coupled.
Block 3
Block 1 Block 2
Block 4
Section 7.4 Bigger, Leaner, and Meaner Programs 333
In contrast, Figure 7.41 shows a similar set of four blocks where every block
interacts in both directions with every other block, forming 12 such interactions.
These interactions are through global and local variables. This kind of system,
referred to as tightly- coupled, would be quite complex and difficult to
understand and maintain.
Maintaining a tightly-coupledsystem is difficult because the hierarchy of the
structure chart has disappeared, and any modification is likely to affect more
than one module, making it complex and error prone. In other words, if you
forget just one of the changes required to keep all the blocks consistent, your
program will most likely have an error.
Generalizing the interactions from this 4-block example to any number N of
blocks is quite simple. In the present case, each of the 4 blocks connects to all of
the remaining 3 blocks for a total of 4 × 3 or 12 interactions. In general, each of
N blocks connects to the remaining (N-1) blocks for a total of N(N-1)
interactions:
• For 5 blocks, there are 5 × 4 = 20 interactions.
• For 10 blocks, there are 10 × 9 = 90 interactions.
• For 20 blocks, there are 20 × 19 = 380 interactions.
As you can see, the maximum number of interactions grows quickly—almost as
fast as the square of the number of blocks. If we assume that checking a
modification implies checking all interactions, you can see why the number of
interactions must be kept low! That is why loosely-coupledsystems are
preferred. They are usually easier to maintain than tightly-coupled ones.
ChangeMaker
Instruct
Output Change
Make Change
SpellOut
Divide
Plural
Enter Amounts
CountOut
InCost InTend
Size
EnterPos Convert
CheckProper
Some parts of Notice that this contour diagram is lacking some essential things:
ChangeMaker • The local variable boxes have not been drawn in.
have already
• The parameters (passed in or out) have not been drawn in either.
been developed
in pseudocode in • The main program, ChangeMaker, calls four subprograms: Instruct,
Chapter 4, Make Change, Enter Amounts and Output Change.
Section 4.4.
• The first subprogram, Instruct, asks if the user wishes instructions. If
so, the subprogram produces a printed set of the user instructions.
• The second subprogram is Make Change that actually performs the
change making computation. To do this, it calls the subprogram Divide
a number of times.
• The third subprogram, Enter Amounts, contains five other subprograms
to help input the various values and validate them. Subprograms
InTend and InCost input and validate the amount tendered and the
cost. Subprogram EnterPos is used to enter only positive values, and
subprogram Convert is used to change the numerical values into
monetary values. Subprogram CheckProper checks that the cost and
the amount tendered are positive and that the cost is less than the
amount tendered.
• The last subprogram, Output Change, contains other output subprograms
A more detailed
and calls them to produce a nicely formatted output. Subprogram
SpellOut is
SpellOut spells the count corresponding to the number of coins, and calls
shown in Figure
P l u r a l to append the character “s” to any written plural denomination.
7.30.
Subprogram CountOut provides a readable output of the number of coins,
and calls Size to determine the number of digits in a number as part of
formatting the output values.
Section 7.4 Bigger, Leaner, and Meaner Programs 335
Dates Example
So far, we have always tried to develop our various algorithms using a top-
down approach, and this has usually led to better structured solutions.
However, very often in programming, there is a temptation to create all
algorithms from their smallest building blocks (starting everything from
scratch). We have seen that it is better to create algorithms out of larger
“abstract” boxes whose exact functions are yet to be defined, and later, when we
are more advanced in the design, we can define these boxes in detail.
In computer applications, dates are a type of data that must often be
manipulated. They usually are made of several parts, like day, month, and
year. In the next example we will concentrate on date processing.
ElapsedTime
InputDate(Date1)
InputDate(Date2)
ElapsedDays(Date1, Date2, Elapsed)
Output Elapsed
End ElapsedTime
Our date example will be the creation of the algorithm ElapsedTime, which
determines the number of days between any two given dates in the same year,
such as two birth dates. Figure 7.43 shows the top two levels of the solution
chosen for ElapsedTime. Proceeding top-down, the top-level program first
inputs the two dates, computes the number of elapsed days between them, and
then outputs that value.
Notice that, at the top level, we refer to the two dates as Date1 and Date2,
ignoring the fact that they are made up of two separate values: the month and
the day. This abstraction makes it easier to avoid getting bogged down in
details. At the next level of InputDate, these constituents are recognized since
the Month and the Day are input. However, their combination into a single
data value is left unspecified in a call to MakeDate, which is, as of yet,
undefined.
The elapsed time between the two dates could be determined easily by
ElapsedDays if we knew the date in its Julian form, as the number of days from
the first of the year. The number of elapsed days can then be found by simple
subtraction of the two Julian dates. In the solution shown in Figure 7.43, we
have assumed that a subprogram, NumDate, to compute the number of days from
the start of the year already exists.
336 Chapter 7 Better Blocks
Figure 7.44 The subprogram NumDate to find a Julian date
NumDate(Date, Julian)
Set Julian to 0
AccumulateDays(Date, Julian)
Set Julian to Julian + Date.Day
AccumulateDays(Date, Total)
For MonthCount = 1 to Date.Month – 1 by 1
Set Total to Total + Days(MonthCount)
The subprogram, NumDate, converts a given Date into the number of days from
January 1, as shown in Pseudocode 7.6. For example, March 15, l984, has a Julian
dateof 75, (31 + 29 + 15). At this point in our development of the ElapsedTime
program, we realize that in order to find the Julian date, we probably need to
know how many days there are in February. For that, we need to know the
year. Therefore, we must go back to our sketch of InputDate and add a
statement to input the year. Notice that ElapsedTime does not have to be
changed—this is an example of the advantages of designing subprograms with
high cohesion.
Since we have only outlined Input Date, little has been changed. Each date
now has three components, Year, Month and Day, instead of only two. This
need to revise earlier subprogram outlines is typical of the program creation
process and is a major reason for proceeding top down. If we had completely
created InputDate, the change would have been much more serious and
frustrating.
Thus, recursion is a process where a subprogram will call itself. Such a self-
referring process may seem unusual at first, but many data structures and
algorithms are more naturally described recursively. In this section, we only
introduce the idea of recursion. It will be dealt with in greater depth in
Chapter 8.
Recursion in its simplest form could be viewed as an alternative to the iterative
form. To illustrate this, let’s take as an example the computation of the square
of an integer. We saw in Chapter 6 that the square of integer Num can be
computed by summing the first Num odd integers. A subprogram that calculates
the Square of a number this way is shown in Pseudocode 7.7 where we find an
iterative version and a recursive version.
If 3 = 1
Else
RecursiveSquare(2, Square)
Stepping
down a level
If 2 = 1
Else
RecursiveSquare(1, Square)
stepping down
another level
If 1 = 1 lowest level
Set Square to 1
Set Square to 1 + (2 × 2 - 1) = 4 stepping back
up one level
Each call of the subprogram yields a contour, resembling levels on a map (stair-
trace). On entry to a subprogram, we step down a level, and then on exit we step
up again. It is important to have a “lowest” level, a stopping point (or a base
case, such as Num = 1), otherwise, the algorithm would be “bottomless” or
unending. This lowest level is shown shaded on Figure 7.45.
At this time, you do not need to know by which mechanism recursion is
See Section 7.3 performed. It is only necessary to know that after a recursive call, like after
for more details any subprogram call (and subsequent detour), the control must “return to the
on returning caller”.
control to the
caller. Remember in Figure 7.15 that the first action done when Divide was invoked
was: “The point of return is noted.” In our case, this means that after each
recursive call, the assignment of a new value to Square is performed, as shown
in Figure 7.45. In Chapter 8, we will take a look at the actual mechanism for
recursive calls.
Functions
See Figure 5.42 There is another kind of subprogram that is useful in some circumstances: the
for more details function. When we first introduced subprograms in Chapter 5, we gave the
on Convert example of a program, Convert Seconds for converting a number of seconds into
Seconds. days, hours, minutes and seconds.
Instead of using the Divide subprogram, which calculates both the quotient and
remainder, we used the following two subprograms:
• Div, which found the quotient, and
• Mod, which found the remainder.
The Convert Seconds algorithm is shown in Pseudocode 7.9.
Section 7.5 More Types of Subprograms 339
Pseudocode 7.8 The Convert Seconds program
Convert Seconds
Input Time
Set Days to Div(Time, 60 × 60 × 24)
Output Days
Set Seconds to Mod(Time, 60 × 60 × 24)
Set Hours to Div(Seconds, 60 × 60)
Output Hours
Set Seconds to Mod(Seconds, 60 × 60)
Set Minutes to Div(Seconds, 60)
Output Minutes
Set Seconds to Mod(Seconds, 60)
Output Seconds
End Convert Seconds
Div and Mod are very much like the subprograms we have been using in this
chapter, with one important difference. In all our examples in this chapter, we
have had subprogram invocations of the form:
Divide(Time, 60 60 24, Days, Seconds)
where the third argument, Days, is used to return the quotient. In Convert
Seconds we use Div very much like a mathematics function, like, for example
the trigonometric function Sine. For this reason, the two subprograms Div and
Mod are known a functions.
The major difference between subprograms and functions is that functions,
rather than having an argument to return the result of their computation,
actually produce the value in a form which can be used directly. This is very
convenient in situations where the subprogram has only a single value to return.
This would obviously not work with the Divide subprogram since it returns two
results, the quotient and the remainder. The pseudocode for the Mod function is
shown in Pseudocode 7.10.
7.7 Glossary
Alias: An identifier that refers to a Pass by reference: A method of
variable that is also known by parameter passing whereby the
another name. For example, the parameter is the alias of the
name of a parameter that is passed corresponding argument.
by reference; since it refers to a
variable in the calling program, it is Pass by value: A method of
an alias for that variable. parameter passing whereby the
parameter is a local variable that is
Argument: A variable, expression or assigned the value of the
constant that is passed to a corresponding argument.
subprogram in the invocation
statement. Recursion: A situation in which a
single subprogram invokes itself.
Base case: The special case in a
recursive subprogram that causes the Scope: The part of a program where a
recursion to terminate. particular identifier is known.
7.8 Problems
1. Divide Again
Create an algorithm to Divide using a subprogram which multiplies. It
may not be efficient, but it shows another way of doing something.
2. Trace Subs
Draw a data-flow diagram corresponding to the given interconnection
of the subprograms below. Trace this program for A = 0 and B = 1.
Draw a tree showing the calling of subprograms and indicate the order
that the subprograms are called in.
Problem 2
A A
P(A, B, C) A N(A, B)
Main B B Set C to A × B Set B to 1 – A
Input A C End P End N
D C B
Input B
E
N(A, C) F
A D
P(C, B, E) G Q(A, B, C)
B E
N(B, D) N(A, D) F
P(A, D, F) N(B, E)
Q(E, F, G) P(D, E, F)
Output G N(F, C)
End Main C End Q
3. Deep Nests
Given the nested blocks shown in the following diagram, indicate
which blocks may be called by each block. If a variable X is declared
in E only, which blocks can access it? If a variable Y is declared in B, D
and F, but is referenced in all of the modules, which variables (if any)
are accessed or “seen” in each module?
Problem 3
A
B
C
D
E
F
G
H
Section 7.8 Problems 345
Problems on Subprograms
4. Divide-And-Conquer
Use the previously defined Divide subprogram to:
a. convert pints to gallons, quarts and pints.
b. convert a decimal number to binary.
c. determine whether a year is a leap year.
d. convert 24-hour (military) time to civil time, indicating AM or PM.
5. Data of Easter
The algorithm to determine the data of Easter for any given year could
involve a number of Div and Mod actions. Create a subprogram to
determine the data of Easter according to the following algorithm for
an input parameter Y, whose value is the year:
1. The “golden number”, G is (Y Mod 19) + 1.
2. The century number C is (Y Div 100) + 1.
3. The number of years X in which leap year was dropped, e.g., 1900,
so as to keep in step with the sun is (3C Div 4) - 12
4. A correction Z to synchronize Easter with the moon’s orbit is (8C + 5)
Div 25.
5. If D = (5Y Div 4) - X - 10 then March ((-D) Mod 7) is a Sunday—if (-
D) Mod 7 = 0 then March 7 is a Sunday.
6. The “Epact” E specifies when a full moon occurs. E = (11G + 20 + Z -
X) Mod 30. If E = 25 and G is greater than 11, or if E = 24 then E is
increased by 1.
7. Easter is on the “first Sunday following the first full moon that
occurs on or after March 21”. The “calendar moon” used for finding
Easter is defined as the Nth of March where N = 44 - E. If N < 21
then set N to N + 30.
8. To advance N to a Sunday, set N = N + 7 - ((D + N) Mod 7.
9. If N > 31 then the data of Easter is the (N - 31) April; otherwise,
the date is N March.
6. Double All
What is output by the following program when it passes parameters by
reference?
Problem 6
Main Program
Set X to 2
Double(X, X, X)
Output X
Double(A, B, C)
Set A to A + A
Set B to B + B
Set C to C + C
346 Chapter 7 Better Blocks
7. Dates
Use some of the previous algorithms (Leap, Days) and create:
a. Valid, an algorithm to test whether a given date Year, Month, Day
is a valid date.
b. UnDate, an algorithm to convert a Julian date Julian,Year back into
the Gregorian form Day, Month, Year.
c. DaysLived, an algorithm to determine the number of days a person
has lived, from the birth date to the present date.
d. Age, an algorithm to determine the (integer) age of a person.
e. WeekDate, an algorithm to determine the weekday a given date
falls on, when given that the first day of the year falls on the Wth
day (where W = 0 for Sunday, W = 1 for Monday, … and W = 6 for
Saturday).
f. FirstDate, an algorithm to determine the weekday of New Year’s
Day, given the year Y. Use the fact that January 1, 1901 was a
Tuesday (W = 2). Notice that a year of 365 days has exactly 52
weeks plus one day (i.e. 52 × 7 = 364).
8. Bind Dates
Create a binding table and contour diagram for any of the above Dates
programs.
9. Range
Create an algorithm that reads in three values A, B, C and outputs the
range R, which is the difference between the largest and smallest
values. This must be done using the following subprograms. Provide the
maximum hiding of variables and subs possible.
The main program Range is to call a subprogram
B i g S m a l l 3 ( I , J , K , L , S ) , which finds the largest L and smallest S
of the parameters I , J , K. This subprogram in turn calls two functions
B i g ( P , Q , R ) and S m a l l ( P , Q , R ) , each of which must call a
subprogram Sort2(G, H), which takes G and H, and arranges them so
that G is largest and H is smallest.
Two-Dimensional Arrays
Two-dimensional arraysare also called tables, or matrices. A table may be
viewed as a vector whose components are themselves vectors. As is the case for
the one-dimensional arrays, all values in a two-dimensional array must be of
the same kind, since arrays are homogeneous.
Figure 8.9 shows a general two-dimensional array A with M rows and N columns
but no values inside of them. The value of a component is found by using two
indices, one to identify the row (first dimension) and the other to identify the
column (second dimension). The element A[I, J] is found by moving
horizontally along row I and vertically down column J until the row and the
column meet: the value of the element is at the intersection.
A[M, N]
M
366 Chapter 8 Data Structures
Figure 8.10 shows a more specific table which, this time, contains actual Integer
values. This table represents the grades 4 different people received on 3
different quizzes. The grade of person P on quiz Q is denoted Grades[P, Q]. In
this example, person 2 made a grade of 80% on quiz 3. This value of Grades[2,
3] is not to be confused with Grades[3, 2], which is the grade of person 3 on
exam 2 (of 100%). The order of the indices is important! This small table has
only four rows and three columns, but could be expanded easily to accommodate
more people or more quizzes.
1 40 60 80
Grades[2, 3]
2 70 30 80 ≠
Grades[3, 2]
3 100 100 100
4 80 60 40
M=4
Col.
Row 1 2 3
1 1 2 3
Row Traversal
2 4 5 6 For First Index = 1 to 4 by 1
For Second Index = 1 to 3 by 1
Output Table[First Index, Second Index]
3 7 8 9
End Row Traversal
4 10 11 12
The algorithm loops through the table elements in the order shown by the
arrows: Table[1, 1], Table[1, 2], Table[1, 3], Table[2, 1], and so on, row
by row. Let’s take a look at the trace of the indices of Row Traversal:
We could just as easily have scanned the table column by column. Try it out.
The following Input Matrix algorithm inputs a sequence of values into a
matrix, row by row.
23 99.0
24 98.6
Original vector
Using the Grades array of Figure 8.10, which gives the grades various students
got on quizzes, we can also perform various kinds of operations. For example, it
may be of interest to find the average grade for each quiz, the average grade of
each student, the average weighted grade, or the average grades when the
poorest values are dropped or “forgiven”.
Section 8.2 Arrays 369
Figure 8.15 Average of columns
Q
Grades P 1 2 3
1 40 60 80
2 70 30 80
4 80 60 40
This first draft consists of a For loop that selects a column, and for this column,
accumulates the sum of all the grades before computing the column average.
Let’s refine this algorithm by defining how the accumulation of the grades is
done.
1 40 60 80 66
2 70 30 80 63
4 80 60 40 54
Now that we have seen how to add and multiply parts of arrays, let’s look at
how to add and multiply w h o l e arrays together. Adding arrays together is
simple: all you have to do is add each pair of corresponding values together
and place the result in the corresponding spot.
For example, in Figure 8.17, we have added the 2 tables A[I,J] and B[I,J]
together to produce C[I,J]. If you look at the shading, the 1 in position [1,1] is
added to the 5 in position [1,1] to produce a 6 in position [1,1].
Array Addition
A[I, J] B[I, J] C[I, J]
The 3 shaded 1 2 5 6 6 8
values are all in + =
the same [1,1]
position. 3 4 7 8 10 12
Matrix Multiplication
Multiplying two arrays is a lot trickier. Array multiplication is used in
Mathematics, Science and Engineering. A complex series of operations between
the rows of one matrixand the columns of another is involved, as shown in
Figure 8.19. It resembles a dance between the items in a row of array A and the
items in a column of array B.
Each element Cij is determined by taking the ith row of matrix A and the jth
column of matrix B, multiplying the corresponding elements, and summing these
products. Figure 8.20 illustrates further the computations involved in a matrix
multiplication.
372 Chapter 8 Data Structures
Figure 8.20 Matrix multiplication
1 2 3 ... R 1 2 ... N
1 1
2 2
3 1 2 ... N 3
4 1 4
. 2 .
. .
.
. × .. = ..
. . .
M R M
N-Dimensional Arrays
Let’s complicate things a bit and add one more dimension to our tables to make
them three-dimensional arrays. This way, we can store even more information
in them. Take, for example, our patient temperatures from Figure 8.14. So far,
we can only store the temperatures for a patient hour by hour over one week. It
would certainly be more useful for a doctor to have a record of the temperatures
taken for a whole month. Now, we know that the number of days in a month
can go from 28 to 31. To simplify matters, let’s assume that our month is 28 days
long: exactly 4 weeks.
So, to store temperatures for a full “month”, we need 4 of the tables shown in
Figure 8.14. But we do not want to deal with 4 arrays—we want all of the
temperatures in one spot: in one array. To accomplish this, we need to build a
three-dimensional array by putting the 4 tables together layer by layer (we
will have 4 layers), forming a cube. Figure 8.21 shows this cube.
Section 8.2 Arrays 373
Figure 8.21 Three-dimensional temperature array
Day
Hour
Layer 2 represents
the 2nd week of
temperatures.
Week
Layer 1 represents
the 1st week of
temperatures.
8.3 Records
Month Month 7
Day Day 20
Two different Date records are shown in Figure 8.22. The one on the left is
empty and the one on the right is full. Take a look at the empty one; it is a
template or a skeleton. We can see that Date is a collection of 3 fields: Year,
Month, and Day. On the right, MoonDate represents a specific date: the day
humans first set foot on the moon. You will note that there are now values
inside of the fields.
Suit Spade
Rank Ace
The Card record of Figure 8.23 describes a playing card in terms of its two main
features, Suit and Rank. This particular diagram shows the specific Ace of
Spades record. Since card decks usually have 52 cards with four possible suits
and 13 possible ranks, we could use the Card record to describe any of the 52
cards.
Real
Part 3.0
Imaginary
4.0
Part
The Complex Number record of Figure 8.24, often used in engineering and
mathematics, consists of two parts, a Real Part and an Imaginary Part.
Section 8.3 Records 375
Figure 8.25 A Part record
Part
ID Number
Price
Quantity
Size
Length
sub-record
Diameter
The Part record of Figure 8.25 describes a typical part (like the parts of a chair
we introduced earlier). It consists of an identification Number, a Price, a
Quantity, and a Size, which is itself a record with two components (Length and
Diameter). We could say that Size is a subrecord of Part.
Student
ID 1234
Status P Month 7
Records can be used to describe most anything from cars to clothes, catalog
items, employees, loans, reservations, customers, bank accounts, schedules,
patients, and many others.
For example, consider the two students named Joe and X described in Figure 8.28.
Joe’s identification number is written Joe.ID and X’s is written X.ID. Record
components are treated as any other variables, and can be assigned, input,
output, or compared, as shown in Pseudocode 8.20.
Status F Status P
The fields of nested records (or subrecords), such as Birth Date, are also easily
accessed by extending the dot notation. For example, since Joe.BirthDate is a
record, the dot notation can be used to access its components, as in:
We could have made our student record more detailed and used deeper nests of
subrecords. The deeper the components, the longer the dot notations. For
example, we could have had:
An entire subrecord like Joe.Birth Date can be assigned values in one shot,
without assigning values to each component individually, by a simple
statement as shown in Figure 8.29.
Figure 8.30 shows how one of the components of a chair can be described for
inventory purposes.
378 Chapter 8 Data Structures
Figure 8.30 Accessing nested records
Rung
Part
ID Number 1234 Length
Diameter 3 Eighths 3
Size
Brand
Brand R e g a l R u n g s
Phono
Phono
Suffix 7890
Notice that the Size of a Rung has two parts, a Length and a Diameter, and
that the Length itself is described by a number of Feet, a number of Inches and a
number of Eighths of an inch. Accessing a deeply nested record component
proceeds naturally top-down from the trunk of the main record. For example
the Rung supplier’s phone number Area Code is denoted:
Rung.Phono.Area Code
Similarly the statement:
Set Rung.Size.Length.Eighths to 5
indicates that the part of the Rung’s length expressed in eighths of an inch is
assigned the value 5. In this way, the concept of top-down applies to items as
well as actions.
Pupil
Projects record
1 C
2 B
3 A
4 A 2 arrays nested
in the record
5 B
6 A
Quizzes
1 87
2 66
3 92
4 70
• Records of arrays are simply records whose components are arrays. For
example, Figure 8.31 shows a Pupil’s record consisting of two arrays.
The first one contains all the grades received on Projects, and the second
contains all grades received on quizzes. The score of Pupil Joe on Quiz 2
is represented by using the mixed dot and bracket notation as
Joe.Quizzes[2]
or more clearly, if the second Quiz is the midterm, as
Joe.Quizzes[Midterm]
Workers array
40 Hours
Worker[1]
10 Rate record nested
in the array
50 Hours
Worker[2]
10 Rate
20 Hours
Worker[3]
15 Rate
...
168 Hours
Worker[N]
10 Rate
• Arrays of records are arrays whose elements are records. For example,
Figure 8.32 shows an array of workers where the number of Hours
worked and an hourly Rate of pay is specified for each Worker. The
time worked by the third person can be selected by the notation:
Worker[3].Hours
More complex structures can be created from the above two structures. For
example, the array of workers could actually be a component of a Department
380 Chapter 8 Data Structures
record. In such a case, the hours worked by the third person in the research
department are denoted by:
Research.Worker[3].Hours
We can keep on combining records and arrays, nesting them deeper and deeper
within each other. We can even construct arrays of arrays which are
convenient for structuring data. A two-dimensional array is in fact a one-
dimensional array whose components are themselves one-dimensional arrays.
Similarly, a three-dimensional array is a one-dimensional array whose
components are themselves two-dimensional arrays, and so on.
8.4 Sets
A B
• The intersection of two sets A and B is the set comprising the elements
common to both A and B, is denoted by the symbol ∩ as in A ∩ B, and is
illustrated by Figure 8.34.
A B
Section 8.4 Sets 381
• The difference of two sets A and B is the set comprising the elements of
A that are not in B, is denoted by the symbol “–” as in A − B, and is
illustrated by Figure 8.35.
A B
Let’s look at a few examples to illustrate the various set operations. First, let’s
define some sets:
Digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Evens = {0, 2, 4, 6, 8}
Primes = {2, 3, 5, 7}
Lucky = {7}
X = {1, 8}
Y = {1, 5, 9}
PowersOfTwo = {0, 2, 4, 8}
We then have the following identities:
X ∪ Evens = {0, 1, 2, 4, 6, 8}
Primes ∩ Evens = {2}
Lucky ∩ X = {}
Y – X = {5, 9}
1 ∉ Evens ∪ Primes
Digits = Evens ∪ Primes ∪ Lucky ∪ X ∪ Y
By inspecting these data, we can try to find courses that can be offered
concurrently. For instance, it is obvious that courses 2, 5 and 6 cannot be given at
the same time as course 1 because of students 1 and 4. However, there is no
conflict between course 1 and courses 3 and 4, so course 1 could be given at the
same time as courses 3 and 4. But courses 3 and 4 are in conflict because of student
3 and cannot be given together, so it appears that course 1 can be given at the
same time as either course 3 or course 4.
We could continue and determine our timetable this way. However, if we want
to be able to solve timetable problems that are realistic, we must find a
systematic way of doing this. You must be aware that even in a small college
the number of students and the number of courses are much larger than our
example, and would not be as easy to manage.
Based on our first try above, our solution will have the following structure:
The first part of the solution will be easy to define, as we want to input data
and end up with one set of courses per student as seen in Figure 8.36.
From this registration data, we want to Find the Conflicting Courses. To do
that, we construct a new vector of sets of courses, Conflicts, with one element for
each course. The ith element of Conflicts is the set of courses with which course
i conflicts. A course conflicts with course i because one student (or more) has
selected both of the courses. Conflicts[i] is then the set of courses that cannot
be scheduled concurrently with course i. Thus, returning to our example data in
Figure 8.36, courses 1, 2, 5 and 6 all conflict and cannot be run concurrently—
because Student 1 has chosen courses 1 and 2, and Student 4 has chosen courses 1,
5 and 6. Pseudocode 8.24 constructs the Conflicts vector.
Section 8.4 Sets 383
Pseudocode 8.24 Algorithm to construct Conflicts vector
Find Conflicting Courses Here we set up a
vector of empty
For Course Num = 1 to Number of Courses by 1 sets called
Set Conflicts[Course Num] to { } Conflicts.
For Student ID = 1 to Number of Students by 1
Loop through all
For Course Num = 1 to Number of Courses by 1 courses, one
If Course Num ∈ Registration[Student ID] student at a time.
Set Conflicts[Course Num] to Conflicts[Course Num] ∪
Registration[Student ID]
End Find Conflicting Courses
Based on the sample data in the Registration vector, Figure 8.37 shows a trace
of how the Conflicts array is built, using the Find Conflicting Courses
algorithm. The final Conflicts array is found in the last column at the right of
the figure. This shows, for example, that courses 2, 4 and 6 all conflict with
course 3 and cannot be run concurrently—because Student 2 has chosen courses 2
and 3, Student 3 has chosen courses 2, 3 and 4, and Student 5 has chosen courses 3
and 6.
The first three lines of this algorithm find the lowest numbered course in
Unscheduled and set Course Num to that value. Let’s put these two pieces of
pseudocode together (Figure 8.38).
Section 8.4 Sets 385
Figure 8.38 Combined Algorithms from Pseudocode 8.25 and 8.26
We will now trace the Build Sets of Non-conflicting Courses algorithm with
the same data we have used so far for the first three sessions.
{1, 3, 5, 6} ∩ {4} = { }?
If Conflicts[Test Course] ∩ Session = { } True
Figures 8.39, 8.40 and 8.41 trace the execution of the algorithm for each of the
three sessions. Notice that it only took us 3 sessions to schedule the 6 courses.
Let’s summarize the course lists for each session:
• Session 1 Courses 1 and 3
• Session 2 Courses 2 and 5
• Session 3 Courses 4 and 6
Obviously, each session has 2 courses taught at the same time. However,
please note that this algorithm for selecting “suitable” sessions will not
generate an optimal Schedule. In unfortunate circumstances, the number of
sessions in the Schedule may be as large as the number of courses, even if
simultaneous scheduling were feasible.
If you have been able to follow this entire example, congratulations! This was a
difficult example, and you will find that algorithms that need to use sets are
usually complex. Check your understanding by using the algorithm to generate
a timetable from the following registration data:
Student Set of Chosen Courses
1 {1, 4, 6}
2 {2,4}
3 {3, 4, 5}
4 {1, 4, 5}
5 {2, 5}
Dynamic Variables
The problem with the data structures we have seen so far, is that their
structure is static. That is, their size and layout are fixed when the program is
written. This is a problem if we want to be able to use a broad range of data.
Dynamic variables can solve this problem. Dynamic variable
Dynamic variables are variables of a special nature. Like regular variables,
they are used to store data, but unlike regular variables, their number is not
known during algorithm development. They are instead created and used
during the execution of the algorithm when needed. The advantage of using
dynamic variables is that we do not have to guess at the number needed
beforehand: we will use exactly what is needed and nothing more.
Section 8.5 Data Structure Building Tools 387
Pointers
Since we do not know how many dynamic variables we will need (that is the
whole point of having dynamic variables), we cannot give them names, like we
did with other variables. To represent and name dynamic variables, we need
another kind of variable: pointervariables. Pointers can store only one kind of
value: the location of a dynamic variable. When you point your finger at
something, you answer the question “Where?” Same thing with pointers: they
answer “Where is the dynamic variable?”
Let’s take a look at how pointers and dynamic variables are used together. In
Figure 8.42, we use them together to create a list whose length is not known
until the program is run.
List1
Pointer
End (NIL Pointer)
Element Record:
includes item and pointer
You will notice that this list contains 4 element records. On top, we have a
pointer called List1 whose function is to tell us “Where?” the list begins. The
end of our list is marked with a pointer that has a special value, known as NIL,
that points to nothing. A NIL pointer is shown as a slashed box. Each of the
element records in Figure 8.42 contains 2 parts, as shown in Figure 8.43.
Item 1
Part 2: a pointer
An element record in general contains a minimum of two fields (like ours above):
• one for the element information, and
• one for the pointer to the next element record.
It is not unusual that a record contains more fields than that: it could have,
say, three more information fields and a couple of other pointers. Data
structures built in this way are known as “linked lists” because the pointers act
as links between the elements. Here, we are going to keep it simple and say
that we have one pointer per element record. Our element record could look like
the one in Figure 8.44.
We have made the arrows bend here so that you remember this:
Note: Pointers point to the whole element record (both the item and the
pointer), not to one part in particular. Usually, pointers are drawn
as straight lines.
Now that we have seen what element records can contain, let’s return to our
original generic example of Figure 8.42. There are certain algorithm
instructions to remember when using dynamic lists. Remember that the whole
of the dynamic list is only created while the program is run, not when it is being
written by the programmer. So we have to give our algorithm instructions on
how to create this list.
We will begin at the beginning: a dynamic list begins with a pointer. In our
case, it is called List1. This pointer variable already exists in the algorithm.
However, it has no value: it is empty. If we wanted to create a list, we would
have to give List1 a value to define “Where?” the list begins. The instruction
to do this is:
Set List1 to New(Element)
There are two parts to this instruction:
• New(Element) uses a special function called New to: (i) allocate the
memory space for the first element record; and (ii) return a value: the
location of this new memory space.
• Set List1 to New(Element) takes this location value and puts it into
the List1 variable.
Now that List1 is defined, we can use it to refer to either of the two parts of an
element record (the item or the pointer). To do so, we write List1 followed by
an arrow like this: List1->.
List1->blabla can be read as blabla pointed to by List1.
• To refer to Item 1 (the first part of the first element record) in Figure 8.42,
we would write:
List1->Information fields
• To refer to the pointer of the first record, we would write:
List1->Next
• Now to refer to Item 2, it gets a little trickier:
List1->Next->Information fields
Section 8.5 Data Structure Building Tools 389
• To refer to the pointer of the second element:
List1->Next->Next
In other words, we use the pointers to point the way towards the part we want.
We refer to the element records as follows: the information in list elements is
called Information fields and pointers are called Next. To remember how to
reference dynamic lists, think of everything written before the last -> as
arrows pointing the direction of the path to follow. The name after the last ->
is the name of the part wanted. So when we are looking for Item 2, we need to
write down the names of the pointers before it, followed by Item 2’s name,
hence:
List1->Next->Information fields.
Let’s take a look at some pseudocode written to create the list of Figure 8.42.
Input Item 3
Set List1 → Next → Next → Information fields to Item 3
Set List1 → Next → Next → Next to New(Element)
Input Item 4
Set List1 → Next → Next → Next → Information fields to Item 4
Set List1 → Next → Next → Next → Next to NIL
End List Creation
Everything should look relatively familiar here, in light of what we have just
covered, except for the last statement:
Set List1->Next->Next->Next->Next to NIL
This makes sure the last pointer does not point to anything. We should take a
look at what each instruction accomplishes.
390 Chapter 8 Data Structures
Figure 8.46 The step-by-step creation of a dynamic list
List 1
etc.
Obviously creating a list in this manner will soon be too difficult to follow as
we will have long lists of pointers. Worse than that, the length of such chains
of pointers must be specified when the program is created, thus falling back into
the very problem we were trying to solve.
Luckily, it is possible to proceed in a more general manner when developing
such an algorithm. By using an extra pointer, Current, to refer to the list
element being added, it is possible to rewrite our algorithm in the following
manner without changing the order of the creation.
Section 8.5 Data Structure Building Tools 391
Pseudocode 8.28 Refined List Creation Algorithm using Current
List Creation
Input N
Set List1 to New(Element)
Set Current to List1
Input Item
Set List1 → Information fields to Item
For Index = 2 to N by 1
Set Current → Next to New(Element)
Input Item
Set Current → Next → Information fields to Item
Set Current to Current → Next Shifting the pointer
Set Current → Next to NIL so that it always refers
End List Creation to element being added.
We now have an algorithm that can create a list with 4 elements or with 4,000
elements depending on the value we give to N. However, we still have not
resolved the problem of creating a list without knowing its size (i.e. we still
need to input N in the above pseudocode). That is left as an exercise for you to
do (hint: use pieces from the List Creation pseudocode).
Real-World
Objects Real-World Real-World
and Algorithm Objects
Operations
Programming Computer
Language Computer representation
Objects and Algorithm
Operations of results
You should remember from Chapter 3 that a data type (like Integers, Real
Numbers, and Characters) is made up of 2 parts:
• the value
• the operations possible on the value
For example, an Integer can have any whole number value and it can be added,
subtracted, multiplied, divided to produce a quotient and remainder, and
compared.
All programming languages (like Pascal, Modula-2, and so on) have a number of
predefined types. We saw a number of them in Chapter 5, including Integers,
Real Numbers, and Characters. However, when we come across some “real-
world” objects that cannot easily be modeled with these types, we need to
define new types ourselves, called Abstract Data Types.
Section 8.6 Abstract Data Types 393
Abstract Data Types are not predefined: they must be defined by the
programmer when needed. As the case with types in general, an Abstract Data
Type must be defined in terms of its:
• possible values
• operations possible on the values.
For example, if we had to simulate a line of people waiting in line for tickets at
a rock concert, we could do so quite easily by using an Abstract Data Type called
a “queue”. The rest of the chapter is devoted to introducing four Abstract Data
Types: strings, stacks, queues, and trees.
Strings
A character stringis a sequence of characters that is viewed as one single item.
A character is any element of the character set used on a particular computer.
Character sets include:
• letters (upper case and lower case)
• digits
• punctuation signs, and
• other special signs including spaces.
The treatment of character Strings varies greatly from one programming
language to another. Some programming languages do not include Strings,
while others allow Strings of a fixed length, and still others allow all kinds of
Strings of any variable length. Some programming languages, such as Snobol4,
are specialized languages for string processing. Although general purpose
programming languages treat Strings in a variety of ways, we can define here
an Abstract Data Type String, which will illustrate the characteristics of
character Strings.
Stacks
Stacksare used to implement a number of things, in particular subprogram calls.
It is therefore quite natural to define an Abstract Data Type Stack that can be
used in a number of applications. A Stack is an ordered collection of items,
where only one item is accessible: the last one entered in the stack.
Section 8.6 Abstract Data Types 395
• A Stack is a homogeneous structure in which all the elements are of the
same type, so the values in a Stack are all of a given type. We can
have Stacks of Integers, Stacks of Real Numbers, Stacks of Characters,
Stacks of a given record type, and so on.
Figure 8.48 shows a small stack of Integers, as well as the operations of
the Stack Abstract Data Type.
• The top item in a Stack is the last one that was entered into the Stack.
• The first item entered into the Stack is at the bottom of the Stack.
• The behavior of a Stack is often described as “LIFO”: Last-In First-
Out.
Push Pop
X 4 Y Create
Push (X)
Last one in is 8 Top Pop (Y)
first one out. Is Empty
9
Is Full
First item 1 Bottom Depth (Z)
entered
SPOTS
STOPS Input EQ False
Pour
STOPS
S S
P T
O O
T P
S S
S1 S3
The Pour operation transfers the contents of Stack S1 into Stack S3. Notice that
doing this reverses the order of the contents of the Stack: the top item of S1
becomes the bottom item of S3. This “reversing transfer” is done by the
algorithm in Pseudocode 8.30.
Finally the character sequence from Stack S2 can be compared to the reversed
sequence in Stack S3 by the following pseudocode.
Section 8.6 Abstract Data Types 397
Pseudocode 8.31 Comparing Stack S3 to Stack S1
Set Palindrome to True
While NOT IsEmpty(S2)
Pop Character 1 from S2
Pop Character 2 from S3
If Character 1 ≠ Character 2
Set Palindrome to False
9
56 789 Input Digit2 5
8
1
9 Carry Carry 0
8 2
7 3
6 S4
5 0
S2 S3
As another example, the Big Adder of Figure 8.50 shows how two Integers of
any length can be added digit by digit.
1. The two numbers are input with most significant digits first, and put
into stacks S1 and S2 with the least significant digits on top. The two
numbers are 1 and 5 in the given example.
2. The Adder begins with a Carry of 0 on a one-digit-Stack S3.
3. The digit in S3 is added to the sum of the top values of Stacks S1 and
S2.
4. The sum digit is placed onto another stack S4, with the new carry
replacing the previous carry digit in S3.
5. The output stack S4 is finally output, with the most significant digits
leading.
The algorithm for Big Adder is shown in Pseudocode 8.32.
398 Chapter 8 Data Structures
Pseudocode 8.32 Algorithm for Big Adder
Big Adder
Push 0 onto S3
While NOT (IsEmpty(S1) AND IsEmpty(S2))
If NOT IsEmpty(S1)
Pop Digit1 from S1
Else
Set Digit1 to 0
If NOT IsEmpty(S2)
Pop Digit2 from S2
Else
Set Digit2 to 0
Pop Carry from S3
Set Sum to Digit1 + Digit2 + Carry
If Sum ≥ 10
Push 1 onto S3
Set Sum to Sum – 10
Else
Push 0 onto S3
Push Sum onto S4
Pop Carry from S3
If Carry = 1
Push 1 onto S4
End Big Adder
Queues
Queues occur much too often in everyday life. Queues, as we are familiar with,
are the lines of people usually waiting to be served one at a time (bank teller,
bus line, supermarket cashier). Examples of Queues are not restricted to people,
but also include vehicles stopped at an intersection, tasks waiting to be done,
and so on. Queue
Queues are used as a way of providing service according to the order in which it
is requested. For example:
All our agents are busy helping other customers. Please hold. Your call will be answered in the order
in which it was received.
Enter Exit
3 2 1
Rear Front
Section 8.6 Abstract Data Types 399
In general, a Queueconsists of a channel where items enter at one end (called the
Rear) and ultimately exit at the other end (the Front) as shown in Figure 8.51.
There is no entry or exit in the middle of the queue. The first item into a queue
is the first one out: this is why a queue is called a FIFO structure.
Trees
So far, we have seen that Stacks and Queues are useful ways to represent items
that are arranged in lines (like the line of people at the bank). However, if
you wanted to represent your family tree you would find that it cannot be
represented by a stack or queue because a family tree contains lines with
branches. This is where Abstract Data Structures called Trees can be extremely
useful.
B C - root node
+ D A × leaf node
leaf node A × + D
root node - B C
A treeconsists of elements that are called nodes. Each node is a record that
contains a number of information fields and a number of pointers. Each node in a
tree may have zero, one or several descendants that are connected to the nodes
by branches as shown in Figure 8.52.
400 Chapter 8 Data Structures
In this figure, we have represented the same tree in two ways: one starts at the
bottom and the other starts at the top. The nodes usually have values
associated with them. The root is the main node and is the ancestor of all
others. On the right, branches from a node lead downwards to children, or
upwards to a parent. The nodes that have no children (A, B, C, D in Figure
8.52) are called leaf nodes, leaves, or terminal nodes.
Binary trees, where every node have at most two children nodes, are the most
common in computing. Figure 8.52 shows a binary tree used to represent an
arithmetic expression, A – (B + C) × D. This tree is also called an expression
tree.
Section 8.7 Review: Top Ten Things to Remember 401
8.8 Glossary
Abstract data type: A data type, Set: A group of data values, all of
generally specified by the the same type, stored without
programmer, that is defined purely in ordering or duplicates.
terms of its values and the operations
that may be performed on them. Stacks: A data structure in which
data items are removed in the reverse
Dimension: The number of dimensions order of their insertion.
of an array is the number of subscripts
that are needed to reference a single String: A sequence of characters that
element of the array. is viewed as a single data item.
N-dimensional list: An n-
dimensional array.
8.9 Problems
1. Mystery
What does the following algorithm do?
Problem 1
A[I]
For Index = 0 to N by 1 0
Swap A[Index] and A[N - Index]
1
2
3
4
************
************
********
********
*****
*****
404 Chapter 8 Data Structures
4. Reverse
Create an algorithm to reverse the values in an array A (with and
without using recursion).
5. Normalize
Create an algorithm to convert an array of numbers (frequencies) into an
array of probabilities, by summing all the values and then dividing
each by this sum.
6. Weed
Create an algorithm to “weed out” or eliminate duplicate entries from
an array V, creating a second array W.
7. K-Big
Create an algorithm to find the k-th largest value of an array A of N
different values.
8. Intersection
Create an algorithm to compare the items of two sets (arrays each
having no repeated items) and to output those items that are common to
both sets.
Create also the union, those items in either set or in both.
9. Hilo-Grade
Create an algorithm that computes an average of grades, and then
indicates for each grade whether it is above, at, or below the average.
Section 8.9 Problems 405
10. Median
Create some algorithms to find the median value of an array; this is
the middle value (for an odd-sized array), or the average of the two
mid values (for an even-sized array).
11. A La Mode
The mode M of an array A of N values is the value which occurs most
often. Show two general algorithms to determine the mode. Anticipate
exceptional cases and handle them in any way you wish.
Problems On Tables
13. More-Charge
Recall the previous Charge algorithm of Chapter 3, when drawn as a
table (where the charge C[Adult, Baby] is three dollars for each Adult,
and two dollars for each Baby). Create an algorithm to draw such a
table for any given number of adults M and babies N.
14. Flip-N-Flop
Trace the algorithm given below when operating on the given table.
Then verbally indicate its behavior in general.
Problem 14
For I = 1 to N by 1
For J = 1 to N by 1
Swap A[I, J] and A[J, I]
15. Transpose
Create an algorithm to transpose a rectangular array (i.e., to convert
all values A[I, J] to A[J, I]). This essentially “rotates” the array values
about a diagonal.
16. MiniMax
Given an array of M rows and N columns, construct a flow block diagram
that finds the smallest entry in the row having the greatest sum.
17. Tic-Tac-Win
The game of Tic-tac-toe (or Xs and Os, or naughts and crosses) is played
on a table as shown in Figure 8.11. A game is won if there are three
identical symbols in a row, in a column, or along a diagonal. Show two
different algorithms to detect a win.
406 Chapter 8 Data Structures
18. Normalize Frequencies
Two dice are rolled N times, with outcomes D1 and D2 noted and put
into a table F[D1, D2] of frequencies of occurrence. Create an algorithm
to convert (normalize) this table of frequencies F into a table of
probabilities P, by dividing each entry by N. Then use this P table to
find the probability of all sums S from 2 to 11. For example, the
probability of (S=11) is P[5,6] + P[6,5].
21. Convolution
Trace the following algorithm when operating on the given arrays.
Problem 21
Convolution
For Index 1 = 1 to N by 1
Set Sum to zero
For Index 2 = 0 to Index 1
Set Sum to Sum + A[Index 2] × B[Index 1 - 1]
Set C[Index 1] to Sum
End Convolution
N 3
0 1 4
1 2 5
2 3 0
3 0 0
A B C
Chapter Outline
9.1 Preview....................................................................416
9.2 Sorting......................................................................416
General Sorting Strategies.........................................416
The Four Methods of Sorting......................................418
Count Sort..........................................................419
Count Sort Analysis...........................................421
Swap Sort..........................................................422
Swap Sort Analysis...........................................424
Select Sort.........................................................425
Select Sort Analysis...........................................427
Insert Sort..........................................................428
9.3 More Complex Sorting...............................................428
Improving Sorts.........................................................428
Recursive Sorts..........................................................432
9.4 Searching.................................................................435
Linear Searching.......................................................436
Binary Searching......................................................437
Pattern Matching......................................................438
9.5 Implementing Abstract Data Types............................441
Stacks.......................................................................441
Implementing Stacks with Arrays.............................441
Implementing Stacks with Pointers............................444
Queues......................................................................445
Implementing Queues of Arrays.................................446
Implementing Queues with Pointers...........................448
Trees.........................................................................449
9.6 Review Top Ten Things to Remember........................451
9.7 Glossary...................................................................453
9.8 Problems...................................................................454
416 Chapter 9 Algorithms To Run With
9.1 Preview
The first two tasks that are studied, sorting and searching, are applications of
the array data structures. The objective of sorting is to rearrange the data into
a specific sequence, e.g. alphabetic or numeric order, while the objective of
searching is information retrieval.
As is common with many tasks, there are several ways to perform sorting and
searching. For example, although there are only four basic ways to sort an
array, there are dozens of variations of each of these ways. Only a few of the
variations are considered here. Their individual advantages and
disadvantages are discussed.
A particular area of interest in the study of algorithms is their analysis. This
is an investigation of the way in which their execution timeincreases with the
amount of data being worked with. Algorithm analysis is presented and
applied to the various algorithms that are introduced in this chapter.
As another example of the use of data structures, methods of implementing
stacks, queues and trees are also introduced and discussed. Some of these
techniques use arrays as the underlying data structure, while others use
dynamic variables and pointers.
9.2 Sorting
A1 A2 A3 ... An A1 A2 A3 ... An
A1 A2 A3 ... An A1 A2 A3 ... An
A1 A2 A3 ... An A1 A2 A3 ... An
8, 5, 4, 9, 1, 7, 6, 3, 2
You might have noticed that these values are sorted in alphabetic order
(eight, five, four, nine, etc.). However, we wish to sort them into numerical
order.
Count Sort
One of the simplest sorting methods is Count Sort although it tends to be
forgotten. This method finds the rank of all values in an array: the largest
value has a rank of 1, the smallest has a rank of N (if all values are different).
The top left part of Figure 9.4 shows the original array A before it is sorted.
The rank of a value X is found by comparing it to a l l values in the array of N
elements, and counting the number of values that are greater than or equal to
that value X. The largest value has only one value (itself) equal to it, and so
has rank 1. The second largest has two values greater than or equal to it, and so
has rank 2. The smallest has all N values greater than or equal to it, and so
has rank N.
Section 9.2 Sorting 419
Figure 9.4 Count Sort
There are only 2
array elements
greater than or
equal to 8.
Before
counter trace for the first element (8) in A
I A[I]
1 8 C= 1
2 5 C= 1
3 4 C= 1
4 9 C= 2
5 1 C= 2
6 7 C= 2
7 6 C= 2
8 3 C= 2
9 2 C= 2
Rank After
I R[I] R[I]
1 2 2 2 2 2 2 2 2 2
2 5 5 5 5 5 5 5 5
3 6 6 6 6 6 6 6
4 1 1 1 1 1 1
5 9 9 9 9 9
6 3 3 3 3
7 4 4 4
8 7 7
9 8
After pass = 1 2 3 4 5 6 7 8 9
The first pass of the sort is shown in the top half of Figure 9.4. It takes the first
value, 8, and compares it to all of the values in the array (including itself). It
increments a counter each time it finds a value that is greater than or equal to 8.
1. In our case, it takes 8, compares it to the first value, 8, and puts the
counter at 1.
2. Then, when it encounters the 9, the counter goes to 2.
This determines that the first value, 8, has a rank of two because only two
values are larger or equal to it. The bottom half of Figure 9.4 shows how the
results of each pass are used to build the Rank array. Nine passes are done in
all, one for each value (N=9).
Now that we have seen how the sorting process operates, we can develop an
algorithm. We will proceed top-down, first defining a rough outline for the
Count Sort algorithm.
We now refine this algorithm by giving the detail of the loop body.
420 Chapter 9 Algorithms To Run With
Pseudocode 9.2 Refined version of Count Sort
Count Sort(A, Rank)
For Pass = 1 to Number of items by 1
Set Value to A[Pass]
Set Count to 0
For Index = 1 to Number of items by 1
Actions for each pass
If A[Index] ≥ Value
Increment Count
Set Rank[Pass] to Count
End Count Sort
Swap Sort
This family of sorts comprises a great number of variations on a common theme.
We will introduce the Swap Sort theme on a specific and very well known
example, the Bubble Sort.
Bubble Sort involves the comparison of adjacent values in the array being
sorted, and swapping them if they are not in order. The top half of Figure 9.5
shows the first pass over all the items of an original array A, where all pairs
of adjacent items are compared. After this pass we can say that the array is
slightly more sorted. Notice that the largest value (originally in position 4)
has finished in the first position, which is where it should be.
The results after each pass are summarized in the bottom half of Figure 9.5. As
we see, after pass 1, the largest value (which is 9) has bubbled up to its final
position at the top of the array, and everything else has shifted past it. After
pass 2, the second largest value (which is 8) has bubbled down to the second
position. This continues for each pass as shown by the shaded values. This
bubbling action of each value leads to the name of this sorting method, “Bubble
Sort”.
Note that after pass 4 all the values are already sorted, but the algorithm
continues and does all 8 passes. Why? Because in a worst case scenario, the
algorithm actually requires N–1 passes for all N values to arrive at their final
positions. To check this out, try sorting some values that are already sorted in
reverse order (like A[9] = 9, A[8] = 8, etc.). Let’s develop the algorithm top-
down as usual, starting with a first draft of the algorithm.
We now need to refine the bubbling action, where we must pass through all
pairs of adjacent elements, comparing and swapping them as we go along.
422 Chapter 9 Algorithms To Run With
Pseudocode 9.4 Second draft of our Bubble Sort algorithm
Bubble Sort(A, Size)
For Pass = 1 to Size - 1 by 1
For Index = Size - 1 to 1 by -1
Compare adjacent values and swap them if increasing
End Bubble Sort
Before
I A[I]
1 8 8 8 8 8 8 8 8 9
2 5 5 5 5 5 5 5 9 8
3 4 4 4 4 4 4 9 5 5
4 9 9 9 9 9 9 4 4 4
5 1 1 1 1 7 7 7 7 7
6 7 7 7 7 1 1 1 1 1
7 6 6 6 6 6 6 6 6 6
8 3 3 3 3 3 3 3 3 3
9 2 2 2 2 2 2 2 2 2
After the first pass, the largest value 9 "bubbles" to the top position.
After
A[I] A[I]
1 8 9 9 9 9 9 9 9 9
2 5 8 8 8 8 8 8 8 8
3 4 5 7 7 7 7 7 7 7
4 9 4 5 6 6 6 6 6 6
5 1 7 4 5 5 5 5 5 5
6 7 1 6 4 4 4 4 4 4
7 6 6 1 3 3 3 3 3 3
8 3 3 3 1 2 2 2 2 2
9 2 2 2 2 1 1 1 1 1
After pass = 1 2 3 4 5 6 7 8
Note that all values are already
sorted at this stage. The rest of the
passes just "go thru the motions".
We reach the final and complete algorithm by specifying the details of the
comparison.
The formula
N ( N − 1)
C =
2
for the sum of the first N-1 natural numbers is easy to derive by noting that the sum C can be
expressed in two ways:
C = ( N − 1) + ( N − 2) + ( N − 3)+…+3 + 2 + 1
and
C = 1 + 2 + 3+…+ ( N − 3) + ( N − 2) + ( N − 1)
If we add both formulas, forming the sum term by term, we get the following:
2C = (( N − 1) + 1) + (( N − 2) + 2)+…+(2 + ( N − 2)) + (1 + ( N − 1))
The formula below is equivalent to the one above as an expression for the sum of the first N
natural numbers:
N ( N + 1)
1 + 2 + 3+…+( N − 3) + ( N − 2) + ( N − 1) + N =
2
424 Chapter 9 Algorithms To Run With
Another way to prove this is to use induction:
1. Show that it holds for N = 1.
2. Suppose it holds for N, show that it also holds for N+1.
Select Sort
The Select Sort algorithm is based on the selection of extreme values, either
the maximum value or the minimum value. For example, the algorithm could
start by finding the maximum value of the array to be sorted. This value is
then noted, put into another array and eliminated from the original array.
This process is repeated on the remaining original array: the maximum of the
remaining values is selected, recorded and eliminated. So, as the sorted array
is filled, piece by piece, the original one is emptied, piece by piece. This cycle
continues until the N values in the array have been “recorded”.
Before After
trace of how the maximum M
A[I] of array A is found A[I]
8 M= 8 8
5 M= 8 5
4 M= 8 4
9 M= 9 0
1 M= 9 1
7 M= 9 7
6 M= 9 6
3 M= 9 3
2 M= 9 2
Maximum After
I B[I] B[I]
1 9 9 9 9 9 9 9 9 9
2 8 8 8 8 8 8 8 8
3 7 7 7 7 7 7 7
4 6 6 6 6 6 6
5 5 5 5 5 5
6 4 4 4 4
7 3 3 3
8 2 2
9 1
After pass = 1 2 3 4 5 6 7 8 9
The top half of Figure 9.6 shows the first pass over our array of positive
integers. The first maximum value is found to be 9, is output (or stored in
another array), and its value is replaced by zero.
The bottom half of Figure 9.6 shows snapshots of the resulting array B after
each pass. Notice that the original array A is slowly destroyed in the process,
ultimately becoming an array of zeros. Let’s develop our Select Sort algorithm
using our usual top-down approach. We loop N times, one pass for each value in
the array to be sorted.
Section 9.2 Sorting 425
Pseudocode 9.6 Rough draft of Select Sort algorithm
Select Sort(Table, Size, Result)
For Pass = 1 to Size by 1
Set Maximum value
Output Maximum
Eliminate Maximum
End Select Sort
Let’s refine the various parts of the algorithm. During each pass, the maximum
value is found, stored in the resulting array and eliminated from the original
array.
Let’s refine further the algorithm into its final form. The Maximum is
compared in turn to each value in the array and updated together with its
position in the original array.
The Select Sort method, as we have presented it, only works with positive
integers, since eliminated values were replaced by zero, the smallest positive
integer. If the data had included negative values, we would have to modify
our algorithm to mark deleted items with the lowest possible negative value
available.
9.4 Searching
Searching for a particular item in a table is a very common operation. The item
searched is sometimes called the search key or the target. If the item occurs in
the table, we would like to know its position. If it is not in the table, we would
like to receive a special value that can be tested for, or some message to
indicate its absence. In some cases, we might even want to count the number of
times the required item occurs in the table.
The data structure of Figure 9.10 shows an array of 13 items. We are to search
the array for a given item Key, to count in the variable Count the number of
times it is found and to record in the variable Position the index of the last
item found with the given key.
Of the many ways to search, we will consider the two most important ways:
• Linear search; and
• Binary search.
Linear Searching
The simplest search, a linear search, involves one pass over the elements of an
entire array. The following pseudocode illustrates a simple sequential or linear
search algorithm.
Section 9.4 Searching 433
Pseudocode 9.18 The Linear Search algorithm
Lenear Search
Input Array(Table, Number)
Input Key
Set Position to 0
Set Count to 0
For Index = 1 to Number by 1
If Table[Index] = Key
Increment Count increments counter
Set Position to Index each time a key is found
If Count = 0
Output "Not found"
Else
Output "Found" Count "at position" Position
End Linear Search
This algorithm examines each element in the array once, incrementing the
counter of found items when it finds an array element equal to the Key.
Position indicates the position of the last occurrence found. If only the first
occurrence is required, then the algorithm can be easily modified, replacing the
For loop by a While loop as shown in Pseudocode 9.19. If the item is not found,
the value of Count remains zero.
In our example in Figure 9.10, if the key were 38, the following would be output.
Found 2 at position 5
If we require only the first occurrence, we can define a faster linear search
algorithm, where the loop stops with Position indicating the first occurrence.
Pseudocode 9.19 illustrates this change.
With this faster search, the item might be found after only a few comparisons
or after inspecting almost all the elements in the table. It depends on where
the item is located. On average, half of the elements of the table must be
inspected before finding the desired element, which gives the Fast Linear
Search a complexity of O(N).
Binary Searching
The previous two versions of the linear search were general, and made no
assumptions about the data. Sometimes the data values in the table are sorted,
in increasing or decreasing order, and we can use this fact to speed up the search.
434 Chapter 9 Algorithms To Run With
We used the We can use the method of Bisection described in Chapter 6 to keep reducing the
Bisection size of the part of the array to be searched until either we find the item, or we
method as early know that it is not present. The binary searchalgorithm proceeds by halving
as in Chapter 4 the search range at each stage. You may wish to create this Binary search
for our guessing algorithm on your own by modifying the Bisection algorithm described in
game. Chapter 6 (Pseudocode 6.26).
The Binary search method is considerably faster than the previous linear
search algorithms. For example, searching an array of N items requires N/2
comparisons, on average, using a fast linear search algorithm. On the other
hand, using a binary search method only requires log 2N comparisons. This
means that, for an array of 1000 items, the fast linear search makes on the
average 500 comparisons, whereas the binary search makes only 10
comparisons. For arrays with very large sizes the contrast is even more
significant; for a million items the linear search will make 500 000 comparisons
whereas the binary search makes only 20 comparisons!
Of course, remember that nothing is free, and to achieve this speed, the binary
search requires the initial array to be sorted. If a sort has to be done before the
binary search, this will add quite a number of additional comparisons. But if
the array, once sorted, is searched often, this binary search method is
extremely efficient.
Pattern Matching
Sometimes, we need to do a different kind of searching called Pattern
Matching. Pattern Matching is necessary when we are searching a string of
characters for a particular sequence of characters. It can be accomplished by
trying to match the particular pattern as we move it along the string, like in
Figure 9.11.
Pattern = t i m e
2 String = N o w i s t h e t i m e
Pattern = t i m e
3 String = N o w i s t h e t i m e
Pattern = t i m e
The expanded algorithm (Pseudocode 9.21) is not very efficient because it keeps
comparing the characters of the pattern and the string even after setting Found
to False.
Our second example of a pattern matching algorithm, Find First Match, will
be faster, because it stops after finding the first match, and compares the
characters of the pattern to the characters of the string only until it finds a
mismatch. Once a mismatch is found, the pattern is moved forward in the
string for another try. In order for this algorithm to stop when finding the first
match, we will use a logical flag to indicate this condition as soon as it
happens. Pseudocode 9.22 defines this new pattern matching algorithm.
We still have to define the details of the actual pattern matching. We are
using a solution similar to our previous algorithm, but modifying it so that the
process stops as soon as a mismatch is detected. To do that, we use another
logical indicator, Equal, to transmit the result of the pattern matching to the
enclosing loop (Pseudocode 9.23).
436 Chapter 9 Algorithms To Run With
Pseudocode 9.23 The Find First Match algorithm with detailed
pattern matching
Find First Match
Set Found to False
Set S_Index to 1
While S_Index ≤ (String length - Pattern length + 1) AND NOT Found
Set Equal to True
Set P_Index to 1
While P_Index ≤ Pattern length AND Equal
If Pattern[P_Index] ≠ String[S_Index + P_Index - 1]
Set Equal to False
Increment P_Index As soon as equal is
false (one pair of
Set Found to Equal characters does not
Increment S_Index match), we move on to
If Found next string chunk.
Output S_Index
Else
Output "Not present"
End Find First Match
These two pattern matching algorithms are rather simple, but are not the most
efficient pattern matching algorithms. There are other much faster pattern
matching algorithms, such as the Boyer-Moore algorithm, the Knuth-Morris-
Pratt algorithm and the Rabin-Karp algorithm. These algorithms go beyond
our scope and will not be presented here.
Stacks
Stacks were introduced in Chapter 8 as an abstract data type with the
following operations:
• Create a stack.
• Push an item onto a stack: the new stack top contains the pushed item.
• Pop an item from a stack: the result is the top stack item, which is
deleted from the stack.
• Check if a stack is empty.
• Check if a stack is full.
• Count the number of elements in a stack.
Stacks can be implemented in many ways. Here we will look at two
implementations, one using arrays, and the other using pointers.
Section 9.5 Implementing Abstract Data Types 437
Implementing Stacks with Arrays
Figure 9.12 Four ways of implementing stacks as arrays
1 1 Top 1 1 Bottom
2 2 2 2
3 3 Bottom 3 3 Top
Top Bottom
Bottom Top
We can use arrays to implement stacks and this can be done in a number of
different ways as shown in Figure 9.12, where the bottom and top of the stacks
are shown as well as the indices of the array. Notice how the indexing changes
from method to method. Each of the following four methods is analogous to a
physical situation
• Method a corresponds to books in a box; the first book put in goes to the
bottom and the top changes as books are placed on the stack.
• Method b corresponds to stacks of plates in some restaurants, where the
top plate is at the counter level, and the bottom plate is moved up by a
spring whenever the top plate is taken.
• Method c corresponds to a number of drinking cups in a dispenser where
the “top” cup is at the bottom, and as it is taken all the cups move down
one.
• Method d corresponds to lighter than air balloons in a vertical tube,
with the “bottom” balloon floating at the ceiling.
Selection of one of these stack implementations is made easy if you realize that
Methods b and c require all the items in a stack to be moved when the top is
pushed or popped. Methods a and d are better candidates for our
implementation; they do not involve such inefficient moving of the stack
elements. We might choose the first way, Method a, to implement our stacks,
for it seems more “natural” in that the stack Top can be represented at the top of
the page. On the other hand, it would seem more natural to number the array
elements from the bottom of the stack as Method d does. So we’ll choose
Method d but we will reverse it in the diagram as shown in Figure 9.13.
Array contains N
N elements. Push
3 Finally
2 Pop Top
Bottom 1 Initially
Variation of Method d
Our choice consists of an array with N elements, and a variable, Top, which
indicates the stack top. Because of the structure we chose, the implementation
of the various stack operations is simple. First, we create an empty stack as
shown by the following pseudocode.
438 Chapter 9 Algorithms To Run With
Pseudocode 9.24 Create Stack using arrays
Create Stack
Set Top to 0
End Create Stack
Checking whether or not a stack is full is easily done by checking if the stack
top is at the last element in the array.
To check if the stack is empty, we check to see if the stack Top is zero.
We cannot push an item onto a full stack. If the stack is not full, the Top of the
stack moves up one position and the item is copied into the next position.
We cannot pop an item from an empty stack. If the stack is not empty, the Top
of the stack is copied into Item, and the Top is changed to point to the next item
on the stack.
As always, remember that there are many different ways of doing things and
the implementation of stacks is no different. The implementation we have just
seen has the disadvantage that the stack size must be fixed once and for all,
when we choose the array to represent our stack. Each time an application
needs more space in its stack, we must redefine the array used in the
implementation.
Section 9.5 Implementing Abstract Data Types 439
Implementing Stacks with Pointers
To solve the problem of the fixed stack size we just mentioned, we can abandon
the array implementation of stacks and use dynamic variables instead. In fact,
we can use the dynamic list representation that was introduced in Chapter 8
(Figure 8.42) to implement our stack abstract data type. In that case, a stack
will be represented as shown in Figure 9.14
The creation of a stack will be done easily by giving the stack pointer a NIL
pointer value (pointer pointing nowhere), indicating that there are no elements
in the stack. Its algorithm is shown in Pseudocode 9.29.
Checking whether a stack is full cannot be done as it was done with the array
implementation. If a call to New, which creates a new element, fails, then we
will know all the memory has been used up. This is equivalent to having a full
stack.
Bottom of stack
New Top First New Top created
The pointer variable Stack will always point to the top element of the stack.
Our Push and Pop operations will be redefined by Pseudocode 9.31 and 9.32.
Before pushing a new element onto the stack, we need to create that element.
This is done by a call to New. If this memory allocation is successful, we copy
the information into the new element. Remember we use New Top-> to refer to
440 Chapter 9 Algorithms To Run With
the dynamic variable indicated by pointer New Top. We connect the new
element to the top element of the stack through its Next pointer field, and we
change the value of Stack to indicate this new element as the top element. Try
to follow this algorithm as you add Item 5 to the stack of Figure 9.14.
Note: The dashed items in Figure 9.14 were added to help you visualize
the “Push” operation.
We cannot pop an item from an empty stack, so we must check for that condition.
If the stack is not empty, the top element of the stack is copied into Item, and
Stack is changed to point to the next element on the stack, while the old top
element is freed (Dispose is the inverse operation of New). Try to follow this
algorithm as you delete Item 4 from the stack in Figure 9.14.
Queues
Queues were introduced in Chapter 8 as an ADT with the following operations:
• Create a queue.
• Check if a queue is empty.
• Check if a queue is full.
• Count the elements in a queue.
• Enter an element into a queue.
• Remove an element from a queue.
As was the case with the stack, there are many ways of implementing queues.
We will show only two here: one based on the use of an array, and another one
based on dynamic elements.
Front 1 -
3 2 -
3 1
4 9
Rear 5 8
6 6 4
-
Size -
4 N
As items are entered in the queue, the rear indicator advances, and as items are
removed from the queue the front indicator also advances, leaving behind some
“used” values. So the queue “snakes” through the array. As each indicator
passes the last item of the array it continues to the first item, thus creating a
“circular array”.
The algorithm to create a queue initially sets both Front and Rear variables to
the first index, and sets the Size of the queue to zero, as shown below.
The functions to check whether the queue is empty or the queue is full are
obvious, as illustrated by Pseudocode 9.34.
The function to count the elements in a queue is trivial since the Size variable
tells us how many there are.
The variables Front and Rear are pointer variables and the elements in the
queue are dynamic variables. With this representation for queues, the creation
operation is simple and just sets the Front and Rear pointers to NIL pointers.
The Enter Queue algorithm is defined by Pseudocode 9.38. Look at the dashed
right-hand-side of Figure 9.16 to get an idea of the operations involved.
Follow this algorithm while adding Item 5 to the queue of Figure 9.16.
Section 9.5 Implementing Abstract Data Types 443
The Remove from Queue algorithm is very similar, and is shown below.
Apply this algorithm to the queue in Figure 9.16.
The implementation of the other operations is easily done as it was for the
stacks, and we leave it as an exercise.
Trees
We have seen an example of the nonlinear data structure Tree in Chapter 8.
Although it is possible to represent trees using arrays, a more natural
implementation of trees uses pointers. Such a representation is illustrated in
Figure 9.17, which presents a binary search tree
Tree
15
11 22
18 31
9.7 Glossary
Execution time: The time that it
takes an algorithm to execute.
9.8 Problems
2. Median: MidArray
The middle or median value of an array of an odd number of values, N,
is that value which has as many values less than it as are greater than
it. Create an algorithm to find this Mid value.
Do it in a least two other ways.
3. Slow-Sort
Given an array A of N integers (not necessarily different) ranging from 0
to 1000, create an algorithm to sort the values by checking (in increased
order) if each of the 1000 integers is in the array and if so, by outputting
the value. Compute the number of comparisons required for this sort,
and compare it to some of the other sorts.
4. Quick Queue
Create a queue and its operations EnterQ and ExitQ, using the already
created Stack and its operations.
5. Double Stacks
Two stacks can be implemented by a single array, with the stacks
“growing” toward each other as shown below. Create a general
algorithm for pushing (Push1 and Push2) and popping (Pop1 and Pop2)
the appropriate stacks.
Section 9.8 Problems 449
Problem 5
Stack 1
Bottom 1 1
2
3
4
Top 1
Top 2
Bottom 2
Stack 2
6. More Queues
The given diagrams show two more implementations of a queue, using
arrays. The first queue Q1 always has its Head at position one of the
array, and on ExitQ all values are moved up. The second queue Q2
moves “snake wise” down the queue (like the circular queue), but when
the Rear hits the bottom of the array, then all entries are shifted up so
that the Front is at the top again. Create programs to Enter and Exit
these queues. Compare the two queue implementations briefly.
Problem 6
Queue 1 Queue 2
Front
Front
Rear
Rear
7. Insert Sort
Create a sorting algorithm which enters new values into an array by
moving existing values to make space for the new value.
8. Merge
Create an algorithm to merge two already sorted arrays into one larger
sorted array. Do this in two ways.
450 Chapter 9 Algorithms To Run With
9. Recursive Searches
Given an array of N items, create a recursive algorithm to search the
array. Do this as a linear search and also as a binary search.
Problem 10
Tree Traversal 1(Tree)
If Tree is not empty
Tree Traversal 1(Tree → Right)
Tree Traversal 1(Tree → Left)
Output Node information
End Tree Traversal 1
Chapter Outline
10.1 Preview....................................................................458
10.2 The Seven-Step Method and Applications.................458
Step 1 Problem Definition........................................458
Problem Definition Application.........................460
Step 2 Solution Design..............................................461
Solution Design Application..............................461
Step 3 Solution Refinement.......................................464
Solution Refinement Application.......................464
Step 4 Testing Strategy Development.......................466
Development of Testing Strategy Application....468
Step 5 Program Coding and Testing...........................471
Step 6 Documentation Completion............................471
Documentation Completion Application.............472
Step 7 Program Maintenance.....................................474
Program Maintenance Application.....................474
10.3 An Advanced Case Study Building a Text Index........476
Step 1 Problem Definition........................................476
Step 2 Solution Design..............................................476
Step 3 Solution Refinement.......................................478
Binary Search Tree Unit....................................483
Queues Unit.......................................................486
Step 4 Development of Testing Strategy....................486
Step 5 Program Coding and Testing...........................488
Step 6 Documentation Completion............................488
Step 7 Program Maintenance.....................................489
10.4 Review Top Ten Things to Remember........................490
10.5 Glossary...................................................................491
10.6 Problems...................................................................492
Level 1 — Getting Started.........................................492
Level 2 — Getting Organized with Subprograms.........495
Level 3 — Getting Fancier with Parameters...............498
Level 4 — Getting Your Wings with Units..................501
458 Chapter 10 The Seven-Step Method
10.1 Preview
Up until now, we have shown you that programming involves the following:
• A problem-solving method that can be described by the seven steps
introduced in Chapter 2. These steps are:
1. Problem Definition
2. Solution Design
3. Solution Refinement
4. Testing Strategy Development
5. Program Coding and Testing
6. Documentation Completion
7. Program Maintenance
Steps 1 to 4 are usually part of the design stage, and steps 5 to 7 are part
of the implementation stage. This problem-solving method is closely
related to the software life cycle(the various stages in the life of a
software package.)
• Algorithms that can be represented in many forms. They all consist of a
precise set of instructions to follow to solve a problem.
• Data structures that are the means of representing the data used in the
algorithms. They must be developed at the same time as the
algorithm.
In this chapter, we will explain in greater detail what each of these seven
steps involves. At the same time, we will present a complete case study of a
payroll system, to show you how to use each of these steps to develop
algorithms and data structures.
Let’s take the problem of averaging student grades described above. We could
generate this list of specifications:
• Input: student number, followed by student name, followed on the
second line by five Real Numbers representing the grades in percentages
Sample: 666 Lucifer El Diablo
20.5 66.6 75.0 70.9 100.0
• Output: student number, followed on the next line by one Real Number
for the average and one Character for the corresponding letter grade
Sample: 666
66.6 % C
• Process: for each student, the grades will be summed and averaged, and
this average converted to a letter according to a predetermined scale.
Note: At the end of the Problem Definition step, you should have a list of
specifications.
Problem
Note: At the end of the Solution Design step, you should have a structure
chart describing the hierarchy of your algorithm.
Calculate
Payroll
lines of communication
Calculate
Payroll
Compute Accumulate
Withholdings and Display
refinement added
See Chapter 7 A structure chart is actually a skeleton of the structure of the final program.
for more Each box in the structure chart will be implemented as a procedureor a function.
information on For example, the box “Input Data & Validate” will be implemented as a
developing procedure later on. This should not be surprising, because the structure chart is
interfaces via the result of breaking down the solution function by function.
parameter use. In addition to decomposing the problem into its functional components, you
should also try to identify groups of related operations that could be used
throughout the program to make implementation easier. For instance, if a
group of operations all dealt with a certain kind of data structure, then it
might be desirable to include them in a separate unit—also referred to as an
external unit.
For example, a program that deals with complex numbers could use a separate
unit that defines a complex abstract data type. Such separate units are called
“external” because they are physically external to the main application.
When the main program needs to use part of the external unit, this must be
specified in the main program. Units are sometimes called Libraries, Modules,
or Packages.
Our payroll problem has been greatly simplified and we do not anticipate the
need for external units. If the payroll application were more realistic and were
to process thousands of employees, then we could envision a need for separate
units to process taxes and to deal with all the company benefits (health
insurance, pension plan, etc.).
These units could then be documented by a modular design chart like the one in
Figure 10.5. This chart shows the various interconnections of the units we
intend to use for this solution. The arrows show what elements are imported
from one unit for use in another unit. In Figure 10.5, “Payroll System” imports
elements from units “Tax” and “Benefits”. The figure should be completed by
indicating which procedures from the “Tax” unit or the “Benefits” unit will be
used by the “Payroll System”. If we were designing a complete payroll system,
we would be able to complete the chart once the solution has been refined in the
next step.
Section 10.2 The Seven-Step Method and Applications 463
Figure 10.5 Modular design chart for a more realistic payroll system
external units
Tax Unit Benefits Unit
Payroll
System
In this structural design step, various alternatives for doing the decomposition
must be considered, and the relative advantages and disadvantages of each
alternative must be weighed. Initially, if you are a beginner, you might find it
hard to judge the advantages and disadvantages of a given solution, but this
will become easier with experience.
Note: At the end of the Solution Refinement step, you should have
developed pseudocode for each box of the structure chart. As well,
all of the data structures and variables used must be defined.
Here, the collective name Withholdings has been used to represent the three
variables Federal Tax, State Tax, Soc Sec Tax.
Section 10.3 A More Advanced Case Study: Building a Text Index 483
To test all cases, we will need at least three trivial words files:
• Trivial 1: an empty file for case 1
• Trivial 2: a file with the single word “kernel” for case 2
• Trivial 3: a general file including the list we have given earlier.
We will also need at least three special text files:
• Text 1: a one-page text file with words in alphabetical order
Sample: albatross beauty cartography demon earl
fugitive gross helicopter indeed joy
kernel lullaby mammoth nerd opera possible
quintessence refrigeration subtlety ton
utilitarian vampire wapiti xylophone yak
zero
• Text 2: the same file as Text 1 but with an end-of-page mark between
every word
Sample: albatross\beauty\ cartography\ demon\
earl\ fugitive\ gross\ helicopter\ indeed\
joy\ kernel\ lullaby\ mammoth\ nerd\
opera\ possible\ quintessence\
refrigeration\ subtlety\ ton\ utilitarian\
vampire\ wapiti\ xylophone\ yak\ zero
• Text 3: a file with only two words repeated thirty times with an end-
of-page after each occurrence.
Sample: albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty\
albatross beauty\ albatross beauty
For the various cases we will use the following combinations:
• Cases 1 and 3: Text 1 and Trivial 1. The index contains all the words in
the same order with only a page 1 reference.
• Cases 2 and 3: Text 1 and Trivial 2. The index contains all the words
except “kernel” in the same order with only a page 1 reference.
• Cases 4 and 6: Text 2 and Trivial 3. The index contains all the words in
the same order each with a different page reference.
• Case 5: Trivial 3 and Trivial 3 (same text). The index is empty.
• Case 7: Text 3 and Trivial 2. The index contains two words each with
thirty page references.
You should also add words that are longer than the word length to make sure
they are treated correctly, and of course a long and realistic text.
484 Chapter 10 The Seven-Step Method
Step 5 Program Coding and Testing
The main program follows from our pseudocode. The details of this stage are
covered in the Practice book.
10.5 Glossary
Buffer: A holding area in memory for Testing strategy: A plan for the
data. orderly verification of the execution
of a program during development.
Driver: A program that is used to test
a subprogram by simulating the
context from which the subprogram
will be invoked when the full
program is completed.
10.6 Problems
The following is a series of problems and projects to be solved using the seven-
step method presented in this chapter. As we have done in the case studies, all
of the steps, except for the actual implementation, have to be followed. These
problems are presented in order of increasing difficulty and complexity.
1. A Guessing Game
You are on vacation at home and planning to enjoy your free time. Alas!
your parents ask you to take care of your little sister, and she is a real
pest. In order not to see your vacation time slowly wasted, you decide to
have the computer entertain your little sister. To do this, you want to
develop a simple game program that will pick randomly an integer
number between 1 and 1,000. The program will ask your little sister to
guess that number in a maximum of ten tries, and will produce an
appropriate message when the end of the game is reached.
Obviously, the program needs to be interactive. It will display a
message at the start of the game and prompt your sister for a guess.
Each time she makes a guess, it will have to indicate whether the
guess was between the limits or was high or low, or detect that the
guess was right. At the end of a game, the program will allow your
little sister to decide to continue to play or to stop.
The input format is simply that of an integer number, or a character for
yes or no. The output formats are mostly messages.
Start-of-game message:
Let's play a guessing game.
I pick a number between 0 and 1,000. You have to
guess it. But you have only 10 tries to guess my
number.
End-of-game messages:
Congratulations! 999 is right.
You lose! My number was 999.
Do you want another game? (Y/N)
Game messages:
Make a guess:
Wait a minute! My number is greater than 0!
You wasted a guess! My number is 1,000 or less.
Well ... your number is too small.
Sorry, but your number is too big.
Remember! We have already seen this example in Chapter 4.
3. A Bouncing Ball
While waiting for your date to show up, you idly bounced a tennis ball
on the sidewalk. This gave you the idea to develop a program to
compute and display some data on the bounces a ball will make when
dropped from a given height. Forgetting your late date, you went home
to solve this interesting problem.
To simplify the problem, you assume the ball bounces in place; that is,
it remains bouncing on the same spot and does not have any forward
motion. The program will prompt the user for the initial height of the
ball, the number of bounces to consider, and the ball’s elasticity (which
must lie between 0 and 1). It will compute the height of each bounce
based on the initial height and the elasticity of the ball, and display
it. The program will also compute the total distance traveled, which
is the sum of the up and down bounces, for the given number of bounces,
and display it. The program will repeat this process until the user tells
it to stop.
If the ball is at height h, when it bounces, it reaches new height h’,
which is computed by the formula
h’ = h × resilience
where resilience is expressed as the elasticity coefficient raised to the
nth power, if n is the bounce number:
resilience = elasticity n
If the original height is H, then the first bounce height will be
h 1 = H × elasticity
With an elasticity in the range between 0 and 1, each bounce will be
smaller than the preceding one, but never become 0. We will therefore
stop the program after a specified number of bounces.
Section 10.6 Problems 489
The ball will travel the distance shown in Figure 10.11 (where the
elasticity is 0.8) which we have drawn to help you. We have
represented a forward motion for the sake of clarity (the ball bounces on
the same spot).
0.8
0.64
0.512
0.4
1 2 3 4 5 Bounces
Each time the ball bounces, it travels twice the height of the bounce, so
the total distance traveled is
H + 2h 1 + 2h 2 + 2h 3 + 2h 4 + ...
The user will be prompted for the initial height in this way:
Give the height in inches from which the ball is
dropped:
Then the user will be asked the number of bounces:
Give the number of times the ball will bounce:
And finally the user will be asked the elasticity of the ball:
Give the elasticity of the ball (between 0 and 1):
For each bounce the program will display the following:
On bounce 9 the ball rises to a height of 99.9
inches.
After the last bounce the program will display the following:
The total distance traveled by a ball with an
elasticity of 0.999 when dropped from a height of
99.9 inches and after bouncing 9 times is 999
inches.
The user will be asked if the program is to continue:
Another try?
(1 + r )n
P = rL
(1 + r )n − 1
In the case of our mortgage, where the payments are made every month
over a period of y years, we can express this as
(1 + MonthlyRate)12y
MonthlyPayment = MonthlyRate × Loan × 12y
(1 + MonthlyRate) −1
Now, our problem calls for the interest rate to be expressed as an annual
rate and the monthly rate must be derived from this. Although banks
are a little secretive about the formulas they use to compute mortgages,
we know that to take account of the effects of compounding, they use a
monthly rate that, if compounded twice per year, will yield the stated
annual rate of interest. Loan rate tables show you that
AnnualRate
2y
12y
(1 + MonthlyRate) = 1+
2
which leads to
6 AnnualRate
(1 + MonthlyRate) = 1 +
2
or
AnnualRate
6 × log(1 + MonthlyRate) = log 1 +
2
and finally
log(1+AnnualRate/2)/6
MonthlyRate) = e −1
The program will use these formulas to compute and display the
monthly payment of a given mortgage loan and to produce a detailed
report of the payments over the first 5 years if needed.
The output format used will be the following:
Amount of mortgage loan:
Annual interest rate:
Length of mortgage loan (in years):
Monthly payment: 999.99
Do you want a detailed report?
Interest paid in 5 years: 12345.67
5 year balance: 23456.78
Total cost of mortgage loan: 34567.89
The detailed report format will be the following:
492 Chapter 10 The Seven-Step Method
C b a x
The linear tangent to F(x) at point (a, F(a)) intersects the x axis at point
b, which may be closer to the root than a. Point b is then used as a new
approximation of the root value, and the same process is repeated. It is
possible to compute the value of b if we know F’(x), the first derivative
of F(x).
Slope = F(a)/(a - b) = F’(a)
gives: b = a - F(a)/F’(a)
The method will fail if the slope is zero, as the tangent is parallel to
the x axis: in that case there is no root in the vicinity of the point. We
must protect ourselves against failure by not allowing a division by
zero, and by limiting the number of iterations. This can be directly
transposed to complex numbers.
Section 10.6 Problems 499
500 Chapter 10 The Seven-Step Method
Section 10.6 Problems 501
502 Chapter 10 The Seven-Step Method
Section 10.6 Problems 503
504 Chapter 10 The Seven-Step Method
Section 10.6 Problems 505
506 Chapter 10 The Seven-Step Method
Appendix Solutions 507
Appendix Solutions
This appendix contains the solutions to the first few problems at the end of
each chapter. Oftentimes, there may be many correct answer for the same
question; however, only one answer to each problem is provided.
Appendix Overview
Chapter 1 Solutions 1-3......................................................508
Chapter 2 Solutions 1-3......................................................508
Chapter 3 Solutions 1-7......................................................510
Chapter 4 Solutions 1-3......................................................511
Chapter 5 Solutions 1-3......................................................512
Chapter 6 Solutions 1-3......................................................514
Chapter 7 Solutions 1-3......................................................515
Chapter 8 Solutions 1-3......................................................516
Chapter 9 Solutions 1-3......................................................517
508 Appendix Solutions
Solution to Problem 2
a. Display — human environment.
b. Sensor — physical environment.
c. Digital-Analog Converter — physical environment
d. Scanner — human environment
e. Clock — physical environment
Solution to Problem 3
a. Alan Turing developed a machine used to define the limits on what is
computable.
b. Al-Khwarizimi studied sets of rules which are now called algorithms.
c. It is not clear who designed and built the first electronic digital
computer. The contributor is not in the list.
d. George Boole discovered that symbolism of mathematics could be
applied to logic.
e. Charles Babbage designed the first general-purpose “analytical
engine”.
f. John Von Neumann introduced the concept of a stored program where
instructions and data are both stored in memory.
g. Blaise Pascal designed the first mechanical adding machine.
12
Price P 20
Original
is $2
16
12
Q
2 4 6 8
Replace Replace
Extended Original by: Failsafe-Extended by:
Failsafe Extended
Error Extended
Message Original Failsafe
Extended
Original
510 Appendix Solutions
Chapter 3 Solutions 1-7
Solutions to problems 1 through 7
1. Binary Number Drill
a. 10 = 2 in decimal
b. 1010 = 8 + 2 = 10 decimal
c. 101010 = 32 + 8 + 2 = 42 decimal
d. 7 = 111 binary
e. 17 = 16 + 1 = 10001 binary
f. 170 = 128 + 32 + 8 + 2 = 10101010 binary
Time 1
1430 100
N D 5. Octal: Base 8
Divide a. 11 = 8 + 1 = 9 decimal
Q R b. 23 = 2 × 8 + 3 = 19
c. 132 = 1 × 64 + 3 × 8 + 2 = 90
60 14 30
6. Hex: Base 16
Multiply a. 11 = 16 + 1 = 17
b. CC = 12 × 16 + 12 = 204
840 c. F00 = 15 × 16 × 16 = 3840
Add
7. Other Bases
870 5, 10, 20 are from anatomy
12, 20, 60 have many divisors
Mins (used for time and arc measure)
Output Message
Output Give Input Cost C
Message Change
Give Change
Appendix Solutions 511
Solution to problem 2
Input H, M
True False
Output H " o'Clock" M=0
True False
Output "Half past " H M = 30
True False
Output M " minutes after " H 0 < M < 30
True False
Output (60 - M) " minutes before " 1 H = 12
Solution to problem 3
Input C Input C
Set Sum to C
C=5
T F
Sum < 15
Input C Input C
Input C
C=5 C=5
T F T F Add C to Sum
=
Input C
Output Item
etc etc
C=5
T F Output Sum > 15
Item T F
etc
etc etc Output
etc Change
512 Appendix Solutions
Chapter 5 Solutions 1-3
Solution to problem 1
A B B C C A Conditions Input Values Output
AB C D E F M1
min A<B<C 1 2 3 1 2 1
min min 2
A<C<B 1 3 2 1 2 1
D E F 2
B<A<C 2 1 3 1 1 2
Max 2
B<C<A 2 3 1 2 1 2
2
C<A<B 3 1 2 1 1 2
2
M1 C<B<A 3 2 1 2 1 1
2
Solution to problem 2
False True
A<B
B<A
Solution to problem 3
More Mid Another Mid with data flow
A B C A B C A B C
If (B < A) AND (A < C) OR
(C < A) AND (A < B)
Sum3 Max3 Min3
Set Mid to A
Else
If (A < B) AND (B < C) OR Sum2
(C < B) AND (B < A)
Set Mid to B
Diff2
Else
Set Mid to C
Mid
Appendix Solutions 513
Chapter 6 Solutions 1-3
Solution to problem 1
Monthly
Calendar
Set MonthDay to 1
For Week = 1 to 6 by 1
DoWeek
For Day = 1 to 7 by 1
DoDay
Output NewLine
Solution to problem 2
Plot
Up
For Y = MaxY to 0 by -1
DoLine
For X = 0 to MaxX by 1
DoMark
Output NewLine
Set F to f(x)
Set Fint to F
If Fint = Y
Output Mark
Else
Output Blank
Solution to Problem 3
Sine S = X – X3 + X5 – X7 +...– Xp
3! 5! 7! p!
Term T = 1 2 3 4 N
Power P = 1 3 5 7 P
Sine X
Set SineVal to 0
Set Term to 1
Set TermVal to X
Set NumTerms to N
While Term < NumTerms
Compute Sine
Set Term to Term + 1
Compute Sine
Compute TermVal
If Mod(Term, 2) = 1 Compute TermVal
Set SineVal to SineVal Set Power to Term + Term – 1
+ TermVal Set Incr to (X × X) /
Else ((Power + 1) × (Power + 2))
Set SineVal to SineVal Set TermVal to TermVal × Incr
– TermVal
Solution to Problem 2
Note:
Tree of Calls:
Values above each line are input to the right.
Values below each line are output to the left.
0 N
M 1
A B A B
11 P
0 1 0 1 1
N N 1 N
0
C 1 D 0 10 P
P P 0
E 1 F 0 can Q N
break
Q out N
10
1 more 1 P
G
Note: N
If variables A, B are binary then N
is a NOT, P is an AND, Q is an OR Call Order is N P N P Q N N P N.
and M is an eXclusive-OR. For A=0, B=1, the output G is 1.
Appendix Solutions 515
Solution to Problem 3
A Block A can call B and D.
Block B can call B recursively, D and C.
B Block C can call C.
C Block D can call D, B, E and H.
Block E can call E, H, F and G.
D Block F can call F and G.
E
Block G can call G and F.
Block H can call H and E.
F X in E can be used in E, F and G.
G If Y is defined in B, D, F then
• Y of B is seen in B and C.
H • Y of D is seen in D, E, G and H.
• Y of F is seen in F.
• A does not see any Y.
Solution to Problem 2
Side Bar Plot
Input Array(A, N)
Input Array(T, S)
For Bars = 1 to N by 1
Set Length to A[Bars]
For Thickness = 1 to T by 1
For Star = 1 to Length by 1
Output Star
For Spaces = 1 to S by 1
Output New Line
End Side Bar Plot
Solution to Problem 3
Up Bar
Input A, M, N
For Row = N to zero by -1
For Bar = 1 to M by 1
If A[Bar] > Row
Output Mark
Else
Output Space
Output New Line
End Up Bar
Index
Graphs 46
hierarchical 74, 119
high-level 31
A low-level 31
abstract data type 358, 397, 409 modifying 47
abstract data types notations 78
array queues 446 Order of complexity 453
array stacks 441 pseudocode 47, 75, 118
implementing 441 refinement 256
pointer queues 448 representations 74, 78, 118
pointer stacks 444 reuse 51
Abstraction 134, 164, 166, 234 Robustness 120
Abstraction Form 130 selecting 79
Action 65, 119, 128, 165, 166, 176 Space efficiency 453
in programs 180 static structure 234
on data 180 static view 176
actions tabular 74, 86, 87, 118
groups of 302 test 421
Al-Khwarizmi 23 trace 49, 66, 162, 182, 266
algorithm 30, 65, 74, 75, 118, 119, 458 Unambiguous 76, 120
algebraic 74, 82, 118 Verbal 45, 74, 80, 118
alternate 52, 164 well-structured 120
alternative 137 Alias 350
analyze 421 analysis
assertions 146 Count Sort 421
communicating 56 Select Sort 427
comparing 54 Swap Sort 424
Complete 76, 119 analytical engine 23
Data-flow diagram 47, 74, 118 argument 307, 350
decomposing 111 array 86, 119, 166
Deterministic 76, 119 Binary search 436, 437
dynamic behavior 234 Bubble Sort 422
dynamic view 176 Count Sort 419
Ease of Use 77 deck of cards 158
Efficiency 77, 198, 232 homogeneous items 358
Elegance 77, 119 indices 358
Embedding 51 Linear search 436
equivalence 53, 135, 164, 187 Rank 453
execute 30, 49 Recursive Sort 432
Execution time 453 searching 435
Extending 48, 131, 186, 257 Select Sort 425
Finite 76 Sort and copy 417
flowblock 74, 118 Sort and rank 417
Flowchart 45, 74, 118 Sort in place 418
Foolproofing 50 sorting 416
Generality 77, 119 Swap Sort 422
Generalizing 47 Arrays 358
Good Structure 77 homogeneous 360
520 Index
H
hardware 19
L
heterogeneous 377, 408 leaf node 407, 409
hiding and sharing of data 348 least significant digit 106
Hierarchical programming 166 Libraries, Modules 463
Hollerith, Herman 23 linear search 436
homogeneous 377, 408 linked list 393, 409
Horizontal views 213 Local variables 310
Logical conditions 198
Logical data type 279, 290
logical expression 100, 119
I equivalency 203
I/O devices logical operation
transducers 21 Conjunction (AND) 198
identifier 177, 235 Disjunction (OR) 199, 279
if-then-else 129 Negation (NOT) 199, 280
implementation 36, 66 Logical type 179
Index 523
loop
initialization of values 259
loop control variable 264, 267, 291
loop invariant 176, 214, 234, 235
P
complete body of the loop 231 Packages 463
using 229 paradigm 186, 235
Loop-and-Count form 262 parameter 307, 350
Loosely coupled 350 Parameter crossing 336
loosely-coupled 338, 339, 349 Parameter passing 323, 348
Lord Byron 59 by reference 312, 315
Lovelace, Ada 59 by value 312, 315
parameterized block structure 304
parameters 305
Pascal,Blaise 23
M Pass by reference 350
Pass by value 350
Pattern Matching 438
Search and Count 438
N Pattern MatchingFind First Match 438
n-dimensional list 358, 409 pointer 392, 409
n-tuple 360, 409 Polya,George 31
Nassi-Shneiderman diagrams 113 precedence 119
Negation 199 precision 283, 291
nested selections 257 predicate 99, 119
Nesting 166 problem solving 30
Nesting Selections coding 35
in Fors 269 detailed design 38
nests of loops 290 development of testing strategy 486
node 407, 409 development of testing strategy
application 469
divide and conquer 33, 39
O documentation completion 37, 471,
488
one-dimensional arrays 360 documentation completion
operand 119 application 472
operating programs 21 general algorithms 281
operation Polya’s four steps 31
assignment 180 problem definition 32, 458, 476
comparing values 181 problem definition application 460
incrementing 181 program coding and testing 35, 471,
modulus 205 488
operations program maintenance 37, 474, 489
on Characters 276 program maintenance application 474
operator 91, 119 seven step method 32, 63, 458
precedence 92 solution design 33, 140, 461, 476
operators solution design application 461
AND 99 solution refinement 74, 464, 478
logical 100 solution refinement application 464
NOT 100 systematic method 32
OR 100 task 66
Order of complexity 453 test 66
output parameter 306, 312 testing algorithms 197
524 Index
flowchart 115 software life cycle 32, 60, 66, 458, 489, 491
For Form 262 solution design
infinite loop 207 task 34
initialization 212 solution refinement
initialization of values 259 algorithm 34
initializing loop 110 sorting
iteration 110, 205 pass 428
loop 109 sorting strategies 416
loop body 109, 205 Space efficiency 421
nested 132 specification 194
nesting 265 specifications 32, 66, 459
Repeat-Until 203 speed of operation 198
side effect 208 stacks 399, 401, 409
terminating value 258 State trace 211, 235
termination condition 109 statement
trace 205, 266 logical 99
While loop 205 static view 176
repetitions 264, 290 stepwise refinement 34, 66
Roman numerals 78 strategies 416
Root node 409 Strength 350
String 179, 361, 399, 409
pattern matching 438
structure chart 33, 66
S structured data 166
scientific notation 91, 178, 235 break-out diagrams 153
Scope 350 linear form 154
Select Form 259, 260, 261, 290, 291 structured programming 128, 164, 166
Select Sort 418, 425 stub 467, 491
Selection 120, 166 stucture of actions 165
Selection Form 108, 120, 129, 164, 176, 185, sub-algorithm 86, 109, 120, 219, 234
234, 280 subproblem 33
flowblock 114 subprogram 300, 350
flowchart 114 ”parameterless” 316
larger 189 arguments 315
nested 131, 189, 192, 194 binding 335
proof of equivalence 187, 192 errors 326
selections 257, 290 groups of actions 302
sentinel value 255, 291 input parameter 306
Sequence 166 interface specification 306
Sequence Form 108, 120, 129, 164, 176, invocation 311
182, 234 invoked 219
flowblock 114 no local variables 316
flowchart 114 no parameters 316
set 409 one-way communication 315
difference 385 ouput parameter 306
intersection 385 parameter 300
membership 385 parameter crossing 336
union 385 parameters only 319
Sets 358 recursion 343
homogeneous 358 rules for variable use 318, 334, 348
side effect 208, 235, 350 simply large programs 300
software 19 structure charts 329
526 Index