Principles of Programming
Principles of Programming
TM
CodeWarrior
Principles of
Programming
Metrowerks CodeWarrior Copyright 1993-1995 by Metrowerks Inc. and its Licensors. All
rights reserved.
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.
ALL SOFTWARE AND DOCUMENTATION ON THE COMPACT DISC ARE SUBJECT
TO THE LICENSE AGREEMENT IN THE CD BOOKLET.
Canada and International
Metrowerks Inc.
1500 du College, suite 300
St. Laurent, QC
H4L 5G6 Canada
U.S.A.
Metrowerks Corporation
Suite 310
The MCC Building
3925 West Braker Lane
Austin, TX 78759-5321
voice: 512-305-0400
fax: 512-305-0440
http://www.metrowerks.com
register@metrowerks.com
support@metrowerks.com
sales@metrowerks.com
METROWERKS
America OnLine:
goto: METROWERKS
Compuserve:
goto: METROWERKS
eWorld:
goto: METROWERKS
Table of Contents
Table of Contents
Chapter 1 A Road Map
1.1
1.2
1.3
1.4
1.5
1.6
Preview....................................................................14
Introduction to The Principles of Programming........15
A Global View.........................................................15
The Road Ahead.......................................................16
Signs Along the Road...............................................17
Computers................................................................18
A Low Level View...................................................18
Systems and Their Environments...............................19
History of Programming and the Earth.....................21
Review Top Ten Things to Remember....................24
Glossary...................................................................25
Problems..................................................................27
Chapter 2 An Overview
2.1
2.2
2.3
2.4
2.5
Preview....................................................................30
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
Break-Out Diagrams..................................................39
More on Break-Out Diagrams...................................41
Algorithms and Their Representations.......................45
Modifying Algorithms..............................................47
Alternative Algorithms.............................................52
Equivalence of Algorithms........................................53
Testing......................................................................54
Programming Languages..........................................56
Communicating Algorithms......................................56
Basic.........................................................................56
Fortran.....................................................................57
Pascal.......................................................................57
Modula-2..................................................................58
C..............................................................................58
iii
iv
Table of Contents
2.6
2.7
2.8
2.9
Ada..........................................................................59
Other programming languages.................................59
Life Cycles Stages of Programming.........................60
Review Top Ten Things to Remember....................63
Glossary...................................................................65
Problems..................................................................67
Chapter 3 Algorithms
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
Preview....................................................................74
What Are Algorithms?..............................................75
Algorithm Definition................................................75
General Properties of Algorithms..............................75
Desirable Attributes for Algorithms...........................77
Different Algorithm Representations.........................78
Verbal Representations.............................................80
Algebraic Representations (formulas and
expressions).....................................................82
Tabular Representations (tables, arrays, and
matrices)..........................................................86
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
Flow of Control Diagrams........................................107
Flowcharts................................................................107
Larger Flowcharts Using Subprograms...................110
Flowblocks...............................................................113
Pseudocode..............................................................115
Review Top Ten Things to Remember....................118
Glossary...................................................................119
Problems..................................................................121
4.3
Preview....................................................................128
Building Blocks for Structured Programming............128
The Four Fundamental Forms...................................128
Connecting Several Forms Sequences and Nests.......131
Deep Nesting............................................................133
Different Algorithms, Same Problem.........................135
Equivalent Algorithms..............................................135
Table of Contents
4.4
4.5
4.6
4.7
4.8
Alternative Algorithms.............................................137
Top-down Algorithm Design....................................140
Job Description Example...........................................144
Change Maker Example............................................145
A Game Example, Fifty.............................................148
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
Review Top Ten Things to Remember.....................164
Glossary...................................................................166
Problems..................................................................167
5.3
5.4
5.5
5.6
5.7
5.8
5.9
Preview....................................................................176
Programs..................................................................176
Data for Programs.....................................................176
Actions In Programs.................................................179
Sequence Forms........................................................182
More Programs Using the Sequence Form................183
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
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
Invocation Forms.....................................................219
Seconds Example......................................................221
De-militarize Time Example......................................222
Improving Programs................................................224
Nested Loops and Selections.....................................224
Using Invariants.......................................................229
Review Top Ten Things to Remember....................234
Glossary...................................................................235
vi
Table of Contents
5.10 Problems..................................................................236
6.4
6.5
6.6
6.7
6.8
6.9
Preview....................................................................252
Using External Data and Files....................................252
End-Of-File Markers..................................................255
More Building Blocks...............................................259
The Select Form........................................................259
The For Form...........................................................262
Using the For Forms in Nests....................................265
Nesting Fors in Fors.................................................265
Nesting Selections in Fors.........................................269
Creating Plots with For Nests....................................273
More Data Types......................................................275
The Character Type...................................................275
The Logical Type......................................................279
Some General Problem-Solving Algorithms..............281
Bisection Finding Values.........................................281
Maximum Power Optimizing Power Output...........284
Solver Solving Equations........................................287
Review Top Ten Things to Remember....................290
Glossary...................................................................291
Problems..................................................................292
7.3
7.4
7.5
Preview....................................................................300
Subprograms............................................................300
How to Simplify Large Programs..............................300
What are Parameters?................................................305
Data Space Diagrams................................................309
Parameter Passing.....................................................312
Passing Parameters In and Out..................................312
Special Cases.............................................................316
Some Examples.........................................................321
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
More Types of Subprograms.....................................343
Recursion Self-Referencing Subprograms................343
Table of Contents
7.6
7.7
7.8
Functions..................................................................345
Modules...................................................................346
Review Top Ten Things to Remember....................348
Glossary...................................................................350
Problems..................................................................351
8.3
8.4
8.5
8.6
8.7
8.8
8.9
Preview....................................................................358
Arrays......................................................................358
What are Data Structures Anyway?...........................358
One-Dimensional Arrays...........................................360
Performing Operations on One-Dimensional Arrays..361
Using One-Dimensional Arrays in Algorithms..........364
Two-Dimensional Arrays..........................................367
Performing Operations on Two-Dimensional Arrays 370
Matrix Multiplication................................................373
N-Dimensional Arrays..............................................375
Records....................................................................377
What are Records?....................................................377
Accessing Record Components the Dot Notation....380
Combining Arrays and Records................................382
Sets...........................................................................384
What are Sets?...........................................................384
A Difficult Sets Example (optional)............................386
Data Structure Building Tools....................................392
Dynamic Variables...................................................392
Pointers....................................................................392
Abstract Data Types..................................................397
Strings......................................................................399
Stacks.......................................................................401
Queues.....................................................................405
Trees.........................................................................407
Review Top Ten Things to Remember....................408
Glossary...................................................................409
Problems..................................................................410
Preview....................................................................416
Sorting......................................................................416
General Sorting Strategies.........................................416
The Four Methods of Sorting....................................418
Count Sort.........................................................419
Count Sort Analysis...........................................421
vii
viii
Table of Contents
9.3
9.4
9.5
9.6
9.7
9.8
Swap Sort..........................................................422
Swap Sort Analysis............................................424
Select Sort..........................................................425
Select Sort Analysis............................................427
Insert Sort..........................................................428
More Complex Sorting..............................................428
Improving Sorts........................................................428
Recursive Sorts.........................................................432
Searching..................................................................435
Linear Searching.......................................................436
Binary Searching.......................................................437
Pattern Matching......................................................438
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
Review Top Ten Things to Remember....................451
Glossary...................................................................453
Problems..................................................................454
Table of Contents
Appendix: Solutions
Chapter
Chapter
Chapter
Chapter
Chapter
Chapter
Chapter
Chapter
Chapter
1
2
3
4
5
6
7
8
9
Solutions
Solutions
Solutions
Solutions
Solutions
Solutions
Solutions
Solutions
Solutions
1-3.......................................................508
1-3.......................................................508
1-7.......................................................510
1-3.......................................................511
1-3.......................................................512
1-3.......................................................514
1-3.......................................................515
1-3.......................................................516
1-3.......................................................517
Index ..........................................................................................519
ix
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 overexplained. 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
1.2
1.3
1.4
1.5
1.6
Preview....................................................................14
Introduction to The Principles of Programming............15
A Global View..........................................................15
The Road Ahead.......................................................16
Signs Along the Road................................................17
Computers.................................................................18
A Low Level View.....................................................18
Systems and Their Environments................................19
History of Programming and the Earth......................21
Review Top Ten Things to Remember........................24
Glossary...................................................................25
Problems...................................................................27
14
Chapter 1
1.1
Preview
A Road Map
Section 1.1
Preview
15
and world history, should put the brief lifetime of computers and computing
into its proper perspective.
1.2
16
Chapter 1
A Road Map
Section 1.2
17
2.
Next, the actual material of the chapter is provided, where the major
topics are divided into sections. Since the emphasis through each
chapter is that we learn best by example, each section has many
examples illustrating the topic being presented.
3.
4.
5.
Finally, each chapter ends with a set of Problems to solve. This is one
of the most important parts of each chapter. There are always a few
problems for which the solutions are provided in an appendix at the
18
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 note in
margin which
directs you to
useful
information.
1.3
This is a tip or note box. Inside this box, important information and
tips can be found.
In addition to tip boxes, when a paragraph briefly touches upon a subject which
is covered in more detail in another chapter, a reference is provided in the left
margin.
Computers
A Low Level View
As you progress, youll use the computer to do more and more complex things.
Its always nice and sometimes even actually useful to know more about the
tools you use, so well take a look here at computers.
Most computers, big or small, have the same basic capabilities: they can input
(read) data from an external device and store it for later use, they can
manipulate the stored data by executing the instructions that constitute a
program and they can output ( write) results onto an external device.
You do not need to know many details on computers in order to program them,
just as you dont need to know many details about carburetors or transmissions in
order to drive cars. Of course, knowledge of these details may be useful, but is
not always necessary. It is only when trying to make the best and most efficient
use of computers that these details become important.
Computers differ in details, but they have a common structure. They can be
viewed as comprising four units: a processing unit, a memory unit, an input unit
and an output unit. These units are not always physically separate, but it is
useful to view them functionally this way as in Figure 1.1.
A Memory Unit stores information that can be retrieved, modified and
processed. It not only stores the data that the program will process, but also
the actual instructions of the program. This concept of a stored program is
extremely important, for it makes the computer into a general purpose machine
where changing the program in memory literally changes the behavior of the
machine.
Section 1.3
Figure 1.1
Computers
19
A simple computer
controls the
computer, performs
operations on data
Processing Unit
Input
stores information
Output
Memory
20
Chapter 1
A Road Map
Here, we look at computing from the view of a computer interacting with both
the human and the physical environment.
Figure 1.2
Keyboard
Display
Mouse
Scanner
Sensor
Human Environment
DigitalAnalog
Converter
Clock
Physical Environment
I/O Peripherals
Computer
Memory Devices
Printer
Software
Tape
Translators
compilers
Plotter
Disk
Utilities
editors
Graphic
interpreters
libraries
Operating Systems
resource
scheduler
Other
Processor
Etc.
memory
manager
Modem
telephone lines
Other
Computer
Section 1.3
Computers
21
Earth history
Eras
Epochs
Precambrian
Mesozoic
Paleozoic
(fish & reptiles)
Triassic
Jurassic
Mesozoic
dinosaurs
Cretaceous
Cenozoic
Cenozoic
mammals
Tertiary
Quaternary
humans
Pleistocene
(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.
Figure 1.4
Archeological View
8000 humans
cultivate &
urbanize
2000 Hammurabi
1 AD
Aristotle
500
0
1000
2000
A.D.
1000
1500
1800
2000
Constantine
Attilla
Mohammed
Charlemagne
Al-Khwarizmi
Genghis Khan
da Vinci
Shakespeare
Pascal
1820
Babbage's
engine
1840
Boole's
algebra
1860
1880
Hollerith's
cards
1900
1920
Turing's
machine
1940
Von Neumann
computer
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 Pascals 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
24
Chapter 1
1.4
Review
A Road Map
2.
Most computers, big or small, have the same basic capabilities: they
can input (read) data from an external device and store it for later
use, manipulate stored data by executing the instructions that constitute
a program and they can output, or write, results onto an external device.
3.
4.
5.
6.
7.
The Input and Output Units serve either to input information (from
keyboards or files on disks) into the memory, or to output information
(to printers or graphic displays) from the memory.
8.
9.
10.
Section 1.5
1.5
Glossary
25
Glossary
A to D converter: (Analogue to
Digital converter) A physical device
that takes an analog or continuous
value (for instance, the intensity of
an electric current) and converts it
into a digital (numerical) value.
ALU: Arithmetic Logic Unit, a
component of the computer Central
Processing Unit that executes
arithmetic and comparison
operations.
Analog value: A directly measurable
physical value (temperature, current
voltage, pressure, and so on).
Bus: A signal transmission cable
making it possible to interconnect
various devices.
Compiler: A piece of software used to
translate a program written in a
high-level programming language
into machine language.
CPU: Central Processing Unit, the
heart of the computer that controls
the behavior of its other components
and performs the operations on the
data.
D to A converter: Digital to Analog
converter, a device to convert digital
(numerical) values to their physical
equivalent (current voltage,
temperature, and so on).
26
Chapter 1
A Road Map
Section 1.6
1.6
Problems
27
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
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
Influential People
Match the following list of names with their contributions to
computing. Note: there is one more contribution than there are
contributors!
George Boole
Al-Khwarizmi
Charles Babbage
Blaise Pascal
Alan Turing
a.
b.
c.
d.
e.
28
Chapter 1
A Road Map
f.
g.
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
Chapter 2 An Overview
This chapter provides an overview of problem solving with a computer,
showing a brief birds-eye view of the general ideas, and how they are
related.
Chapter Overview
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
Preview....................................................................30
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
Break-Out Diagrams.................................................39
More on Break-Out Diagrams....................................41
Algorithms and Their Representations......................45
Modifying Algorithms..............................................47
Alternative Algorithms............................................52
Equivalence of Algorithms........................................53
Testing......................................................................54
Programming Languages............................................56
Communicating Algorithms.......................................56
Basic........................................................................56
Fortran.....................................................................57
Pascal.......................................................................57
Modula-2..................................................................58
C..............................................................................58
Ada..........................................................................59
Other programming languages...................................59
Life Cycles Stages of Programming...........................60
Review Top Ten Things to Remember........................63
Glossary...................................................................65
Problems...................................................................67
29
30
Chapter 2
2.1
Preview
An Overview
A cooking recipe:
2.
Turn onto Route 9and go about threequarters of a mile and it will be on your
left. You cant miss it!
Cream Horns
Roll out thinly puff or flaky pastry into an oblong
approximately 12 inches long, and cut into 1inch strips. Moisten one edge of each strip and
roll the strip around a cream horn tin, starting at
the pointed end of the tin and overlapping the
pastry very slightly. Bake in a hot oven until
crisp1015 minutes. Slip the horns off the
tins. When they are cold, fill them with
whipped cream and dredge with confectioners
sugar.
A crochet pattern:
Section 2.1
Preview
31
2.2
understanding the problem: This first step can be very difficult but is
absolutely crucial. Although it happens all of the time, it is foolish to
attempt to answer a question that is not fully understood. In general,
one must find the given data, what is the unknown (the required result)
and what is the relationship that links the given data with the
unknown. It is also important to verify that the given information is
sufficient to solve the problem.
2.
devising a plan: Once the problem is understood, one must devise the
plan of action to solve the problem. A plan is formed by proceeding
from the data to the result according to the relationship that links
them. If the problem is trivial, this step will not require much
thinking. General techniques include the following:
Finding if there are known similar problems,
Reshaping the original problem so that it resembles a known
problem
32
Chapter 2
An Overview
4.
As we all know, there is usually more than one correct way of solving a problem.
When several people are faced with the same problem, it is likely that each
individual will reach a solution in a different manner. However, to be
efficient, a person must adopt a systematic method of problem solving. When
using a computer to solve a problem, the use of a systematic method is crucial.
Without one, people tend to rush over the steps and find out too late that they
should have spent more time in preparation and planning.
Based on the Polya problem solving method, we introduce here a seven-step
problem solving method that can be adapted to each persons own problem
solving style. This method is closely related to what is known as the software
life cycle (the various stages in the life of a program).
The seven steps of the method are:
1.
Problem Definition
2.
Solution Design
3.
Solution Refinement
4.
5.
6.
Documentation Completion
7.
Program Maintenance
Step 1
Problem Definition
Polyas first step is to fully understand the problem. The initial description of
a problem is usually vague: it must be made precise. The poser of the problem
the userand the problem-solver must work together in order to ensure that
both understand the problem. This should lead to complete specifications of
the problem including the precise definition of the input datathe given
dataand of the desired outputthe result.
Section 2.2
Step 2
33
Solution Design
In this step, we want to define the outline of a solution. Starting from the
original problem, we divide it into a number of subproblems. These
subproblems, being necessarily smaller than the original problem, are easier to
solve and their solutions will be the components of our final solution. The same
divide and conquer method is applied in turn to the subproblems until the
whole problem has been converted into a plan of well-understood steps.
To illustrate this step, lets take a simple non-computer problem such as the
recipe for Cream Horns given in the previous section. Based on this recipe, we
can break down the problem into three subproblems:
1.
2.
3.
Structure chart
complete solution
component
sub-component
Make The
Horns
Recipe for
Cream
Horms
Prepare
Whipped
Cream
Finish The
Horns
Slip Off
Tins
Fill With
Cream
Dredge
WIth
Sugar
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 subcomponents.
34
Chapter 2
An Overview
Step 3
Solution Refinement
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
Pseudocode 2.3
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.
Step 4
The preceding step produces the algorithms that will be used to write the
computer program that corresponds with our solution. This program will be
executed by the computer and be expected to produce the correct solution for our
problem. It is necessary to try this program with several different combinations
of input data to make sure that the program will give the correct results in all
cases
Each of these tests consist of different combinations of input data, each of
which is referred to as a test case. To test the program thoroughly, we must
define an assortment of test cases that cover, not only normal input values, but
also extreme input values that will test the limits of our program. In addition,
special combinations of input values will be needed to test particular aspects of
the programs
For example, test cases for a payroll program should include values covering
the full range of pay rates including limit values, a maximum number of hours
worked, and so on. A typical test case would define the hourly rate, hours
worked, and expected result as follows:
Rate = $10.00 Hours = 35 Result = $350.00
It is best to develop test cases before writing the program because the test cases
can be used to check our algorithms at this stage, and because the pressure to
complete a program might lead to a loss of objectivity when testing on the fly.
Note:
Step 5
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.
36
Chapter 2
An Overview
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 programs 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
Step 6
37
Documentation Completion
Documentation begins with the first step of program development and continues
throughout the lifetime of the program. A programs documentation must
include the following:
Explanations of all of the steps of the method,
The design decisions that were made, and
The problems that were encountered during the writing and testing of
the program.
The final documentation must also include a printed copy of the program, called
a program listing. This listing should be made readable by careful layout as
one does with a technical reportwhich is what the written form of the
program really is: a written description of the computer solution of the
problem. Programs can be made easier to understand by the reader if all of
their complex parts include explanations in the form of comments. Later, when
the program must be changed, these explanations will make the changes easier
to implement.
To be complete, the documentation must include some user instructions. For
programs that will be used by people unfamiliar with computers, it is necessary
to include a users manual that explains, without using technical jargon, how to
use the program, how to prepare the input data and how to interpret the
programs results.
Step 7
Program Maintenance
38
Chapter 2
An Overview
As we have seen above, planning and problem solving are the main concerns of
this book. The problems may be large and complex (like controlling a factory or
managing an inventory) or they may be smaller (such as making engineering
calculations, or computing statistics). In all cases, well need to use our seven
step method.
Section 2.2
39
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.
Note:
2.3
Break-Out Diagrams
One useful way of making the complexity of problem solving manageable is to
use a tree-like or hierarchical skeleton for viewing problems in levels, as
illustrated by the structure chart in Figure 2.1. The following figures (Figures
2.3 through 2.6) show four hierarchical representations called break-out
diagrams.. These are another form of structure charts.
Time can be broken down into years, months, days (and further) as suggested in
Figure 2.3. This break-out diagram, if completely expanded, would create one
sequence of 365 (or 366) days at the second level, and one sequence of 8760 (or
8784) hours at the next level.
40
Chapter 2
An Overview
Figure 2.3
Year
January
February
March
April
May
November December
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.
Figure 2.4
Book
Section 1
Chapter 1
Table of Contents
Section 2
Chapter 2
Main body
Index
Review
Chapter 10
Problems
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
employees gross pay
Figure 2.5
Sub-Actions
Determine Gross Pay
Get Hours
Get Rate
Calculate
Determine Deductions
Find Taxes
Find Misc.
Section 2.3
Break-Out Diagrams
41
Attributes
Name
First Name
Sex
Seniority
Address
Last Name
Supervisor
Birthyear
BirthDate
Birthmonth
Birthday
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.
42
Chapter 2
An Overview
Figure 2.7
Work
Day
PM
EVE
Post-Coffee
Lunch
Pre-Tea-Time
Tea-Time
Dinner Time
Snack Time
Pre-Coffee
Coffee Break
Post-Coffee
AM
Work
Day
Pre-lunch snack
Lunch
Lunch
PM
Coffee
EVE
Pre-Tea-Time
Tea-Time
Dinner Time
Snack Time
Section 2.3
Figure 2.8
Routine
Break-Out Diagrams
43
Morning
Routine
Wake Up
Shower
Drink Coffee
Eat
Eat Cereal
Drive to Work
Read Newspaper
Shower
Drink Coffee
Breakfast
Eat
Drive to Work
Read Newpaper
Eat Cereal
This BOD
is much
more
orderly.
Cohesive: All of the items within a breakout box must fit together.
Frequencies, shown in the break-out diagram in Figure 2.9, range from a
few cycles per second, or Hertz (Hz), to thousands of cycles per second
(kHz), to millions of cycles per second (MHz) and beyond. At the left of
this diagram, there is great cohesion. However there is some lack of
cohesion in the part at the right. The VHF frequencies have a mixture
of TV channels and FM ranges. There is a gap between TV Channels 6
and 7 in which some FM channels are used. These mixtures and gaps
show a lack of cohesion.
44
Chapter 2
An Overview
Figure 2.9
Problem:
TV channels and
FM ranges are
mixed together.
TV
Channels
13
Visible light
300 GHZ
12
HI
Freq
11
UHF
10
9
TV
300 MHZ
Frequency
VHF
MID
Freq
FM
TV
300 KHZ
5
AM
Radio
4
3
LOW
Freq
Sonic waves
cohesive
not cohesive
Alternative forms of break-out diagrams are often used and variations are
possible. Some common alternatives to BODs are called: Warnier Diagrams2 ,
Orr Charts3 , or SADT diagrams 4 . Some of these involve boxes in three
dimensions, others involve parentheses and other notations
2
3
4
Section 2.4
2.4
45
For more
information on
the different
possible
algorithm
representations,
see Chapter 3.
With this algorithm, if, for example, the number of hours worked is 25,
then the pay is simply determined by multiplying the rate by the hours
(1025 = 250). But if the hours are 50, then the pay is the sum of two
parts, a regular part and an overtime part. The pay for the first 40
hours is the regular rate multiplied by 40 which is (1040 = 400). For
the 10 hours over 40 we use the higher rate of 15 (time-and-a-half) to
get (50 40)15 = 150. The total pay is the sum of these regular and
overtime amounts (400 + 150 = 550). So a total pay of $550 is the final
output of the algorithm.
Flowchart representations of an algorithms are made of various boxes
joined by arrows as in Figure 2.11. In flowcharts the following symbols
are used:
Oval boxes indicate the start and the end.
Square boxes represent actions, while
Diamonds, or boxes with pointed ends, represent decisions to be
made. Decision boxes contain the conditions that determines which
arrow will be followed out of them.
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 1040 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.
Figure 2.11 The pay algorithm expressed as a flowchart
begin
Input Hours
Hours
True
False
40
Set Pay to
10 Hours
Set Pay to
10 40 +
15 (Hours - 40)
Output Pay
end
20
40
60
50
H
hours worked
Section 2.4
47
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
Hours
40
True
False
Set Pay to
Rate 40 +
1.5 Rate (Hours - 40)
Set Pay to
Rate Hours
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
49
True
Hours
40
True
Set Pay to
Rate Hours
Hours
60
False
False
Set Pay to
Rate 40 +
1.5 Rate (Hours - 40)
Set Pay to
Rate 40 + 1.5 Rate 20 +
2 Rate (Hours - 60)
Output Pay
end
Lets 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
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
10
300
5
400
20
40
60
80
100
H
hours worked
Foolproofing is the process of making an algorithm more reliable, failsafe, or robust, by anticipating erroneous input or other difficulties. For
example, if the number of hours input is more than the number of hours
in a week (724 = 168), then an error message should be produced. The
resulting foolproofed, or robust, algorithm is given in Figure 2.18. It
could be improved further to recognize the input of a negative number of
hours, and output another error message.
Section 2.4
51
True
Hours
>
7 24
True
True
Set Pay to
Rate Hours
Hours
40
Hours
60
False
False
Set Pay to
Rate 40 +
1.5 Rate (Hours - 40)
Set Pay to
Rate 40 + 1.5 Rate 20 +
2 Rate (Hours - 60)
Output Pay
Output "Error"
end
52
Chapter 2
An Overview
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, lets consider the previous
simple pay algorithm from Figure 2.11, which is repeated on the left side of
Figure 2.19.
Figure 2.19 Equivalent algorithms
begin
begin
Input Hours
Input Hours
Set Pay to
10 Hours
True
False
Hours
40
Set Pay to
10 40 + 1.5
10 (Hours - 40)
Set Pay to
10 Hours
Equivalent
in
behavior
True
Hours
40
False
Add to Pay
5 (Hours - 40)
Output Pay
Output Pay
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
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.
Figure 2.20 More equivalent algorithms
True
True
begin
begin
Input Hours
Input Hours
Hours
> 7 24 or
Hours
<0
False
Hours
60
True
Set Pay to
10 Hours
False
True
True
Set Pay to
10 Hours
Hours
40
False
Set Pay to
10 40 +
15 (Hours - 40)
end
False
Add
5 (Hours - 40)
to Pay
True
Output Pay
Hours
>
40
Equivalent
in
behavior
Set Pay to
10 40 + 15 20
+20 (Hours - 60)
Output "Error"
Hours
> 7 24 or
Hours
<0
False
Hours
>
60
False
Add
5 (Hours - 60)
to Pay
Output "Error"
Output Pay
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.
Note:
Testing
The fourth step of our problem solving method, Testing Strategy Development,
leads us to define the following:
1.
2.
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!).
Figure 2.21 Range of input values for testing
Input
Hours
Data range
Output
Test
Value
Left
Right
Out of Range
H > 168
200
Err
Err
Double Time
60 < H 168
100
1500
1500
40 < H 60
50
550
550
Regular Time
0 H 40
20
200
200
Out of Range
H<0
Err
-20
Err
168
60
Time-and-a-half
40
within
range
Section 2.4
55
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.
2.5
Programming Languages
Communicating Algorithms
The subject of this book is programming, and as you progress, youll write
programs to run on a computer. To do this, youll 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 dont understand all of these examples perfectly, dont 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(Beginners 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.
Figure 2.22 A simple pay program in Basic
The REM keyword
introduces comments.
100
110
120
130
140
150
160
170
180
190
REM
SIMPLE PAY IN BASIC
REM
H IS THE NUMBER OF HOURS
REM
P IS THE GROSS PAY
INPUT H
IF H > 40 THEN 170
LET P = 10 * H
GOTO 180
LET P = 10 * 40 + 15 * (H-40)
PRINT 'GROSS PAY IS ', P
END
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
*
SIMPLE PAY IN FORTRAN 77
INTEGER HOURS, PAY
READ *, HOURS
IF (HOURS .LE. 40) THEN
PAY = 10 * HOURS
ELSE
PAY = 10 * 40 + 15 * (HOURS - 40)
ENDIF
PRINT *, 'Gross pay is ', PAY
END
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 }.
Figure 2.24 A simple pay program in Pascal
PROGRAM SimplePay(INPUT, OUTPUT);
{ Simple pay in Pascal }
VAR
hours, pay: INTEGER;
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 Pascals 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
MODULE SimplePay;
(* Simple pay in Modula-2 *)
FROM InOut IMPORT WriteString, ReadCard, WriteCard;
VAR hours, pay: CARDINAL;
BEGIN
ReadCard(hours);
IF hours <= 40 THEN
pay := 10 * hours;
ELSE
pay := 10 * 40 + 15 * (hours - 40);
END;
WriteSring("Gross Pay is ");
WriteCard(pay, 6);
END SimplePay;
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 */.
Figure 2.26 A simple pay program in C
/* Simple pay in C */
#include <stdio.h>
main()
{
int hours, pay;
scanf("%d", &hours);
if(hours <= 40)
pay = 10 * hours;
else
pay = 10 * 40 + 15 * (hours - 40);
printf("gross pay is %d", pay);
}
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
60
Chapter 2
An Overview
2.6
Code it in
a language
Translate it
assemble, compile
Set up
link, load
Run it
Test it
Use it
Execute
run & monitor
Terminate
Section 2.6
61
Long Life
programming
product
40%
Produce
60%
Use
20%
Planning and
Specifying
8%
30%
Designing and
Developing
12%
Testing and
Evaluating
20%
Operating and
Maintaining
60%
50%
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.
2.
3.
62
Chapter 2
An Overview
Section 2.7
2.7
Review
63
Problem Definition
2.
Solution Design
3.
Solution Refinement
4.
5.
6.
Documentation Completion
7.
Program Maintenance
2.
3.
4.
5.
64
Chapter 2
An Overview
6.
7.
8.
9.
10.
Section 2.8
2.8
Glossary
65
Glossary
Action: An operation performed in an
algorithm or program.
66
Chapter 2
An Overview
Implementation: Practical
realization and installation of an
abstract design.
Run: Execute.
Software: The collection of programs
needed to operate a particular
computer hardware.
Software life cycle: A description of
the various phases of a programs
life.
Section 2.9
2.9
Problems
67
Problems
1.
1
2
Discrete Quantity
Q
8
2
4
6
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.
f.
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
d. When some statements (formulas, etc.) are too long to fit on a line
and continue on to another line, how is this indicated (if at all)?
5.
e.
f.
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.
6.
7.
70
Chapter 2
An Overview
Get Spoon
Get Bowl
Improper
Cereal
Wash Spoon
Pour Cereal
Pour Milk
Add Sugar
Eat
San Diego
Los Angeles
In the state
(California)
San Francisco
Improper
Trip
Portland
Seattle
Out of state
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)
(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.
10.
Dogs Life
An algorithm that relates a dogs age to the corresponding humans age
follows:
A one year old dog is equivalent in age to a 15 year old human. In the
second year, the dog grows 10 human years older, and each year after
that, it grows 5 human years.
a. Create an algorithm as a flow chart to show the human age for any
given dog age.
b. Represent this algorithm as a table, with the dogs age varying
from 1 to 10.
72
Chapter 2
An Overview
c.
11.
Sales Commission
A salesman receives a commission or rate of profit of 4% for sales up to
$300K (where K is $1000); then the rate doubles to 8% only for the sales
at or above this level. Create an algorithm in flowchart form which
describes this profit policy. Provide also a table and graph of profit
versus rate for the rate varying from 0 to 1000K in steps of 100K.
Another profit policy begins at a higher rate of 5% and changes to 7%
for sales over 600K. Create a table of this algorithm and draw it on the
above graph. What is the significance of the intersection of these two
graphs?
12.
Telephone Rates
The rate for use of a telephone depends on the time of call, which is
measured as MPMs or minutes past midnight (ranging from 0 to 60 24).
The day rate from 6am to 6pm is given in dollars per minute, and the
night rate as a proportion of this day rate.
If the rate is determined at the beginning of the call and remains fixed
at that value, create an algorithm that computes the total cost for any
call given the start time and the terminating time, both in MPMs.
If the rate can change during a call (when it lasts past the 6 oclock
times) then create the new algorithm to compute the cost.
Chapter Outline
73
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
3.2
3.3
3.4
3.5
3.6
3.7
3.8
Preview....................................................................74
What Are Algorithms?.............................................75
Algorithm Definition................................................75
General Properties of Algorithms..............................75
Desirable Attributes for Algorithms..........................77
Different Algorithm Representations........................78
Verbal Representations.............................................80
Algebraic Representations (formulas and
expressions).....................................................82
Tabular Representations (tables, arrays, and
matrices).........................................................86
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
Flow of Control Diagrams..........................................107
Flowcharts...............................................................107
Larger Flowcharts Using Subprograms......................110
Flowblocks................................................................113
Pseudocode................................................................115
Review Top Ten Things to Remember........................118
Glossary...................................................................119
Problems...................................................................121
74
Chapter 3
3.1
Preview
Algorithms
Section 3.1
Preview
75
3.2
2.
76
Chapter 3
Algorithms
2.
Turn onto Route 9 and go about three-quarters of a mile and you will come to it on the
left side. You cant miss it!
When your get a set of directions that finishes with You cant 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 Freds. 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 Freds 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
77
78
Chapter 3
3.3
Algorithms
versus
LXIII VII = L V + L + L + X V + X + X + V + I+ I + V +
I+I+V+I+I
= L+L+L+L+L+L+L+X+X+X+X+X+
X+X+V+V+V+I+I+I+I+I+I
= C+C+C+L+L+X+X+X+V+V+I
= C+C+C+C+X+X+X+X+I
= CDXLI
Before we look down on the Romans for their number system, we must remember
that their numerals were not developed for arithmetic. When they came into
existence, almost the only use for numbers was counting and the Roman numerals
I, V and X were very simple to notch on tally sticks. Carpenters to this day still
form these numerals with their axes when they number the beams and timbers
they have fashioned. The other Roman numerals for larger numbers, M, C, D
Section 3.3
79
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, youll find a representation that you prefer, or youll 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.
80
Chapter 3
Algorithms
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.
Figure 3.1
Charge admission
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.
Figure 3.2
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:
1984 was a leap year.
1900 was not a leap year.
2000 will be a leap year.
2100 will not be a leap year.
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
Figure 3.3
81
Dice Game
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:
the sum equals the point count, or
the sum equals 7 and you lose..
For example, consider these sequences:
7
you win
6, 7
you lose
4, 2, 11, 3, 4
you win
9, 3, 4, 12, 2, 8, 3, 7
you lose
Figure 3.4 shows a fourth example, Ideal weight, which describes one view of
the relationship between height and weight.
Figure 3.4
Ideal 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:
A woman 5ft. 10in tall should weigh 100 + 6 x10 = 160lbs.
A man 6ft. 0in. tall should weigh 106 + 7 x 12 = 190lbs.
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 first digit, 0, represents the books 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 books 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
Figure 3.5
A verbal algorithm
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.
Section 3.3
Figure 3.6
83
C = 3 x A + 2 x K where
A is the number of Adults
K is the number of Kids
For example:
For 2 Adults and 3 Kids
C= 3 x A + 2 x K = 3 x 2 + 2 x 3 = $12
Time conversion
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
S is the number of Seconds,
M is the number of Minutes,
H is the number of Hours,
D is the number of Days.
For example:
For 1 day, 2 hours, 3 minutes, 4 seconds
T = 4 + 60 x 3 + 60 x 60 x 2 + 24 x 60 x 60
= 93 784 seconds
84
Chapter 3
Algorithms
Figure 3.8
Temperature Conversion
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 = 212F
5
F = 5 x 20 + 32 = 68F
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.
Figure 3.9
S = N + N + N +. .. + N (N times)
or alternatively
S = 1 + 3 + 5 + 7 +. .. + (2N - 1)
For example, if we denote the Square of 7 as Square(7):
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
For other
methods of
finding the
variance, see
Problem 18 in
Section 3.8 and
see Chapter 8.
85
= (10 + 20 + 30 + 40) / 4 = 25
86
Chapter 3
Algorithms
approximation. The more terms of the series we use for our computation, the
more accurate the approximation we obtain.
Figure 3.12 A Sine formula algorithm
SIN(X) = X X 3 /3! + X5 /5! X7 /7!
For example:
SIN(1)
= 1 - 1/(3 x 2 x 1) + 1 /(5 x 4 x 3 x 2 x 1)
= 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.
Figure 3.13 A Base conversion formula algorithm
Binary to Decimal Conversion
(B n.. .B3 B2 B1 B0 ) 2 = 2nBn + 2n-1Bn-1 +... + 2 2 B2 + 2B1 + B 0
For example:
(110) 2
=4+2+0=6
(1101) 2
= 8 + 4 + 0 + 1 = 13
(1000000) 2
= 26 x 1 = 64
Section 3.3
87
Days in a month
Days in a Month
(1 Index)
Month Days
1
31
2
Leap
3
31
4
30
5
31
6
30
7
31
8
31
9
30
10
31
11
30
12
31
Leap Sub-table
Leap
Year
Feb
Days
NO
28
YES
29
88
Chapter 3
Algorithms
Charge admission
Charge Admission
(2 indices)
Charge Table
in two dimensions
1
1
1
1
2
2
2
2
3
3
3
3
This algorithm is
incomplete: not all
combinations are
shown here.
0
1
2
3
0
1
2
3
0
1
2
3
3
5
7
9
6
8
10
12
9
11
13
15
Charge
Kids
0
11 13 15
Adults
10 12
Majority
Majority
(3 indices)
A
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
0
0
1
0
1
1
1
Majority alternative as
Decision Table
A
? 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
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:
3.4
Data-Flow Diagrams
Black Boxes vs. Glass Boxes
Algorithms can be considered from two points of view, both involving flows:
data flow and control flow. Data flow emphasizes the flow of data between
the actions, while control flow emphasizes the sequence of actions.
In Data-Flow Diagrams (or DFDs), the actions that constitute the algorithms
are represented as black boxes and the lines show data flow between them. The
temporal sequence of actions is not represented. This view is in direct contrast
with flowcharts, which emphasize the sequence of actions. Data-flow
diagrams describe mainly the function of an algorithm: w h a t it does, rather
than h o w it does it.
Figure 3.17 shows this difference with a Divide algorithm that divides a
Numerator by a Denominator and produces a Quotient and a Remainder. The
data-flow diagram is at the left of the figure and provides no indication as to
how the Divide operation is done. This diagram only shows the following
three things:
What the Divide algorithm does,
What Divide takes as input, and
What Divide produces, or outputs.
On the right side of Figure 3.17, a flowchart for the same Divide operation
shows how the division is done, hence the name glass box.
90
Chapter 3
Examples of the
black box view
are shown later
in this section.
Examples of the
glass box view
are shown in
section 3.5, using
three different
representations:
flowcharts,
flowblocks and
pseudocode.
Algorithms
A Black box describes a system that accepts inputs, and produces outputs, while
hiding the internal details of the transformation. This view shows what is
being done by each box and how the boxes interconnect. It provides a higher
level birds 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
things are done within a box. It provides a lower level worms eye view.
This view is represented by flowcharts and flowblocks, with arrowhead lines
showing the flow of control between various boxes.
Figure 3.17 Black box vs. glass box
Flowchart
, or
Glass box
Divide N by D
Set
Q to 0
R to N
Data flow diagram,
or
Black box
N
Black boxes are
opaque: all the
details are hidden.
We can only see
what goes in and
what comes out of
the operation.
RD
False
D
Divide
True
Subtract
D from R
Increase
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
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 subalgorithm 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
92
Chapter 3
Algorithms
Value 1 Value 2
Value 1 Value 2
Result
Result
Addition
Subtraction
Value 1 Value 2
Value 1 Value 2
/
Result
Multiplication
Result
Division
D = A
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
93
32
CONVERT degrees F to C
68 F = 20 C
32
20
(F
32 )
(5
32
9)
9
68
/
-
1.8
/
36
0.5555...
36
+
19.9999...
68
F
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 20C to 68F, and on the right of the same figure, the
conversion of 68F back to 19.9999C! 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.
Figure 3.21 Polynomial data-flow diagram
Y = A + X (B + X
(C + X (D + X
E) ) )
Y=A+B X+C
X2 + D
X3 + E
X4
Section 3.4
95
Add
Z
F
S
Subtract
D
A
Multiply
C
D
Divide
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.
Figure 3.23 Conversion factors
1 decagram
= 10 grams
1 hectogram
= 10 decagrams
1 kilogram
= 10 hectograms
= 100 grams
= 1000 grams
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
G
100
2403 Grams
N
Q
Divide
D
R
3 Grams
24 Hectograms
10
10
N
Q
Divide
2
Kg
4
Hg
Kilograms Hectograms
Divide
D
R
3
0
Dg
Decagrams
G
Grams
Section 3.4
97
Grams
G
2403 Grams
N
Divide
10
D
R
3 Grams
240 Decagrams
N
Q
Divide
24 Hectograms
N
Q
Divide
10
D
R 0 Decagrams
Dg
10
D
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
Grams
G
2403 Grams
N
Divide
Q
Kg
N
Q
Divide
N
Q
100
D
R
4 Hectograms
3 Grams
Dg
2 Kilograms
403 Grams
Hg
1000
Divide
10
D
R
0 Decagrams
3 Grams
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.
Section 3.4
99
A
F
F
T
T
AND
C
B
F
T
F
T
C
F
F
F
T
P
F
F
T
T
OR
R
Q
F
T
F
T
R
F
T
T
T
X
NOT
Y
X
F
T
Y
T
F
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.
Figure 3.28 NOR logical operator
K
L
OR
NOR operator
NOT
M
K
F
F
T
T
L
F
T
F
T
K OR L
F
T
T
T
M
T
F
F
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 DeMorgans Laws. DeMorgans 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 DeMorgans First Law, lets 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
101
OR
NOT
NOT
=
NOT
AND
P
F
F
T
T
Q
F
T
F
T
Left
T
F
F
F
=
=
=
=
Right
T
F
F
F
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.
DeMorgans Second Law is:
NOT(P AND Q) = NOT(P) OR NOT(Q)
This law will be further discussed in Chapter 5.
102
Chapter 3
Algorithms
X
Square
Y
M
Days
D
Y
Max2
M
49
30
1
A
B C
Maj3
M
1
13
50
10
H
R
Gross Pay
G
11
N
D
Divide
Q
R
A B C
Sort3
L M S
550
7
D
Mod
R
Section 3.4
103
X
Square
Y
X
Square
Y
9
16
Add
25
Square
Root
5
H
104
Chapter 3
Algorithms
Integer Divide
C
100
32
DIV
MOD
Subtract
68
25
Divide
Q
18
10
Q Quarters
Divide
Q
8
Dimes
Nickels
Pennies
Divide
Q
1
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).
Figure 3.33 Change Maker as a black box
T
100
32
Change Maker
2
Q
1
D
1
N
3
P
Section 3.4
105
Y
3
Z
5
B
Sort3
M
two ways
Y
3
Z
6
C
S
Add
Sum
14
Min
3
Subtract
11
Divide
11
Divide
5.5
M
5.5
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.
The formula
algorithm for
base conversion
is shown in
Figure 3.13
Decimal to Binary
1
13
8
N
Divide
D
Q
1
Mult
Mult
Mult
4
N
D
Divide
Q
1
2
1
Add
N
R
13
Divide
D
Q
0
1
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
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.
3.5
Charge $3
Sum N values
Output result
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
Increasing
Age < 12
True
(A < B)
and
(B < C)
Color
False
True
False
Selection Form
Average
Repetition Form
Charge
True
Age < 12
False
Sum N values
Divide by N
Loan
True
Charge
$2
Charge
$3
Balance > 0
False
Make Payment
Change Balance
Invocation Forms
Average
Charge
Loan
Section 3.5
109
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 subalgorithm, and they can be invoked whenever needed. The lower part
of Figure 3.38 shows the invocation of the three corresponding subalgorithms 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 dataflow 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
begin
Charge More
Input Age
Divide N by D
Q is Quotient
R is Remainder
True
Age > 21
Loop
initialization
False
Age 21
True
Charge $5
True
Set
Q to 0
R to N
Age < 12
Charge $2
False
Charge $3
RD
False
Loop
Terminating
condition
Subtract
D from R
Increase
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 loops
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.
Larger Flowcharts
Using Subprograms
Section 3.5
111
SUBalgorithm
Days
Input Month
Leap
Input Year
True
Month is
April, June
Sept, Nov
Output
30
False
Month
is Feb
True
True
True
False
False
100
divides
Year
True
Leap
Output
31
This Days
algorithm was
previously seen
in Figures 3.2
and 3.14.
400
divides
Year
Out
29
Out
28
Out
29
False
4
divides
Year
False
Out
28
Days is an algorithm that determines the number of days in any month. It does
this first for all the months except February. Finding the number of days in
February requires determining whether a leap year is involved. Since this is a
fairly complex operation, this part of the Days algorithm is separated from
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.
Lets develop an algorithm to play the simple dice game introduced in Figure
3.3. Here are the rules for this game:
First, two dice are thrown.
If their sum is 7 or 11, you win, and if the sum is 2, 3 or 12, you lose.
Otherwise remember the sum, the point count, and keep throwing until either:
the sum equals the point count (you win), or
the sum equals 7, (you lose)..
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.
Figure 3.41 Dice flowchart
MAIN
algorithm
SUBalgorithm
Dice
Point is
4, 5, 6,
8, 9, 10
begin
begin
More
Throw Sum
Throw Total
True
Sum is
7 or 11
True
Win
Lose
False
Sum is
2,3,12
True
False
Set Point
to Sum
More
(Total 7)
and
(TotalPoint)
False
Throw Total
Total = 7
or
Total = Point
True
Total = 7
Lose
end
False
Win
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
113
Roll Die D1
Throw Sum
Roll Die D2
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.
Figure 3.43 Sequence form in flowcharts and flowblocks
Average
Average
Input N values
Input N values
Sequence
Sum all the values
Divide sum by N
Output result
Invocation
Divide sum by N
114
Chapter 3
Algorithms
Maximum
False
X>Y
Max is X
Selection
X>Y
Max is Y
Max is X
Max is Y
Output Max
Output Max
Section 3.5
115
Divide
Set Q to 0
R to N
True
RD
Set Q to 0
Set R to N
False
Subtract
D from R
Increase Q
Repetition
RD
Decrease R by D
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
Dice Game
Throw Sum
Sum is 7 or 11
T
Flowblock
representation
Sum is 2,
3 or 12
Set Point
to Sum
Win
Lose
More Throws
Throw Total
While (Total 7 ) and (Total Point)
More
Throws
Throw Total
Total = 7
T
Lose
Pseudocode
representation
F
Win
Dice Game
Throw two dice and get Sum
If Sum = 7 or 11
Win
Else
If Sum = 2, 3, or 12
Lose
Else
Set Point to Sum
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
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
T
T
Hours > 60
Hours 40
Output
Error
Message
Set Pay to T
40 Rate +
1.5 20
Set Pay to
Rate + 2
Rate Hours
Rate
(Hours 60)
Set Pay to
40 Rate +
1.5 Rate
(Hours - 40)
Output Pay
Input Hours, Rate
Payroll
Input Hours, Rate
While Hours 0
If Hours > 7 24
Output "Error"
Else
If Hours 60
If Hours 40
Set Pay to
Else
Set Pay to
Else
Set Pay to 40
2
Output Pay
Input Hours, Rate
End Payroll
Hours Rate
40 Rate + 1.5 Rate (Hours 40)
Rate + 1.5 20 Rate +
Rate (Hours 60)
117
118
Chapter 3
3.6
Review
Algorithms
2.
3.
4.
5.
6.
7.
8.
Flowblock forms involve only rectangular boxes, with very limited (but
significant) ways of connecting them. They also describe only the flow
of control of actions.
9.
Data flow forms also involve boxes, but describe the flow of data. This
form is most useful at higher levels when dealing with sub-algorithms.
The flowblocks are also useful for concurrent programming.
10.
Section 3.7
3.7
Glossary
119
Glossary
Action: operation or process.
Algorithm: a plan to perform some
actions on some data.
Array: a collection of memory cells to
store some data.
Assertion: a statement which is
either true or false.
Black box: the representation of
what a process does, the input(s) it
takes and the output(s) it produces,
while hiding the internal details of
the process.
Complete: a property of algorithms
specifying that all actions must be
precisely defined.
Deterministic: a property of
algorithms by which an algorithm
always produces a predictable result.
Pseudocode: a representation of
algorithms based on a mixture of
English and mathematical notation.
120
Chapter 3
Algorithms
Section 3.8
3.8
Problems
121
Problems
1.
b. 1010
c. 101010
and then convert the following decimal numbers to binary (base 2):
d. 7
2.
e. 17
f. 170
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.
4.
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
7.
b. CC
c. F00
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:
10.
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
11.
Charge Tree
For the previous Charge algorithm, with at most 3 adults and 3 kids,
create a representation in the form of a tree. Do this in two ways, first
beginning with adults.
Section 3.8
12.
Problems
123
Simpler Binary
Find the decimal equivalents of these binary numbers:
a. 11111111
b. 100000000
Use the above to find a simple way to obtain the decimal equivalent of
a binary number consisting of any number N of ones in succession.
13.
Binary Octal
Draw a data-flow diagram showing how binary numbers can be
converted to octal numbers by bunching each group of three binary
numbers (from the right or least significant bit) and replacing this by
the octal equivalent. Show it for the decimal value of 299 which is 100
101 011 in binary and 453 in octal.
14.
15.
Expression Trees
Create a tree (data flow) diagram corresponding to the following
expressions, and compare them:
16.
a. (XY) (X + Y)
b. X X Y Y
c. S + 60M + 6060H
d. S + 60 (M + 60H)
e. AB + B4 + C2 + D
f. 2 (2 (2A + B) + C) + D
Leaping Again
Represent the Leap algorithm of Figure 3.40 as a table, with three
conditions (4 divides Y, 100 divides Y, and 400 divides Y) and eight
rules (combinations). Then create another table with fewer rules.
17.
Change Change
Modify the data-flow diagram describing Change Maker in Figure 3.32,
to allow for half-dollars.
18.
Variation On Variance
Another way to compute the variance of N values is to subtract the
square of the averages of the values from the average of the squares of
the values. Compute this for the four values: 10, 20, 30 and 40.
124
Chapter 3
Algorithms
19.
Hot One
Since humans hate division, they often create algorithms to avoid it.
For example, instead of converting temperatures by this formula:
F = 95 C + 32
the following algorithm is sometimes used.
First, multiply C by 2 and subtract from this amount its first (most
significant) digit. Then add 32 to this and the result should be the
Fahrenheit value.
For example, 20C becomes:
40 4 + 32 = 68
Check this algorithm for some numbers and indicate any limitations,
problems or inaccuracies.
20.
Find Algorithms
There are many algorithms guiding everyday things, but we may not be
aware of them. Investigate and determine some similar to the
following. Attempt to express them using different methods (verbal,
tabular, data-flow diagrams, flowblocks, and so on):
a. Sales commission (For the first thousand sold, pay at the rate of ...
)
b. Numbering of state highways (Odd numbers go south to north,
increasing)
c.
d. Library fines for late books (For every day after 5 days ... )
e.
f.
j.
Weight (Men should weight 106 pounds plus 6 pounds for every inch
over 5 feet)
m. Proportional rule of two (Twice around the wrist is once round the
neck)
n. Ideal Athlete (Weight in pounds is twice the height in inches)
Section 3.8
o.
Problems
125
126
Chapter 3
Algorithms
Chapter Outline
127
Chapter Outline
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
Preview....................................................................128
Building Blocks for Structured Programming...............128
The Four Fundamental Forms.....................................128
Connecting Several Forms Sequences and Nests..........131
Deep Nesting............................................................133
Different Algorithms, Same Problem.........................135
Equivalent Algorithms..............................................135
Alternative Algorithms............................................137
Top-down Algorithm Design......................................140
Job Description Example............................................144
Change Maker Example............................................145
A Game Example, Fifty.............................................148
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
Review Top Ten Things to Remember.........................164
Glossary...................................................................166
Problems...................................................................167
128
Chapter 4
4.1
Preview
Algorithm Structure
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.
4.2
Section 4.2
129
Flowchart
Flowblock
Pseudocode
A
B
B
True
False
If C
D
Else
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.
The Repetition form (also referred to as the Iteration or Loop form)
indicates that one or more actions must be repeated a number of times.
As shown in Figure 4.3, this form begins by specifying a condition, G. If
this condition is true, action H, the body of the Repetition form, is
performed and condition G is re-tested. In other words, action H is
repeated until condition G is evaluated as false. At this point, the
130
Chapter 4
Algorithm Structure
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.
Figure 4.3
True
False
While G
H
H
Sub
Sub
Sub
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.
Section 4.2
131
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.
Figure 4.5
T
Output
"Increasing"
Output
"Decreasing"
Output
"Neither"
Compare
If (A < B) and (B < C)
Output "Increasing"
Else
If (A > B) and (B > C)
Output "Decreasing"
Else
Output "Neither"
End Compare
Decreasing
(such as 5, 2, 1 or 3, 0, -4),
Neither
(such as 1, 0, 2 or 1, 1, 1).
This algorithm should not be seen as five boxes (two conditions and three
actions), but should instead be seen as two forms: a Selection nested within a
Selection. Viewing algorithms as forms, rather than as the parts of forms,
reduces the apparent complexity of the algorithm, thus keeping it simple.
In this case (Figure 4.5), the reduction of complexity is from 5 boxes to 2 forms.
Although this may not seem significant, in other cases a reduction from 50 boxes
to 20 forms could prove very helpful.
Extending this algorithm is very easy. The last box (Output Neither) could
be expanded by further nesting to determine whether the values are constant
(such as 7, 7, 7) or non decreasing (such as 2, 2, 3) or undulating (such as 3, 0,
3 or 3, 5, 3). A problem asking you to extend this algorithm can be found at the
end of this chapter.
The Service algorithm, of Figure 4.6, describes a queue or waiting in line. It
illustrates a Repetition form that is nested within a Selection form.
132
Chapter 4
Algorithm Structure
Figure 4.6
Get in line
Not at head
Go away
Wait
Get Served
Service
If Available
Get in line
While not at head of line
Wait
Get served
Else
Go away
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.
Figure 4.7
Raise
Low limit
(to Guess)
Guess
Set Limits High and Low
Try a Guess
While Guess is not correct
F
If Guess is too high
Lower High limit to Guess
Else
Raise Low limit to Guess
Guess the mid of High and Low
Output the Guess
End Guess
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
Figure 4.8
Note:
H > 60
133
H > 7 24
Pay
If Hours > 7 24
Error
Else
If Hours > 60
Double Pay
Else
If Hours > 40
Extra Pay
Else
Regular Pay
End Pay
H > 40
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.
Figure 4.9
F
R
A
D
Q
C
E
If P
A
While Q
B
Else
If R
C
Else
D
E
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.
Figure 4.10 Simpler version of algorithm of Figure 4.9
P
F
R
If P
A
W
Else
If R
C
Else
X
If P
Y
Else
Z
Section 4.2
135
A
A
P
P
T
B
C
B
Q
Q
D
R
E
F
D
4.3
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.
Pseudocode 4.1
Algorithm Leap1
Leap 1
If Year is divisible by 400
Year is a leap year
Else
If Year is divisible by 100
Year is not a leap year
Else
If Year is divisible by 4
Year is a leap year
Else
Year is not a leap year
End Leap 1
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.
Pseudocode 4.2
Algorithm Leap2
Leap 2
If Year is divisible by 4
If Year is divisible by 100
If Year is divisible by 400
Year is a leap year
Else
Year is not a leap year
Else
Year is a leap year
Else
Year is not a leap year
End Leap 2
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
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.
Pseudocode 4.3
Algorithm Leap3
Leap 3
If Year is divisible by 100
If Year is divisible by 400
Year is a leap year
Else
Year is not a leap year
Else
If Year is divisible by 4
Year is a leap year
Else
Year is not a leap year
End Leap 3
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
Right
A
C
Isosceles
Non-triangle
Rightisosceles
Isosceles
Triangle
Section 4.3
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.
Pseudocode 4.4
Triangle Classification 1
Input sidesA, B, C
Sort sides so that A B C
If A + B C
Output "Not a triangle"
Else
If A = C
Output "Equilateral triangle"
Else
If (A= B) OR (B = C)
Output "Isosceles triangle"
If A A + B B = C C
Output "Right triangle"
Else
Output "T r iangle"
End Triangle Classification 1
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
A+BC
A A+BB=C C
T
F
Output
"Right"
(A=B) or (B=C)
T
Output
"Not a triangle"
Output
"Isosceles"
A=C
Output
"Equilateral"
Triangle Classification 2
Input sides A, B, C
Sort sides so A B C
If A + B C
Output "Not a triangle"
Else
If A A + B B = C C
Output "Right"
If (A= B) or (B = C)
Output "Isosceles"
If A = C
Output "Equilateral"
Else
Output "T riangle"
End Triangle Classification 2
Notice the
two different
outputs if
once again,
an equilateral
triangle is
encountered.
Output
"Triangle"
4.4
Explanation
Change
Tire
Example
Compute
Pay
Example
Job
Description
Example
General
View
Computer
Examples
Changemaker
Example
Fifty
Example
Section 4.4
141
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 persons 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 viewa birds-eye viewand 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 detailsthe
worms eye viewand then proceeds to higher levels by combining smaller
blocks. Unfortunately, by concentrating on the details first, without the context
provided by the birds eye view, the building process may quickly become mired
in the details and unmanageable.
Other names for top-down design are: stepwise refinement, iterative multilevel modeling and hierarchical programming. It is often pictured with breakout 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
2. Divide it into 3
smaller actions.
Change Tire
Set-Up
Get
spare
Jack
car up
Exchange Tires
Clean Up
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.
Figure 4.17 The top-down view of Computing Net Pay
Compute
Net Pay
Input hours
Find rate
Calculate
Determine
Deductions
Take taxes
Etc.
The two diagrams shown in Figures 4.16 and 4.17 have been drawn as true topdown diagramsthey 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
143
What
sub-sub-action 3
sub-action 1
4
2
Main
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.
Dont 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 breakout diagram is incomplete!
The next few pages contain different examples of algorithms created using topdown design.
144
Chapter 4
Algorithm Structure
Job
Level 1
All customers
helped
Clean
up
Attend to
Customer
Attend to Customer
Take Order
Level 2
Fill Order
Handle payment
Take Order
Customer accepts
suggestions
Compute total
Inform cost
Handle payment
Fill Order
Greet customer
Receive money
Pick up items
Takeout
Level 3
Make Change
Take
down
Put items
Put items
items
in bag
on tray
Thank customer
Section 4.4
145
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 subalgorithm 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.
146
Chapter 4
Algorithm Structure
Make Change
Make Change
Compute Change
Give Change
End Make Change
Compute Change
Input Cost
Input T endered
Set Remainder to T endered Cost
End Compute 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.
Pseudocode 4.5
Give Change
Give
Give
Give
Give
Quarters
Dimes
Nickels
Pennies
{Remainder = 0}
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
147
Make Change
Input Cost
Input Tendered
Set Remainder to T endered - Cost
{Remainder 0}
While Remainder 25
Output a quarter
Decrease Remainder by 25
{Remainder < 25}
While Remainder 10
Output a dime
Decrease Remainder by 10
{Remainder < 10}
While Remainder 5
Output a nickel
Decrease Remainder by 5
{Remainder < 5}
While Remainder 1
Output a penny
Decrease Remainder by 1
{Remainder = 0}
End Make Change
Give Quarters
Give Dimes
Give Nickels
Give Pennies
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
If Remainder 5
Output a nickel
Decrease Remainder by 5
If Remainder 5
Output a nickel
Decrease Remainder by 5
{Remainder < 5}
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 dollarthis 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.
Section 4.4
149
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.
Figure 4.21 Verbal description of the dice game Fifty
Fifty: a dice game for two people with two dice.
The players each take a turn in one round and the rounds continue as long as neither person's
score has reached 50.
During a player's turn, the two dice are thrown once. There is no change in score unless two
identical numbers come up.
If both dice are sixes, then 25 points are added to that player's score.
If both dice are threes, then that player's score is reset to zero.
If any other doubles are thrown, five points are scored.
The winner is the one whose score after a round is at least 50 and the higher of the two scores.
A tie is also possible.
Fifty
Set up
Play
Evaluate
End Fifty
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.
Pseudocode 4.9
Fifty
Set Score1 to 0
Set Score2 to 0
While (Score1 < 50) and (Score2 < 50)
Turn of Player 1
Turn of Player 2
IF Score1 = Score2
The game is a T ie
Else
No-T ie
Set Up
Play
Evaluate
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 subalgorithm.
Then, a Selection determines whether there are any Doubles. For
example, if the scores DiceA and DiceB are equal, another subalgorithm determines whether they are a Good Double or not.
At this level, the sub-algorithm Turn of Player is shown in Pseudocode 4.10.
Pseudocode 4.10
Turn of Player
Throw to get DiceAand DiceB
If DiceA = DiceB
Doubles
End Turn of Player
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.
Pseudocode 4.11
Turn of Player
Throw to get DiceAand DiceB
If DiceA = DiceB
If DiceA= 3
Set Player's Score to 0
Else
Good Double
End Turn of Player
Doubles
Section 4.4
151
Doubles
Good Double
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.
Pseudocode 4.13
Evaluate
If Score1 = Score2
The game is a T ie
Else
If Score1 > Score2
Player 1 wins
Else
Player 2 wins
End Evaluate
No-Tie
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.
Pseudocode 4.14
Fifty
Set Score1 to 0
Set Score2 to 0
While (Score1 50) and (Score2 50)
T urn of Player 1
T urn of Player 2
IF Score1 = Score2
The game is a T ie
Else
If Score1 > Score2
Player 1 wins
Else
Player 2 wins
End Fifty
152
Chapter 4
Algorithm Structure
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.
4.5
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
153
2
3
4
hearts
spades
10
Jack
Queen
King
char 1
char 2
char j
char 70
Char
0
bit 0
bit 1
bit 2
bit 3
bit 4
bit 5
bit 6
bit 7
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
Month
Feb
day 1
Mar
Day
day 2
28 - 31
Dec
hour 1
2
24
hour 24
Organization
Initial
person 1
Last
person 2
person 3
Person
name
person k
address
attributes
person n
street
city/state
Number
Name
country
code
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
155
:
:
:
John
M
Motil
:
:
:
:
123-45-6789
:
:
:
2000
Feb
29
156
Chapter 4
Algorithm Structure
Ingredients
Secret Sauce
Place all ingredients in large bowl
Mix thoroughly
End Secret Sauce
3 pounds beef
2 pounds beans
2 teaspoons salt
1 cup Secret Sauce
Chili recipe
Wash beans
Add 2 quarts water
Soak overnight
Add salt
While not tender
Simmer
2 pounds of tomatoes
2 teaspoons salt
_1 teaspoon paprika
4
_1 teaspoon cayenne
8
6 whole cloves
2 bay leaves
2 tablespoons chili powder
{finished simmering}
Section 4.5
157
beans
water
Secret Sauce
salt
wash
mix
soaked
beans
soak
add
tenderize
brown
drain
combine
water
simmer
add
Chili
There is a huge difference between the representations (pseudocode and dataflow diagram) used in Figures 4.26 and 4.27. As we have already mentioned in
Chapter 3, pseudocode describes flow of control (the sequence of actions in time),
whereas the data-flow diagram describes the flow of data without concerning
itself with actions. Pseudocode will show repetitions and selections since its
emphasis is on actions; in a data-flow diagram, repetitions and selections of
actions have no meaning.
Assertions can be made in the two algorithm representations. We have seen
that assertions were comments that indicate the situation at any given point of
an algorithm. In pseudocode, between any two statements, we can make an
assertion about the state of the operation of the algorithm. Similarly, in a
data-flow diagram, we can put an assertion with any line joining two boxes.
The assertion in the pseudocode of Figure 4.26 is shown in braces, while the
assertion in Figure 4.28 is shown in a dotted box. Notice the difference between
what is being asserted in each case:
In the pseudocode, which is action oriented, the assertion is finished
simmering, which makes a statement about the progress of the action
in relation to time.
In contrast, the assertion in the data-flow diagram, soaked beans,
makes a statement about the state of the data.
This does not mean that we cannot use the data flow assertions in the
pseudocode, as they give indications on the data that could be the results of an
action. The opposite is also true for we could probably use most pseudocode
assertions in data-flow diagram. However, in practice, the two representations
use more specialized assertions that are action-oriented or dataoriented.
158
Chapter 4
Algorithm Structure
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.
Now, lets look at an algorithm that uses structured data. This example
involves a card trick.
21 playing cards are placed face-up in 7 rows and 3 columns, as shown in Figure
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.
Figure 4.29 Arrangement of cards for Card Trick
8
Q
510
7J
4
10
26
3
K
4
2
89
J
5
A
K
A
3 columns of 7 rows
Once the cards have been arranged in this manner, perform the following steps:
1.
2.
Without pointing at the card, have the person indicate the column that
contains the selected card.
3.
4.
Deal out the cards in its familiar 7 rows by 3 column structure, row by
row!
5.
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
Pseudocode 4.15
159
Card Trick
Arrange 21 cards face up row by row in 3 columns and 7 rows
Have someone secretly choose a card and indicate the column of
the chosen card
Repeat 2 times
Pick up the cards column by column, with the indicated column
placed in the middle
Place the cards on the table again, row by row in
3 columns and 7 rows
Have the person indicate the column containing the chosen card
Pick up the cards in "sandwich" order as before
Count off ten cards
Show the eleventh card: it is the chosen card
End Card Trick
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).
Figure 4.30 Using the Decimal to Binary algorithm to convert
N=13
N =
13 6 3 1 0
13
2
6
2
3
1
1
2
160
Chapter 4
Algorithm Structure
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:
31
Number
Count
50
Guess
Challenger
Select a Number
Set Count to 1
Request and Get a Guess
While Guess Number
If Guess is high
Output "High"
Else
Output "Low"
Increment Count
Request and Get a Guess
Output "Congratulations"
Output Count
End Challenger
The algorithm Guesser, Figure 4.32, describes one systematic way of making
guesses, and could be followed by the player trying to guess the Challengers
Section 4.5
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).
Figure 4.32 Guesser sample data and algorithm
100
High
Low
50
Try
Guesser
Set High to 100
Set Low to 0
Set Try to (High + Low) / 2
Output T ry
While T ry is not correct
If T ry is high
Set High to T ry
Else
Set Low to T ry
Set T ry to (High + Low) / 2
Output T ry
End Guesser
162
Chapter 4
Algorithm Structure
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.
32.
Guesser Trace
Number = 31
Count = 1
High = 100
Low = 0
Try = (High + Low)/2 = 50
Guess = 50
Guess Number
"High"
Count = 2
Try is not correct
Try is high
High = 50
Try = (50 + 0)/2 = 25
Guess = 25
Guess Number
"Low"
Count = 3
Try
Try
Low
Try
is not correct
is low
= 25
= (50 + 25)/2 = 37
Guess = 37
Guess Number
"High"
Count = 4
Try is not correct
Try is high
High = 37
Try = (37 + 25)/2 = 31
Guess = 31
"Congratulations"
"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
4.6
163
2.
3.
4.
5.
6.
7.
Alternative Algorithms are algorithms which act the same, but do not
produce the same output for all possible cases. Alternative algorithms
are similar in behavior and may be structured differently.
8.
164
Chapter 4
Algorithm Structure
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.
Section 4.7
4.7
Glossary
165
Glossary
Abstraction: A method of conceptual
simplification through the
suppression of details that are
irrelevant to the application of the
abstraction.
Action: some small process applied to
some data.
Array: A data organization by rows
and columns.
Assertion: A statement that is either
true or false.
Binary search: A search algorithm
that repeatedly halves the area of
search until it is reduced to one
element, the object of the search or it
is found that the item is not present in
the data being searched.
Bisection search: Synonym for Binary
search.
Data: Something given or measured.
Data Structure: Organization of data
elements grouped for a given purpose.
Divide and Conquer: A method to
break the complexity by considering
small parts of a problem.
Four Fundamental Forms: The
Sequence, Selection, Repetition and
Invocation forms; each of which has
a single entry point and a single exit
point. These four forms together are
sufficient to build all programs.
Hierarchical programming: Synonym
for top-down design.
Invocation: Use of a sub-algorithm.
One of the Four Fundamental Forms.
Method: Orderly procedure.
166
Chapter 4
4.8
Problems
Algorithm Structure
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
M=0
True
False
M = 30
True
False
0 < M < 30
False
Section 4.8
3.
Problems
167
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
True
C=5
Input C
True
C=5
Input C
False
True
C=5
Output
Item
False
Output
Change
False
Output
Item
Output
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.
7.
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
11.
Problems
169
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.
12.
Start a car.
2.
3.
4.
5.
Operate a combination
lock.
6.
7.
8.
Balance checkbook.
9.
13.
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
14.
Rotation Dice
The game of Rotation is played with two dice and two people. The
players each take a turn for a round. There are 11 rounds in a game, one
for each of the combinations: 2, 3, 4, up to 12. During the first round, the
goal is to throw a 2, during the second round it is to throw a 3 and so
on up to 12. Each time a player is successful, that number of points is
added to that players score; otherwise nothing is added. The winner is
the player with the higher score after the 11 rounds.
15.
Pig Dice
The game of Pig is played with one die and two people. The players
each take a turn during a round and the rounds continue while all scores
are less than 100. During a players turn, the die is repeatedly thrown
and the score accumulated until either a 1 comes up or the player
chooses to stop. If the 1 comes up, the sum is lost; otherwise, it is added
to the players score. The winner is the one whose score is the highest
at the end of the game.
16.
Dice Climb
Create an algorithm describing the following game involving two
players and one die. The players try to roll a 1, then a 2, a 3 and so on,
up to 6, in that order, but not necessarily one number immediately
following the other. First, they roll a die to determine who goes first
(the highest). Then, they alternate turns, stopping as soon as one
player (the winner) reaches the value 6. During each turn, a player
rolls the die once and keeps rolling only if the desired numbers are
obtained.
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.
18.
Archery Scram
Create an algorithm describing the following game of skill involving
two players shooting arrows at a target. The target consists of nested
circles labeled with values from 1 to 6; value 1 is farthest out and value
6 is in the center, or Bulls eye.
Section 4.8
Problems
171
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 players 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
5.2
Preview....................................................................176
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
5.1
Preview
Algorithm Behavior
5.2
Programs
Data for Programs
The algorithms considered until now have been quite general, involving data
that are as diverse as people, dice, cards, resistors, pebbles, triangles, recipes
and money.
Section 5.2
Programs
177
Variable (Box)
Type
(kind of box)
21
Age
Value
(content)
Identifier
(label)
178
Chapter 5
Algorithm Behavior
Figure 5.2
21
-500
Count
0205080057
ISBN
1984
Year
Could also be
represented as
9.11E-30.
0.00000000000000000000000000000911
Pi
Quantity
Rate
MassOfElectron
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).
Figure 5.4
'+'
Function
'A'
grade
'J'
Initial
'.'
Period
Section 5.2
Programs
179
There are also other data types such as the Logical type (also called Boolean
type) that comes from decision-making, which comprises only two values, True
and False. Logical expressions are usually found as conditions in either the
Selection or Repetition Forms.
Figure 5.5
Logical
String
False
Tall
Story
Other data types often used include the String type, consisting of a sequence of
characters, as shown in Figure 5.5.
Figure 5.6
An array of 21 cards
3 columns of 7 rows
10
26
3
K
4
2
8
Q
510
7J
4
8
9
J
5
A
K
A
Name
FirstName
Initial
LastName
Address
Street
City
Country
Code
Attributes
IdNumber
Birth
Year
Month
Day
:
:
:
John
M
Motil
:
:
:
:
123-45-6789
:
:
:
2001
Feb
29
Actions In Programs
The kind of operations or actions that can be performed on data depends on the
type of the data, and this is why the operations are an implicit part of a data
type. For example, the logical operators AND, OR, and NOT only apply to
Logical type valuesthey cannot apply to Real Numbers, Integers, or
Characters. On the other hand, Real Numbers and Integers may be added,
subtracted, multiplied and divided, yielding results of the same type. Such
arithmetic operations cannot act on variables of Logical or Character types
dividing two characters would be meaningless.
One of the most important operations in a program is the assignment, which
operates on a l l data types. The assignment is the process of giving a value to a
180
Chapter 5
Algorithm Behavior
variable, the act of putting some content into a box. The assignment operation is
represented by the phrase Set Variable to Value, as in the following
assignment:
Set X to 3
or alternately,
X
This puts the value 3 into the variable box labeled X. If box X contained a
value before this assignment, the old value is replaced by the new value 3. A
more general assignment notation involves two variables as illustrated in
Figure 5.7.
Figure 5.7
An Assignment example
Before
Action:
X =
Y =
X =
Y =
Set Y to X
After
Before Count = 3
Action:
Count =
The increment operation of Figure 5.8 shows how the value of variable Count is
increased by a constant. This action is often used to increment a counter and it
Section 5.2
Programs
181
Accumulating a Total
Before Total = 8
Action: Set
Value =
Value =
= 10
5.3
Sequence Forms
The simplest computer algorithms involve a sequence of actions executed one
after the other, and the simplest Sequence programs involve actions that are
all similar.
Lets take an example and suppose that the four variables North, South, East
and West represent four traffic densities: the number of cars that travel North,
South, East or West through some intersection in one minute.
Lets design an algorithm to compute the average traffic density, Mean, of the
four values North, South, East, and West. This Mean value is a measure of the
activity of the intersection that will be computed and printed out every minute
to show how the traffic density through the intersection changes with time.
182
Chapter 5
Algorithm Behavior
The value of Mean is obtained by summing the four values and dividing their
sum by 4.
The Average algorithm, which computes this Mean, is shown at left of Figure
5.10 with a trace of its execution at the right. Suppose that the values of
North, South, East and West were 20, 10, 40, and 30 respectively. First,
variable Sum is set to zero. Then, the value in North is added to it, replacing
the zero in Sum by 20. At the third step, the value of South is added into Sum
bringing it to 30. Similarly in step 4, the value of East is accumulated bringing
Sum to 70 and finally the value of West is added, ultimately yielding a Sum
of 100. Finally, at step 6, this value of 100 is divided by 4 to yield the value of
Mean, 25.
Figure 5.10 The Average algorithm
Average
Set Sum to 0
Set Sum to Sum + North
Set Sum to Sum + South
Set Sum to Sum + East
Set Sum to Sum + West
Set Mean to Sum / 4
End Average
Step
1
2
3
4
5
6
West
30
30
30
30
30
30
unchanged values
Actions
Algorithm Structure
North
20
South
10
East
40
West
30
4
5
Sum
Mean
Set
Set
Set
Set
Set
Set
Sum to 0
Sum to Sum + North
Sum to Sum + South
Sum to Sum + East
Sum to Sum + West
Mean to Sum / 4
Section 5.3
Sequence Forms
183
Figure 5.11 shows two kinds of structures. On the left of the figure, the data
structure comprises six variables or boxes, and on the right side of the figure the
algorithm structure consists of six actions. To average 50 numbers with this
method would require 52 data boxes (one for Sum, one for Mean, and one for each
data item), and also 52 actions (one for initializing Sum, one for each
accumulation, and one for dividing). For large amounts of data, this sequential
method is long and tedious. Later, we will find a better way to accomplish this
using the Repetition form. For a few numbers though, this Sequence form of
averaging is acceptable.
Although the Sequence Form in Figure 5.16 is correct, our simple traffic average
could also be computed by using a single action:
Set Mean to (North + South + East + West)/4
The simple Average program of Figure 5.11 can be generalized by replacing the
constant value of 4 by a variable Count. This variable can be set to the actual
number of values to average and used in the division. We will see more on this
in Chapter 6.
Sales
Input ItemPrice
Input Quantity
Set SalePrice to ItemPrice Quantity
Set TaxRate to 0.065
Set TaxPaid to TaxRate SalePrice
Set FullPrice to SalePrice + TaxPaid
Output FullPrice
End Sales
184
Chapter 5
Algorithm Behavior
Variable1 =
Variable2 =
Temporary =
Swap
Set Temporary to Variable1
After Swap
Variable1 =
Variable2 =
Temporary =
The Swap algorithm swaps the values of Variable1 and Variable2 using
following three steps:
5.4
1.
2.
3.
Selection Forms
Simple Selection Forms
Our first example to illustrate Selection Forms will be based on finding an
absolute value. The absolute value of a number (positive or negative) is the
positive value of the number without its sign. A flowblock diagram of an
algorithm, which produces the absolute value of a variable X and puts it into
the variable Absolute, is shown at the left of Figure 5.13. Its corresponding
pseudocode is given at the right of the same figure.
Figure 5.13 The Absolute Value algorithm
Set Y to X
T
X<0
Set Y to -X
Set Absolute to X
If X < 0
Set Absolute to (0 X)
Section 5.4
Selection Forms
185
If the value is negative, it is subtracted from 0 and the positive result assigned
to Absolute. If the value is positive, it is left untouched. Alternatively, the
algorithm could have multiplied any negative value by -1, again resulting in a
positive value. Since multiplication on a computer is more complex and slower
than subtraction, we will use the algorithm that uses subtraction.
Note that instead of subtracting X from 0 for negative numbers, we could have
simply written Set Absolute to -X where the minus operator is put in front of
the X.
The next examples that illustrate Selection Forms show two Maximum
algorithms at the left and right sides of Figure 5.14. They show two different
ways of finding the maximum value of two variables, X and Y.
Figure 5.14 Maximum value
Proof of equivalence
condition
Maximum1
If X > Y
Set Max1 to X
Else
Set Max1 to Y
End Maximum1
input
X
Y
output
Max1 Max2
X < Y
= 1
X = Y
= 2
X > Y
3 = 3
Maximum2
Set Max2 to Y
If X > Y
Set Max2 to X
End Maximum2
Equivalent
See Chapter 3,
Figure 3.44 for a
previous version
of Maximum1.
To get a better
understanding
of what
equivalence is,
see Chapter 4,
Section 4.3.
186
Chapter 5
Algorithm Behavior
Lets extend somewhat the Maximum algorithms we have just considered, into
the three Big-Small algorithms, shown in Pseudocode 5.2. These will return
two results: the maximum value Big, and the smallest value Small, of the two
values X and Y.
Pseudocode 5.2
BigSmall1
If X > Y
Set Big to X
Set Small to Y
Else
Set Big to Y
Set Small to X
End BigSmall1
BigSmall3
Set Big to Y
Set Small to X
If Small > Big
Swap Big, Small
End BigSmall3
Section 5.4
Selection Forms
187
If old
Aged
Else
Child
If male
Boy
Actions
Right
Left
= Child
Child
Child,Boy = Child,Boy
Aged
= Aged
Aged
= Aged
If old
Aged
Else
Child
If young male
Boy
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.
Figure 5.16 Nested versus sequentially connected Selections
Conditions
Value
Age<12 Age>21 Age
If Age < 12
Increment Low
Else
If Age > 21
Increment High
Actions
Left
Right
18
none
none
25
High
High
10
Low
Low
??
???
???
Equivalent
If Age < 12
Increment Low
If Age > 21
Increment High
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!).
Figure 5.17 Another proof involving Selections
Conditions
Cond1 Cond2
If Cond1
Action1
Else
If Cond2
Action2
Actions
Left
Right
none
none
Action1
Action1
Action2
Action2
Action1
Action1,Action2
If Cond1
Action1
If Cond2
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.
Section 5.4
Selection Forms
189
True and False, or Yes and No. Lets 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.
Figure 5.18 Specification of Majority Voting
We first
encountered this
algorithm in
Chapter 3,
Figure 3.16
In the above table, the combination of values (1, 0, 1) corresponds to the third
line from the bottom of this table, which has an index number of 5. There are at
least six possible algorithms that can produce the results specified by the
table. These algorithms are shown below in Pseudocode 5.3 through 5.8,
Majority Method 1 through Majority Method 6.
Pseudocode 5.3
Majority Method 1
If A = O
If B = 0
If C = 0
Set Majority
Else
Set Majority
Else
If C = 0
Set Majority
Else
Set Majority
Else
If B = 0
If C = 0
Set Majority
Else
Set Majority
Else
If C = 0
Set Majority
Else
Set Majority
End Majority Method 1
to 0
{Combination 0}
to 0
{Combination 1}
to 0
{Combination 2}
to 1
{Combination 3}
to 0
{Combination 4}
to 1
{Combination 5}
to 1
{Combination 6}
to 1
{Combination 7}
190
Chapter 5
Algorithm Behavior
Majority Method 2
Set Sum to 0
If A = 1
Set Sum to Sum + 1
If B = 1
Set Sum to Sum + 1
If C = 1
Set Sum to Sum + 1
If Sum 2
Set Majority to 1
Else
Set Majority to 0
End Majority Method 2
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.
Pseudocode 5.5
Majority Method 3
If (A + B + C) 2
Set Majority to 1
Else
Set Majority to 0
End Majority Method 3
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
Pseudocode 5.6
Selection Forms
191
Majority Method 4
If A < B
If A < C
Set Majority to 1
Else
Set Majority to 0
Else
If B < C
Set Majority to A
Else
Set Majority to B
End Majority Method 4
{Combination 3}
(Combination 2}
{Combination 1, 5}
{Combination 0, 4, 6, 7}
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.
Pseudocode 5.7
Majority Method 5
If A = B
Set Majority to A
Else
If B = C
Set Majority to B
Else
Set Majority to C
End Majority Method 5
{C = A}
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.
Pseudocode 5.8
Majority Method 6
If A = B
Set Majority to A
Else
Set Majority to C
End Majority Method 6
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.
It is interesting to notice the different conditions in each of the six methods.
Some methods (1 and 2) compare a variable to a constant.
192
Chapter 5
Algorithm Behavior
If A < B
Set Majority to C
Else
If B < C
Set Majority to A
Else
Set Majority to B
Left Right
Majority
0 = 0
0 = 0
0 = 0
1 = 1
0 = 0
1 = 1
1 = 0
1 = 1
If A > B
If C > B
Set Majority to 1
Else
Set Majority to 0
Else
If C > B
Set Majority to 0
Else
Set Majority to C
Section 5.4
Selection Forms
193
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 Two ways of finding the maximum of three values
If X < Y
If Y < Z
Set Max
Else
Set Max
Else
If X < Z
Set Max
Else
Set Max
Condition
( X, Y, Z )
Left Right
Max Max
to Z
X < Y < Z
Z = Z
to Y
X < Z < Y
Y = Y
to Z
to X
Y < X < Z
Z = Z
Y < Z < X
X = X
Z < X < Y
Y = Y
Z < Y < X
X = X
Set Max to X
If Max < Y
Set Max to Y
If Max < Z
Set Max to Z
Figure 5.20 shows two algorithms for computing the Maximum of three values
X, Y, and Z. Lets 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 valuesan
infinite numberto 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
Condition
(X, Y, Z)
Lift
Max
1
1
2
3
2
3
2
3
1
1
3
2
3
2
3
2
1
1
X<Y<Z
X<Z<Y
Y<X<Z
Y<Z<X
Z<X<Y
Z<Y<X
3
3
3
3
3
3
Right
Max
=
=
=
=
=
=
3
3
3
3
3
3
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. Lets look
closer to more examples of nested Selections in order to understand them better
and to see if its 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:
A score of 90 to 100 gets a grade of A
A score of 80 to 89 gets a grade of B
A score of 60 to 79 gets a grade of C
A score of 50 to 59 gets a grade of D
A score of less than 50 gets a grade of F
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
Pseudocode 5.9
Selection Forms
195
Grades 1
Input Percent
If Percent 90
Output "A"
Else
If Percent 80
Output "B"
Else
If Percent 60
Output "C"
Else
If Percent 50
Output "D"
Else
Output "F"
End Grades 1
Grades 2
Input Percent
If Percent < 50
Output "F"
Else
If Percent < 60
Output "D"
Else
If Percent < 80
Output "C"
Else
If Percent < 90
Output "B"
Else
Output "A"
End Grades 2
196
Chapter 5
Algorithm Behavior
Pseudocode 5.11
Grades 3
Input Percent
Set TestValue to Percent 50
If TestValue < 0
Output "F"
Else
Set TestValue to TestValue 10
If TestValue < 0
Output "D"
Else
Set TestValue to TestValue 20
If TestValue < 0
Output "C"
Else
Set TestValue to TestValue 30
If TestValue < 0
Output "B"
Else
Output "A"
End Grades 3
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.
Pseudocode 5.12
Grades 4
Input Percent
Set Grade to "A"
If Percent < 90
Set Grade to "B"
If Percent < 80
Set Grade to "C"
If Percent < 60
Set Grade to "D"
If Percent < 50
Set Grade to "F"
Output Grade
End Grades 4
The four methods given here are not all the possible methods for the Grades
algorithms; at least two other different structures are also possible.
For more details
on the problem
solving method,
see Chapter 2,
Section 2.2.
Whenever we define an algorithm, we should test it. This is in fact step 4 and
part of step 5 of our problem solving method. Testing algorithms is extremely
important as errors can creep up even in simple algorithms like our Grades
algorithms, and in fact, there is an error in one of them.
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.
Note:
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
information on
Logical
conditions, see
Logical DataFlow Diagrams in
Section 3.4. De
Morgans First
and Second
Laws are also
mentioned
there.
The conditions we have used in our Selections are usually called Logical
conditions because they can only be true or false. The conditions we have used so
far were simple, but we can define more complex conditions by using the three
main connectives AND, OR and NOT, which we already encountered in
Chapter 3, Figures 3.27 and 3.29. Their behavior is specified by the truth
tables of Figure 5.21.
Figure 5.21 Truth tables
Conjunction
Disjunction
Negation
AND
OR
NOT
F
F
F
T
F
F
If Condition1
If Condition2
Set Cond to True
Else
Set Cond to False
Else
Set Cond to False
Section 5.4
Selection Forms
199
NOT
NOT
AND
OR
NOT
DeMorgans 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):
(Total7) AND (TotalPoint)
The assertion after leaving the loop was just the opposite:
(Total=7) OR (Total=Point)
This results directly from DeMorgans 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
F
T
T
T
F
T
NOT P
NOT Q
NOT P
AND
NOT Q
P OR Q
NOT
(P OR Q)
T
T
F
F
T
F
T
F
T
F
F
F
F
T
T
T
T
F
F
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 DeMorgans 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.
Figure 5.25 Truth table for distributive law
3 logical variables
A B C
8 possible combinations
F
F
F
F
T
T
T
T
F
F
T
T
F
F
T
T
F
T
F
T
F
T
F
T
Left Right
F
F
F
F
F
T
T
T
=
=
=
=
=
=
=
=
F
F
F
F
F
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
Leap 1
If Y is divisible by 400
Y is a leap year
Else
If Y is divisible by 100
Y is not a leap year
Else
If Y is divisible by 4
Y is a leap year
Else
Y is not a leap year
End Leap 1
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))
Pseudocode 5.15
Leap 2
If Y is divisible by 4
If Y is divisible by 100
If Y is divisible by 400
Y is a leap year
Else
Y is not a leap year
Else
Y is a leap year
Else
Y is not a leap year
End Leap 2
Possible paths
for a leap year
202
Chapter 5
Algorithm Behavior
Leap 3
If Y is divisible by 100
If Y is divisible by 400
Y is a leap year
Else
Y is not a leap year
Else
If Y is divisible by 4
Y is a leap year
Else
Y is not a leap year
End Leap 3
Possible paths
for a leap year
Leap1
If (Y D 400) OR (NOT(Y D 100) AND (Y D 4))
Y is a leap year
Simplification: now only one
possible path
Else
for a leap year
Y is not a leap year
End Leap1
Section 5.5
5.5
Repetition Foms
203
Repetition Forms
The Repeat-Until Form
Since computers are extremely good at repetitive tasks, algorithms based on
Repetition Forms are important in computing. Repetition Forms in algorithms
are very often called loops, as we loop through the algorithm while
executing it. Note that a loop is more visible on a flowchart because an arrow
has to loop back to an upper part of the diagram (look back at Section 3.5 of
Chapter 3 as well as at Figure 4.3 of Chapter 4)
Although there exist several forms for the loops, thus far we have used only
the While form of the loop. In this form, a test of the condition is made and, if
the condition is met, the body of the loop is executed. This process is repeated
until the condition is found to be False when tested.
An alternative loop form, the Repeat-Until form first executes the body of the
loop and then continues repeatingiterating until the condition on which it
is based is found to be True when tested. Figure 5.26 shows a comparison
between the flowcharts of these two looping forms.
Figure 5.26 Comparison of flowcharts for While and Repeat-Until
loop forms
While Loop
True
The body of the
loop may never
be executed, not
even once.
Repeat-Until Loop
False
B
True
False
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
Pseudocode 5.18
Repeat
B
Until Cond
is exactly equivalent to
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.
Figure 5.27 Structure and trace of the Modulus algorithm
Structure
Modulus
Input Num
Input Den
Set Rem to Num
While Rem Den
Set Rem to Rem - Den
Trace
Num = 14
Div = 4
Rem = 14
14 4 is True
10 4 is True
6 4 is True
Rem = 10
Rem = 6
Rem = 2
Output Rem
End Modulus
2 4 is False
Output 2
Iteration 1
Iteration 2
Iteration 3
Section 5.5
Repetition Foms
205
We will refine our traces to more convenient two-dimensional trace tables that
will prove to be extremely useful.
Figure 5.28 Trace of the Divide algorithm
Structure
Divide
Input Num
Input Den
Set Rem to Num
Set Quot to 0
While Rem Den loop
Trace
Num = 14
Div = 4
Rem = 14
Quot = 0
14 4
10 4
T
64
T
24
F
T
Rem = 10
Rem = 6
Rem = 2
Rem = 2
Quot = 1
Quot = 2
Quot = 3
Quot = 3
Output Quot
Output Rem
End Divide
Output 3
Output 2
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.
206
Chapter 5
Algorithm Behavior
An erroneous algorithm
Product A
Set Product to 0
Repeat
Add X to Product
Decrement Y
Until Y = 0
End Product A
infinite loop
Problem: if Y is initially 0, we
get an infinite loop.
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, lets 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.
Pseudocode 5.20
An erroneous algorithm
Product B
Set Product to 0
Repeat
Add X to Product
Decrement Y
Until Y 0
End Product B
incorrect product
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!
Pseudocode 5.21
An erroneous algorithm
Product C
Set Product to 0
If Y 0
Repeat
Add X to Product
Decrement Y
Until Y 0
End Product C
Y value destroyed
Section 5.5
Repetition Foms
207
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
Product D
Product D
Set Product to 0
Set Count to Y
If Count 0
Repeat
Add X to Product
Decrement Count
Until Count 0
End Product D
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 kludge1something 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.
208
Chapter 5
Algorithm Behavior
Add D to P
Add D to P
Better Product
Set Multiplier to Y
Set Multiplicand to X
Set Product to 0
While Multiplier > 0
Set Product to Product + Multiplicand
Set Multiplier to Multiplier 1
End Better Product
If X < Y
Set Multiplier to X
Set Multiplicand to Y
Else
Set Multiplier to Y
Set Multiplicand to X
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 executeessentially 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.
Section 5.5
Repetition Foms
209
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.
Figure 5.30 Top-down development of loan program
Set up
Set up Amount,
Payment,
Duration,
Rate, Balance,
Time
Loop
Loan
Output
End Loan
Compute Interest
NewBalance
Increment Time
Output Balance
Input Amount
Input Duration
Input Payment
Input Rate
Set Balance to Amount
Set Time to 0
Set Interest to Rate Balance
Chop Interest
Set Balance to Balance +
Interest Payment
Set Time to Time + 1
210
Chapter 5
Algorithm Behavior
Amount
Duration
Payment
Rate
Amount = 6000
Duration = 6
Payment = 1000
Rate = 0.10
Balance = 6000
Time = 0
0<6
T
1<6
T
2<6
T
3<6
T
4<6
T
5<6
T
Interest = 600
560
516
467
414
355
Balance = 5600
5160
4676
4143
3557
2912
Time = 1
2912
5600
1
5160
2
6<6
F
4676
3
4143
4
3557
5
Balance = 2912
Time = 6
final
state
(after)
Section 5.5
Repetition Foms
211
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.
Getting Insights
The trace of an algorithm can yield many insights. Oftentimes, a study of such
a trace will show an error in an algorithm. When no errors are detected, the
trace might suggest improvements or even spark an idea for an alternative
algorithm. Traces also might show useful relationships among variables. We
will illustrate these concepts throughout the rest of this chapter with a number
of examples.
The Odd Square
algorithm was
introduced in
Chapter 3,
Figure 3.9.
Our first example, the Odd Square algorithm, shown in Figure 5.33, finds the
square of any integer Num by summing the first Num odd integers. The
algorithm has three parts
Initialization: The starting values are assigned to the variables.
Loop: The value of the square is calculated by summing a sequence of
odd numbers.
Output: The calculated value of the square is output.
212
Chapter 5
Algorithm Behavior
Square =
Count =
OddNum =
Input Num
Set Square to 0
Initialize
Set Count to 1
Set OddNum to 1
16 26 36 46 56 66 76
T
T
T
T
T
T
F
Loop
Square =
16
25
36
OddNum =
11
13
Count =
Increment Count
Output
Output
36
Output Square
at every
stage
between any
two iterations
Horizontal View
Square =
OddNum =
Count =
Vertical View
+
16
Square = (Count - 1) 2
OddNum = OddNum + 2
OddNum = 2 CountNum - 1
Count = Count + 1
Section 5.5
Repetition Foms
213
16
25
36
OddNum =
11
13
Count =
Vertical views consider each stage separately and show all the variables at
each iteration, as shown in Figure 5.35.
Figure 5.35 Some vertical slices
One slice per stage of
algorithm execution.
Square =
16
25
36
OddNum =
11
13
Count =
1 + 3 = 22
After iteration 2,
4 + 5 = 33
After iteration 3,
9 + 7 = 44
....and so on.
In general:
Square + OddNum = Count
Count
Some assertions about the state of a program (such as the one above) are
unaffected by the execution of the body of a loopif the assertion is true before
execution of the body, it will still be true after its execution. Such assertions are
called loop invariants. As an example, Pseudocode 5.23 repeats the pseudocode
loop of the Odd Square algorithm, this time including the invariant between
braces.
Pseudocode 5.23
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, lets look
at the Go Stone game as described in Figure 5.36.
Section 5.5
Repetition Foms
215
The Box
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 stonean
odd number of white stonesis 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.
When we evaluated the trigonometric sine function in Chapter 3, we used the
Factorial mathematical function. Factorials are also used in probability,
statistics and counting problems. The Factorial of any non-negative integer N is
written as N! and defined as follows:
N! = N (N 1) (N 2) (N 3) ... 3 2 1
Because multiplication is commutative, the products can be done in either
increasing or decreasing order as...
5! = 1 2 3 4 5
5! = 5 4 3 2 1
or
Figures 5.37 and 5.38 illustrate these two different algorithms. Fact1
multiplies products in increasing order while Fact2 does so in decreasing order.
Figure 5.37 Trace of the Fact1 algorithm for N = 5
Fact1
Input N
Set Fact to 1
Set Count to 1
N=5
Fact = 1
Count = 1
15
T
While Count N
25 35 45 55
T
T
T
T
Fact = 1
24
120
Count = 2
65
F
Output
Fact Count
Count!
120
Count = Count!
24
120
720
24
120
720
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.
Figure 5.38 Trace of the Fact2 algorithm for N = 5
Fact2
Input N
Set Fact to 1
Set Count to N
N=5
Fact = 1
Count = 5
5>0
T
Fact = 5
60
120
120
Decrement Count
Output
Output Fact
End Fact2
Fact Count!
N!
Count! = N!
120
120
120
120
120
120
120
120
120
120
120
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.
5.6
Invocation Forms
Sub-algorithms (or subprograms) are simply algorithms that have been
packaged into single units that may be used in other algorithms, as any other
action is. Sub-algorithms hide data and actions internally and so appear
simple externally. When a sub-algorithm is used as an action in another
algorithm, we say that it is called or invoked. In pseudocode, this is done
by giving its name and listing the data that it must use.
Figure 5.39 shows a data-flow diagram of Max, a sub-algorithm that finds the
maximum of two values.
Figure 5.39 Data-flow diagram for the sub-algorithm Max
Max
In this view, a black-box view, we show all that is needed in order to be able to
use Maxwe 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
Pseudocode 5.24
Invocation Forms
219
Input X
Input Y
Set Bigger to Max X, Y
Output Bigger
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.
Figure 5.40 Data-flow diagram and Pseudocode to find maximum
of four values
A
Max
Max2
Max
Max3
Max
Find Maximum 4
Input A
Input B
Input C
Input D
Set Max2 to Max (A, B)
Set Max3 to Max (Max2, C)
Set Max4 to Max (Max3, D)
Output Max4
End Find Maximum 4
Max4
220
Chapter 5
Algorithm Behavior
Pseudocode 5.25
Find Maximum
Input A
Input B
Input C
Input D
If A > B
Set Max2 to A
Else
Set Max2 to B
If Max2 > C
Set Max3 to Max2
Else
Set Max3 to C
If Max3 > D
Set Max4 to Max3
Else
Set Max4 to D
Output Max4
End Find Maximum
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.
2.
3.
Section 5.6
Invocation Forms
221
Figure 5.41 Data-flow diagrams for the Div and Mod subalgorithms
Numerator Divisor
Numerator 0
Numerator Divisor
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
= 1 000 000
C1
Div
Mod
Seconds
= 49 600
C2
Div
Mod
Seconds
= 2 800
C3
= 60 60 24
= 86 400
Convert Seconds
Input Time
Set Days to
= 11
Days
Div (Time, 60 60 24)
Output Days
Set Seconds to
Mod (Time, 60 60 24)
Set Hours to
Div (Seconds, 60 60)
= 60 60
Output Hours
= 3600
Set Seconds to
Mod (Seconds, 60 60)
Set Minutes to
Div (Seconds, 60)
Hours
= 13
Output Minutes
Set Seconds to
Mod (Second, 60)
Output Seconds
End Convert Seconds
= 60
Div
Minutes
= 46
Seconds
= 40
Mod
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.
Section 5.6
223
Invocation Forms
representation for a number that is not pure base 10. We would have a similar
problem if we tried to represent a persons 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.
Figure 5.43 Time Difference algorithm with Invocations
Hour1
Hour2
0250
Time
2030
2030
Convert
Time-Difference
Hour1
Hour2
Convert
Convert
Min1 170
TimeDifference
Min2 1230
Subtract
-1060
Div
Mod
Hour
20
60
Min
30
Multiply
Absolute
Value
Difference
100
Add
1060
Difference
1230
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 subalgorithm, MinDiff, to find the minimum of three values.
Figure 5.44 Minimum time difference
Time1 Time2
Time1 Time3
Time2 Time3
TimeDifference
TimeDifference
TimeDifference
Diff1
Diff2
Minimum
MinDiff
Diff3
MinDiff
Input Time1, Time2, Time3
TimeDifference (Time1, Time2, Diff1)
TimeDifference (Time1, Time3, Diff2)
TimeDifference (Time2, Time3, Diff3)
Minimum (Diff1, Diff2, Diff3, MinDiff)
Ouput MinDiff
End 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.
Pseudocode 5.26
5.7
Improving Programs
Nested Loops and Selections
Until now, the algorithms of this chapter involved only simple forms. Here we
will consider some combinations of the Four Fundamental Forms, but we are
mainly interested in tracing these more complex structures. Their design will
only be considered in Chapters 6, 7, and 8.
Our first combination example computes the greatest common divisor of two
integers, that is, the largest integer that divides both of them. For example,
the greatest common divisor of 111 and 259 is 37. The Greatest Common Divisor
algorithm was first created by Euclid, in about 300 BC. (algorithms did not
wait for computers!) Figure 5.45 presents the Greatest Common Divisor (GCD)
algorithm as an algorithm that illustrates the nesting of a Selection form
inside a Repetition form.
Figure 5.45 The Greatest Common Divisor algorithm and trace
GCD
Input P
Input Q
Set X to P
Set Y to Q
P = 111
While X Y
111 259
T
111 148
T
111 37
T
74 37
T
If X > Y
111 > 37
T
74 > 37
T
X = 111
X = 111
X = 74
X = 37
Y = 148
Y = 37
Y = 37
Y = 37
Set X to X Y
Else
Set Y to Y X
Output Y
End GCD
Q = 259
X = 111
Y = 259
37 37
F
Output 37
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.46 The convert decimal to binary algorithm and trace
Convert to Binary
Input X
Set Power to 16
Set Temp to X
While Power > 0
Set Diff to
Temp Power
If Diff < 0
Output "0"
Else
Output "1"
Set Temp to
Diff
Divide Power by 2
End Convert to Binary
X = 13
Power = 16
Temp = 13
16 > 0
T
8>0
T
4>0
T
2>0
T
1>0
T
Diff = -3
Diff = 5
Diff = 1
Diff = -1
Diff = 0
-3 < 0
T
5 <0
F
1<0
F
-1 < 0
T
0<0
F
Temp = 5
Temp = 1
Temp = 0
0>0
F
2.
3.
4.
226
Chapter 5
Algorithm Behavior
5.
X = -4
Y = +5
Temp = -4
Product = 0
-4 > 0
F
-4 < 0
T
-3 < 0
T
-2 < 0
T
-1 < 0
T
Subtract Y from
Product
Product
= -5
Product
= -10
Product
= -15
Product
= -20
Increment Temp
Temp = -3
Temp = -2
Temp = -1
Temp = 0
Output Product
End Signed Product
0<0
F
Output
-20
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.
See Pseudocode
4.10 for a
detailed Make
Change
algorithm.
Section 5.7
Pseudocode 5.27
Improving Programs
227
Change Maker 1
Input Cost
Set Change to 100 Cost
Set Quarters to 0
While Change 25
Increment Quarters
Set Change to Change 25
Output Quarters
Set Nickels to 0
While Change 5
Increment Nickels
Set Change to Change 5
Output Nickels
Set Pennies to Change
Output Pennies
End Change Maker 1
Giving nickels
Giving pennies
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.
Lets look now at another version of Change Maker.
Pseudocode 5.28
Change Maker 2
Input Cost
Set Change to 100 Cost
Set Quarters to Change / 25
Output Quarters
Set Change to Change Quarters 25
Set Nickels to Change / 5
Output Nickels
Set Pennies to Change Nickels 5
Output Pennies
End Change Maker 2
Giving quarters
Giving nickels
Giving pennies
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
Pseudocode 5.29
Change Maker 3
Input Cost
Set Sum to Cost
Set Pennies to 0
While Mod (Sum, 5) 0
Increment Pennies
Increment Sum
Output Pennies
Set Nickels to 0
While Mod (Sum, 25) 0
Increment Nickels
Set Sum to Sum + 5
Output Nickels
Set Quarters to 0
While Sum 100
Increment Quarters
Set Sum to Sum + 25
Output Quarters
End Change Maker 3
Giving pennies:
counting up to the
nearest multiple of 5.
Giving nickels:
counting up to the
nearest multiple of 25.
Giving quarters:
counting up to 100.
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.
Lets 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
Pseudocode 5.30
Improving Programs
229
Change Maker 4
Input Cost
Set Change to 100 Cost
Set Quarters to 0
Set Nickels to 0
Set Pennies to 0
While Change > 0
If Change 25
Increment Quarters
Set Change to Change 25
Else
If Change 5
Increment Nickels
Set Change to Change 5
Else
Increment Pennies
Decrement Change
Output Quarters
Output Nickels
Output Pennies
End Change Maker 4
Giving quarters
Giving nickels
Giving pennies
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.
230
Chapter 5
Algorithm Behavior
5>0
T
4>0
T
3>0
T
2>0
T
1>0
T
Product = 6
Product
= 12
Product
= 18
Product
= 24
Product
= 30
Multiplier = 4
0>0
F
Loop Invariant:
X + Y = Product + Multiplicand Multiplier
Output
30
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
Pseudocode 5.31
Improving Programs
231
original relation
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
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:
Pseudocode 5.32
232
Chapter 5
Algorithm Behavior
X=5
Y=6
Multiplier = 5
Multiplicand = 6
Product = 0
5>0
T
4>0
T
2>0
T
1>0
T
5 odd
T
4 odd
F
2 odd
F
Product = 6
1 odd
T
Product
= 30
Multiplier = 4
Multiplier
=0
0>0
F
Else
Set Multiplicand to
Multiplicand +
Multiplicand
Multiplicand = 12
Multiplicand = 24
Set Multiplier to
Multiplier / 2
Multiplier
=2
Multiplier
=1
Output Product
End Positive Product 2
Output
30
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
233
Improving Programs
X=5
Y=6
Multiplier = 5
Multiplicand = 6
Product = 0
5>0
T
5 odd
T
2>0
T
1>0
T
2 odd
F
1 odd
T
0>0
F
Set Product to
Product +
Product = 6
Product = 30
Multiplicand
Set Multiplier to
Multiplier = 4
Multiplier = 0
Multiplier 1
Set Multiplicand to
Multiplicand + Multiplicand = 12 Multiplicand = 24
Multiplicand
Set Multiplier to
Multiplier = 2
Multiplier = 1
Multiplier / 2
Output Product
End Positive Product 3
Output
30
234
Chapter 5
5.8
Review
Algorithm Behavior
2.
3.
4.
Sequence Forms are quite simple, and can replace some of the other
structures. This shows in particular that different structures can have
the same behavior.
5.
6.
7.
8.
9.
10.
Section 5.9
5.9
Glossary
Character: A data type whose
values are textual symbols such as
letters, digits, punctuation marks
together with other symbols used to
control spatial arrangement or text,
such as tabs and end of page.
Identifier: A symbolic name that is
used to refer to a programming entity
such as a sub-program or variable.
Infinite Loop: A repetition form
whose condition is never met: the
loop keeps looping.
Instruction: A single action in a
program.
Iteration: A single execution of the
body of a repetition form.
Kludge: [Pronounced klooj and said
to be from Yiddish klug smart.]
An attempt to fix a programming
error by modification of the
symptoms of the error rather than
the logical cause for the error. If the
fix is successful, the program works,
but for the wrong reasons. By
extension, applied to a program that
has been fixed in this way and is thus
devoid of elegance.
Loop invariant: An assertion whose
truth is not changed by the complete
execution of the body of a loop. Thus,
if the assertion is true before the loop
is executed, it will still be true after
the loop has terminated.
Paradigm: A model or template for a
design.
Scientific notation: A method of
expressing real numbers as a decimal
Glossary
235
236
Chapter 5
Algorithm Behavior
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.
1.
min
2.
min
min
Max
Max
Max
min
M1
M2
Max
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
False
False
3.
C<A
C<B
A<B
True
True
False
True
False
C<B
C <A
True
True
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?
5.
b. A A B
c. A A B
B A+ B
B A B
BBA
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
7.
b. E A
c. Z A
B A+ A
A B
ZB+ Z+ Z
C B + B
BC
ZC+ Z+ Z
DC+ C
C D
Z D+ Z+ Z
E D+ D
DE
ZE+ Z+ Z
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.
9.
a. C A A
b. C A + B
DBB
D A B
EC D
EC D
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
10.
Problems
Logical Proof
Prove (or disprove) the following logical expressions.
a. NOT( P AND Q) = (NOT P) OR (NOT Q)
b. P AND (Q OR R) = (P AND Q) OR (P AND R)
c.
P OR (NOT P AND Q) = P OR Q
Equality of Selection
Compare the following two algorithms and try (intuitively) to
determine if they are equivalent. Then prove, or disprove, this
equivalence.
Problem 11
If P
If Q
X
Else
Y
Else
If R
Y
Else
Z
12.
If P and Q
X
Else
If R
Y
Else
Z
Bigger Equivalence
Prove whether or not the given algorithms are equivalent.
Problem 12
If P
If Q
If R
W
Else
X
Else
X
Else
If Q
If R
W
Else
Y
Else
Z
If Q
If R
W
Else
If P
X
Else
Y
Else
If P
X
Else
Z
239
240
Chapter 5
Algorithm Behavior
13.
14.
If P
X
Else
If Q
If R
X
Else
Y
Else
Y
15.
If C < A
If B < C
X
Else
Y
Else
If A < B
Y
Else
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
17.
Problems
Test Equivalence
Prove whether or not the following algorithms are equivalent in
behavior.
Problem 17
If A
If B
X
Else
Y
Else
If C
Y
Else
Z
If A and B
X
Else
If A or C
Y
Else
Z
If A or C
If A and B
X
Else
Y
Else
Z
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
19.
Test Sort
Prove whether or not the following data-flow algorithm sorts
variables having unequal values.
241
242
Chapter 5
Algorithm Behavior
Problem 19
A1
B1
Min
C1
Max
Min
20.
Min
Max
Max
A2
B2
C2
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
Set C to
Else
Set D to
Set C to
Output P
21.
P D
C1
D D
C/2
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
22.
Refine Prime
A prime number is defined to be any positive integer which is divisible
only by 1 and itself.
The following algorithm indicates whether any value X is prime or not.
Modify this algorithm in at least two ways, so that it does less looping.
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"
Square Again
The square of an integer N can be computed by summing all the integers
from 1 to N and then back down to 1. For example:
42 = 1 + 2 + 3 + 4 + 3 + 2 + 1 = 16
Create an algorithm to compute the square of any Integer N using such a
method.
244
Chapter 5
Algorithm Behavior
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.
26.
27.
28.
Extend Change
Extend the Change Maker algorithms (1 through 4 of Section 5.7) to
output the count of dimes also.
29.
Expo
Create an algorithm to compute the exponential function from the first
N terms of the following series:
Expo(x) = 1+ x +
30.
x2 x 3 x 4
+ +
+
2! 3! 4!
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
+
2
3
4
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.
Sine(x) = x
x3 x5 x7
+
3! 5! 7!
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).
33.
More Majority
Draw a data-flow diagram for the formula:
M = AB + AC + BC - (2A) (BC)
first using only binary functions (having two inputs), then using
functions of any number of inputs (i.e., using a four-input product). Prove
that this formula behaves as a majority.
34.
246
Chapter 5
Algorithm Behavior
35.
ISBN Flow
Draw a data-flow diagram describing the ISBN algorithm of Chapter
3. The inputs are the nine digits D1, D2, .. D9 and the output is the
check symbol C.
36.
What Is It?
Draw a data-flow diagram for the following formula, and indicate
briefly its behavior for all integers.
M = ( ABS(A + B) - ABS(A - B) )/2
37.
Invariance of Division
Find the loop invariant of the Divide algorithm, Figure 5.29.
39.
Invariance of Square
Create an algorithm to compute the square of any nonnegative integer N
by successively adding N for a total of N times. Find the loop
invariant.
40.
Invariance of Power
Create an algorithm to compute the power of any number X raised to
some integer value N, by looping N times and multiplying. Find the
loop invariant, and use it to improve this algorithm.
41.
Invariance of Pow
Find the loop invariant of the Pow algorithm shown in Problem 20.
Section 5.10
42.
Problems
247
Invariance of a Cube
The given algorithm computes the cube of any positive integer N. Trace
it for N = 5. Then indicate which of the following is the loop
invariant.
a. C3 = A + B + C + 6
b. C = B + D3
c.
C = B + (A/6)3
d. D3 = A3 + B 2 + C + 6
e.
43.
6 = A +B +C +D3
Invariance of Loan
Find the loop invariant of the Loan algorithm of Figure 5.32. You need
to introduce more variables, representing some sums.
44.
More Invariance
Trace the following algorithms Cube and First, and find their loop
invariants. Find two invariants for Second.
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
Loan Again
Modify the Loan algorithm of Figure 5.38
a. so that the interest rate increases by 1% each year,
248
Chapter 5
Algorithm Behavior
46.
to determine the time to pay off the entire loan and compute also
the total interest paid.
47.
48.
49.
Section 5.10
Problems
249
250
Chapter 5
Algorithm Behavior
Chapter Outline
251
Chapter Overview
6.1
6.2
6.3
6.4
6.5
6.6
6.7
6.8
6.9
Preview....................................................................252
Using External Data and Files...................................252
End-Of-File Markers.................................................255
More Building Blocks................................................259
The Select Form........................................................259
The For Form.............................................................262
Using the For Forms in Nests......................................265
Nesting Fors in Fors...................................................265
Nesting Selections in Fors..........................................269
Creating Plots with For Nests....................................273
More Data Types.......................................................275
The Character Type..................................................275
The Logical Type......................................................279
Some General Problem-Solving Algorithms................281
Bisection Finding Values..........................................281
Maximum Power Optimizing Power Output...............284
Solver Solving Equations..........................................287
Review Top Ten Things to Remember........................290
Glossary...................................................................291
Problems...................................................................292
252
252
6.1
Chapter 6
Bigger Blocks
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.
6.2
Section 6.2
Figure 6.1
An Average program
253
Find Mean 1
Find Mean 1
Set Num to 4
Set Sum to 0
Add North to Sum
Add South to Sum
Add East to Sum
Add West to Sum
Set Mean to Sum / Num
Output Mean
Find Mean 1
Sum
Mean
Num
North
South
East
West
Algorithm
0 20 30 70 100
25
4
20
10
40
30
Internal Data
Data
not external
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.
Figure 6.2
Extended Average
Find Mean 2
Find Mean 2
Set Num to 4
Set Sum to 0
Input Value
Add Value to Sum
Input Value
Add Value to Sum
Input Value
Add Value to Sum
Input Value
Add Value to Sum
Set Mean to Sum / Num
Output Mean
End Find Mean 2
Algorithm
Sum
Mean
Num
Value
0 20 30 70 100
25
4
20 10 40 30
Data
Not in
Memory
Internal Data
20
10
40
30
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.
Figure 6.3
Find Mean 3
Set Sum to 0
Input Num
Set Count to 0
While Count < Num
Input Value
Set Sum to Sum + Value
Set Count to Count + 1
Set Mean to Sum / Num
Output Mean
End Find Mean 3
Algorithm
Sum
Changed from
previous version
Mean
Num
Value
Count
Internal Data
4
20
10
40
30
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
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.
Figure 6.4
Find Mean 4
Set Sum to 0
Set Num to 0
Set Terminator to -999
Input Value
While Value Terminator
Set Sum to Sum + Value
Set Num to Num + 1
Input Value
Set Mean to Sum / Num
Output Mean
End Find Mean 4
External data
Sum
20
10
Mean
40
30
-999
Num
Value
Terminator
-999
Changed
from
previous
version
Terminating Value
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.
Note:
256
Chapter 6
Bigger Blocks
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.
Figure 6.5
Find Mean 5
Set Sum to 0
Set Num to 0
Input Terminator
Input Value
While Value Terminator
Set Sum to Sum + Value
Set Num to Num + 1
Input Value
Set Mean to Sum / Num
End Find Mean 5
External data
Sum
Mean
Num
Terminator
-999
-999
20
10
40
30
-999
Changed
from
previous
version
Value
Terminating Value
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
algorithms
Maximum 1 and
Maximum 2
were introduced
in Figure 5.14.
Pseudocode 6.1
Maximum 1
If A > B
Set Max to A
Else
Set Max to B
Output Max
End Maximum 1
Section 6.2
257
Maximum 1 Extended
If A > B
If A > C
Set Max to A
Else
Set Max to C
Else
If B > C
Set Max to B
Else
Set Max to C
Output Max
End Maximum 1 Extended
Maximum 2 Extended
Set Max to A
If Max < B
Set Max to B
If Max < C
Set Max to C
Output Max
End Maximum 2 Extended
Shallow
Deep
258
Chapter 6
Bigger Blocks
Figure 6.6
Sequence Max
We
extend
Maximum
2, first.
Loop Max
Input Value
Set Max to Value
Input Terminator
Input Value
Set Max to Value
Input Value
If Max < Value
Set Max to Value
Input Value
While Value Terminator
Input Value
If Max < Value
Set Max to Value
Input Value
Second, we
refine
Sequence
Max.
Output Max
End Sequence Max
Output Max
End Loop Max
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
Pseudocode 6.3
259
Typical pattern
for algorithms
inputting
external data
These computations may also be done using arrays, as we will see in Chapter 8.
6.3
If Cond 1
Actions 1
Else
If Cond 2
Actions 2
Else
If Cond 3
Actions 3
Nested Selections
template
Else
If Cond n
Actions n
Else
Actions n+1
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
Select
Cond 1 Actions 1
Cond 2 Actions 2
Cond 3 Actions 3
Cond n Actions n
Otherwise Actions n+1
The Grades 1
algorithm was
first introduced
in Chapter 5,
Pseudocode 5.9.
The form in Pseudocode 6.5 is much simpler to understand than the Pseudocode
6.4 which uses only Selection Forms. To fully illustrate the difference between
these two forms, Figure 6.7 shows the Grades 1 algorithm expressed as a nested
set of Selection forms (left) and as a single Select Form (right). This figure also
shows how the value of Percent selects the grade for output.
Figure 6.7
algorithm
Grades 1
Input Percent
If Percent 90
Output "A"
Else
If Percent 80
Output "B"
Else
If Percent 60
Output "C"
Else
If Percent 50
Output "D"
Else
Output "F"
End Grades 1
equivalent
Grades 1
Input Percent
Select
Percent 90:
Output "A"
Percent 80:
Output "B"
Percent 60:
Output "C"
Percent 50:
Output "D"
Otherwise:
Output "F"
End Grades 1
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
Pseudocode 6.6
261
Input Percent
Select
Percent 90:
Output "A"
Increment CountA
Percent 80:
Output "B"
Increment CountB
Percent 60:
Output "C"
Increment CountC
Percent 50:
Output "D"
Increment CountD
Otherwise:
Output "F"
Increment CountF
Group of actions
Lets illustrate further the Select Form with an algorithm for determining the
unit price, depending upon the quantity ordered, shown in Pseudocode 6.7.
Pseudocode 6.7
Select Form
Price
Input Quantity
Select
Quantity = 1:
Set Price to
Quantity = 2:
Set Price to
Quantity = 3:
Set Price to
Quantity = 4:
Set Price to
Quantity = 5:
Set Price to
Quantity = 6:
Set Price to
Quantity = 7:
Set Price to
Quantity = 8:
Set Price to
Quantity = 9:
Set Price to
Otherwise:
Set Price to
Output Price
End Price
99
98
98
95
95
95
Price
Input Quantity
Select Quantity
1:
Set Price
2, 3:
Set Price
4, 5, 6:
Set Price
7, 8, 9:
Set Price
Otherwise:
Set Price
Output Price
End Price
to 99
to 98
to 95
to 90
to 85
90
90
90
85
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.
Input X
Input Y
Set Product to 0
Set Count to 1
While Count Y
Add X to Product
Increment Count
Output Product
equivalent
Input X
Input Y
Set Product to 0
For Count = 1 to Y by 1
Add X to Product
Output Product
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.
Pseudocode 6.8
Section 6.3
263
Factorial
Input N
Set Factorial to 1
Set Count to 1
While Count N
Set Factorial to
Factorial Count
Increment Count
Output Factorial
End Factorial
Factorial
Input N
Set Factorial to 1
For Count = 1 to N by 1
Set Factorial to
Factorial Count
Output Factorial
End Factorial
Square
Input Num
Set Square to 0
Set OddNum to 1
While OddNum (Num + Num)
Set Square to
Square + OddNum
Set OddNum to
OddNum + 2
Output Square
End Square
Square
Input Num
Set Square to 0
For OddNum = 1 to
Num + Num by 2
Set Square to
Square + OddNum
Output Square
End Square
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
Pseudocode 6.11
While
For
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
6.4
the While loop is more general than the For loop. When in doubt,
you can always use the While loop.
Pseudocode 6.12 shows two forms of an algorithm with doubly nested counting
loops. It is a version of an algorithm we have discussed in various forms in
Chapter 3, and that computes the total admission Charge if Adults pay three
dollars each and Kids pay two dollars each. The algorithm creates a table of
charges for one to two adults and zero to three kids. On the top of the figure, is
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
Pseudocode 6.12
265
Nested Loops
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.
Figure 6.9
Adults =
Adults 2
Kids =
T
0
T
1
T
2
T
3
T
4
T
0
T
1
T
2
T
3
T
4
Kids 3
Charge =
T
3
T
5
T
7
T
9
T
6
T
8
T
10
T
12
Kids' =
3
1
5
2
7
3
9
4
6
1
8
2
10
3
12
4
Adults' =
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
Kids =
Charge =
8 10 12
8 10 12
Outer loop
control variable
Inner loop
control variable
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.
Lets 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
Outer loop
counter
Hour Timer
For Minutes = 0 to 59 by 1
Wait a minute
Wait-a-Minute
For Seconds = 0 to 59 by 1
Wait a Second
Output Minutes
Output Seconds
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
For Tens = O to 9 by 1
For Units = 0 to 9 by 1
Output Tens
Output Units
For Dice1 = 1 to 6 by 1
For Dice2 = 1 to 6 by 1
Output Dice1
Output Dice2
267
268
Chapter 6
Bigger Blocks
Pseudocode 6.15
Binary counter
For Bit1 = 0 to 1 by 1
For Bit2 = 0 to 1 by 1
For Bit3 = 0 to 1 by 1
Output Bit1
Output Bit2
Output Bit3
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.
Those
combinations
could then be
tabulated, as
seen in Figure
5.24.
This Binary Counter algorithm could be used to generate all of the possible
combinations to test the Majority algorithms seen in Chapters 3 and 5.
Going one level deeper, Pseudocode 6.16 illustrates the For forms for a mileage
odometer.
Pseudocode 6.16
For Hundreds = 0 to 9 by 1
For Tens = 0 to 9 by 1
For Units = 0 to 9 by 1
For Tenths = 0 to 9 by 1
Output Hundreds
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.
Pseudocode 6.17
While True
For Hours = 0 to 23 by 1
For Minutes = 0 to 59 by 1
For Seconds = 0 to 59 by 1
Wait a second
Output Hours
Output Minutes
Output Seconds
Section 6.4
269
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.
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.
Figure 6.13 Production data
dept 1
1990
dept 2
dept 3
dept 1
dept 2
1991
dept 3
person 1
person 2
person 1
... 2
... 3
person 1
... 2
person 1
... 2
person 1
person 1
... 2
... 3
person 4
30
40
40
20
30
40
40
40
40
60
10
30
20
40
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
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.
Figure 6.15 Top-down development of Production algorithm
Stage 1: Production
Set up
For Year = First to Last by 1
FindMaxProduction
PrintReport
Stage 2: Find Max. Production
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
Set TotalProd to 0
Input Count
For Person = 1 to Count by 1
Input Prod
Set TotalProd to TotalProd +
Prod
272
Chapter 6
Bigger Blocks
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!
Set Date to 1
For Row = 1 to 4 by 1
For Column = 1 to 7 by 1
Output Date
Increment Date
New line
Rows
1
2
3
4
Output of Scan
Columns
1
2
3
4
5
6
71
2
3
4
5
6
8
9 10 11 12 13
15 16 17 18 19 20
22 23 24 25 26 27
7
14
21
28
y=
x2
3
can be created by printing marks on a grid as shown at the left of Figure 6.17. In
practice, using screens or printers, it is more convenient to plot this on its side as
shown at the right of the figure.
Section 6.4
273
Sideways Plot
direction of printing
Y
Yint
X
0
1
4
0 1
10
*
*
4
X
*
*
Y=X
3
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.
Figure 6.18 Sample values
X
1
3
4
3
16
3
25
3
Y int
The table of Figure 6.18 shows how the values of the output Y are rounded into
integers Y int.
Figure 6.19 Algorithm for plotting a graph
Plot
For X = 0 to 5 by 1
Compute Y
Set Y int to Y
Print a line for Y int
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.
Figure 6.20 An extended plot of two graphs
f(x)
Y=XX
Z = K X
For Position = 0 to 10 by 1
If Position = Y int
Output '*'
Else
If Position = Zint
Output '+'
Else
Output ' '
Extension for
the plot of 2
functions
6.5
Section 6.5
275
A,
B,
C,
D,
Reply
Y,
N,
y,
Operator
+,
-,
*,
Digit
0,
1,
2,
3,
Bracket
4...9
276
Chapter 6
Bigger Blocks
Select Function
'+' :
Set Result to Result + Value
'' :
Set Result to Result Value
' ' :
Set Result to Result Value
'/' :
Set Result to Result / Value
Otherwise:
Output "Function error"
End Decode
Note:
1+2*3=
(which returns 3 3 or 9)
4*56/7=
(which returns 14 / 7 or 2)
9 / 5 * 100 + 32 =
Section 6.5
277
ISBN Checksum
Set Sum to 0
Set Mult to 1
Input Character
While Character '.'
If Character '-'
Convert Character
Set Sum to sum + Mult Digit
Set Mult to Mult + 1
Input Character
Set Remainder to Mod Sum, 11
If Remainder = 10
Output 'X'
Else
Output Remainder
End ISBN Checksum
Select Character
'0' :
Set Digit to 0
'1' :
Set Digit to 1
'2' :
Set Digit to 2
'3' :
Set Digit to 3
'4' :
Set Digit to 4
'5' :
Set Digit to 5
'6' :
Set Digit to 6
'7' :
Set Digit to 7
'8' :
Set Digit to 8
'9' :
Set Digit to 9
Otherwise:
Output "Digit error"
End Convert Character
Notice here that the numeric Characters input
must be converted first of all into numbers,
before any operations can be performed on
them. Other converting methods are possible.
Notice that the Decode algorithm (Figure 6.21) uses the Case Form (a variation
of the Select Form) that compares a single value with a set of constants and
performs the appropriate action. If the Function entered is not one of the
recognized operations, the message Function error is output.
For more details
on how to
compute the
checksum for
ISBNs, see Figure
3.5.
278
Chapter 6
Bigger Blocks
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.
Male to True
Over21 to (Age > 21)
Danger to (Divisor = 0)
Done to (Counter = Last)
Triangle to ((Small + Mid) > Large)
Right to ((X X + Y Y) = H H)
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.
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
Pseudocode 6.23
279
Examples using OR
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.
Pseudocode 6.24
A AND B = 5
T = 7 OR 11
A <B <C
X OR Y > Z
I = J AND K
S NOT 7 OR 11
Proper
should
should
should
should
should
should
read
read
read
read
read
read
(A = 5) AND (B = 5)
(T = 7) OR (T = 11)
(A < B) AND (B < C)
(X > Z) OR (Y > Z)
(I = J) AND (I = K)
NOT((S = 7) OR (S = 11))
280
Chapter 6
Bigger Blocks
Note:
PQ
T
T
F
T
1
P=Q
T
F
F
T
2
PQ
F
T
T
F
3
P>Q
F
F
T
F
4
6.6
Finding Values
The Bisectionalgorithm is very useful for solving many types of problems and is
often also referred to as Bracketing, Divide and Conquer, or the Half-Interval
Method. It proceeds by taking two limiting values and adjusting them
successively to bracket the required result. This is actually the method we used
in the Guesser algorithm of Chapter 4 (see Figure 4.7), which is reproduced
and renamed at the left of Pseudocode 6.26.
Section 6.6
281
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
SqRoot = 6
High = 6
High = 6
SqRoot = 3
High = 6
Low = 4.5
Low = 3
Low = 0
Low = 0
Low = 0
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
instead of
(SqRoot
SqRoot)
X.
Lets 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
283
X = 24
Set High to X
Set Low to 0
Set Precision to 0.1
High = 24
Low = 0
Precision = 0.1
SqRoot = 12
15 > 0.1
T
9 > 24
F
High =
12
Low =
SqRoot =
4.5
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.
Maximum Power
284
Chapter 6
Bigger Blocks
Circuit
+
RS = 6
VS = 120
R = RS + RL
I = VS / R
RL
P = I2
RL
Relations among the variables are given by the formulas on the right in Figure
6.27 (determined from knowledge of Ohms law and Kirchoffs 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.
Figure 6.28 Power plot for circuit in Figure 6.27
Power (watts)
P
800
PMax = 600
600
400
half power
200
RLbest = 6
RLlow = 1
10
20
30
RLhigh = 34
Load (ohms)
RL
Section 6.6
285
Process
Set 1 to V S / (RS + RL )
Set P to 1 1 R L
If P Max < P
Set P Max to P
Set R Lbest to RL
End Process
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.
Solver
Solving Equations
Now we will develop a general equation solving algorithm, Solver, that solves
any two equations that are functions of a single variable, say x. The equations
may be linear or highly nonlinear. Solver will find any number of values of x
that satisfy both equations, be it zero, one, two or more.
286
Chapter 6
Bigger Blocks
F (x)
6
Error
(of 4.0)
for
x = 2.0
Equations:
F(x) = x2
G(x) = 2 - x
Solutions:
x = +1.00
x = -2.00
G (x)
-4
-2
Section 6.6
y1
= F(0.5) = (0.5)(0.5)
= 0.25
y2
= 1.50
Err
= 1.25
287
If the random value chosen for x is +1.0, then y1 = y2 and the error is zero. For
other values of x, there could be a larger error. We could reduce the errors by
using the Solver again, but within a range that is much closer to the actual
value of a solution.
In the case of our example, other tries of Solver would also yield the other
solution (which is -2.00). In fact, it would be useful to run Solver a number of
times, say 10, so that other solutions (if they exist) may be seen.
Figure 6.31 Solver algorithm for solving pair of equations F(x)
and G(x)
Solver
Set Range
Set MinError
...
While more values
Get Random x
Update Best
Increase Count
Output Bestx
Output MinError
End Solver
Update Best
Set y1 to F(x)
Set y2 to G(x)
Set Err to Abs(y2 y1)
If Err < MinError
Set MinError to Err
Set Bestx to X
End Update Best
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:
Value of x
Minimum Error
-1.98
0.006
+0.50
1.250
+0.99
0.030
+1.04
0.122
-2.02
0.060
288
Chapter 6
Bigger Blocks
Section 6.7
6.7
Review
289
2.
3.
4.
5.
6.
The Case Form, a variation of the Select Form, was also introduced and
is used to compare one variable against many constants.
7.
8.
9.
The choice of data types was also made bigger by adding the Character
data typeand the Logical data type. As with other data types,
operations on Characters include assignment, comparison, input and
output. Operations on Logical type variables include the assignment,
conjunction (AND), disjunction (OR), and negation (NOT). Logical
variables may also be compared.
10.
The Bisection algorithm was also introduced and is very useful for
solving many types of problems. It proceeds by taking two limiting
values and adjusting them successively until they bracket the required
result.
290
Chapter 6
6.8
Glossary
Bigger Blocks
Section 6.9
6.9
Problems
291
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.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
5
*
2
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:
Sine(x) = x
x3 x5 x7
+
3! 5! 7!
4.
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
10.
OUTPUTS
Miles
Gals
Short
Long
1000
20
1200
10
20
20
1500
20
15
16.67
...
...
...
...
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
45
45
100
50
55
55
120
60
60
30
Max = 60
294
Chapter 6
Bigger Blocks
12.
Unbiased Mean
In some sports, a number of judges each ranks performance on a scale from
1 to 10. To adjust for biases, both the highest and lowest values are
eliminated before computing the average. Create an algorithm to
compute such an average for M judges on N performances.
Once More
What action is performed by the following algorithm?
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 B
C
15.
While A AND B
C
Expo
The exponential function
terms of this series:
Expo(x) = 1+ x +
x2 x 3 x 4
+ +
+
2! 3! 4!
Section 6.9
16.
Problems
295
Down Timer
Create a timer to count down from a given number of hours, minutes and
seconds to zero. At intervals of five seconds, it outputs the time
(remaining to zero).
17.
Pythagorean Triplets
Construct an algorithm to produce all integers x, y, and z that satisfy
the Pythagorean theorem (relating the sides of a right triangle):
x2 + y2 = z 2
(where
x < y < z)
Let x, y, and z be positive integers, all less than some fixed input value
M (say 100).
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.
Logical Swap?
Prove (or disprove) the fact that the following two algorithms swap
the values of the logical variables, P and Q.
a.
Set P to NOT(P OR Q)
b. Set P to (P = Q)
Set Q to NOT(P OR Q)
Set Q to (P = Q)
Set P to NOT(P OR Q)
Set P to (P = Q)
20.
Logical Less
If False is defined as less than True, draw a truth table for the
operation P < Q. Draw also a table for P Q.
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).
22.
When In Rome...
One method for converting an Arabic number into a Roman number is to
separately convert each digit (the units, tens, hundreds, and thousands
positions) as shown:
1
CM
LXXX IV
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.
Section 6.9
Problems
297
298
Chapter 6
Bigger Blocks
Chapter Outline
299
Chapter Outline
7.1
7.2
7.3
7.4
7.5
7.6
7.7
7.8
Preview....................................................................300
Subprograms.............................................................300
How to Simplify Large Programs...............................300
What are Parameters?..............................................305
Data Space Diagrams...............................................309
Parameter Passing.....................................................312
Passing Parameters In and Out...................................312
Special Cases............................................................316
Some Examples.........................................................321
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
More Types of Subprograms........................................343
Recursion Self-Referencing Subprograms...................343
Functions...................................................................345
Modules....................................................................346
Review Top Ten Things to Remember........................348
Glossary...................................................................350
Problems...................................................................351
300
Chapter 7
7.1
Preview
Better Blocks
7.2
Subprograms
How to Simplify Large Programs
There are a number of ways to simplify a large program. The following figures
illustrate these ways, going from simple program forms to more modular forms.
These figures will serve as models on which the examples used later in this
chapter can be based.
Section 7.2
Figure 7.1
Subprograms
301
No Structure
Data
Actions
Split Structure
Temp
Global data are
still accessible
to all of the actions.
Action Group A
Action Group B
Problem: communication
between pieces
is too complex.
Action Group C
Data
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.
Figure 7.3
Hierarchical structure
Section 7.2
Subprograms
303
These data are local to a subprogram and are hidden from the other
subprograms, thus being protected against being changed by them.
Figure 7.4
These local
data are not
accessible by
any other
subprograms
but this one.
Global data
available to
all parts of
the program
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.
Figure 7.5
Global data
Best program
structure: it uses a
minimum amount of
communication
between parts.
Local data
Parameter
304
Chapter 7
Better Blocks
a. External view:
Data flow diagram (black box)
Y
Max
M
Pass-in X , Y
Max
Pass-out M
c. Internal view:
pseudocode (glass box)
If X > Y
Set M to X
Else
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
subprograms interface specification.
Parameters are subprogram variables used to communicate data between the
subprogram and either the main program or another subprogram.
Section 7.2
Figure 7.7
A
subprogram
parameters
Subprograms
305
Y
Max
M
E
X
Y
Max
M
Max3
Input A, B, C
Max( A , B , E )
Max(E, C, L)
Output L
End Max3
program
arguments
To see how such a subprogram is used, lets 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), Max3s variables A, B and E are
connected to Maxs 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); Max3s variables, E, C, and
L, are connected to Maxs 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
callers arguments and the subprograms parameters and the values are
transmitted through this connection.
Lets 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
jumping
Pr ogram Excitement
Get up at dawn.
Go do some bungee-jumping
.
Tell all your friends how exciting it was.
Go to bed.
Program Excitement
Get up at dawn.
Go do some sky-diving .
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 subprograms parameterand bungeejumping the main programs argument. This program and subprogram are shown
in Figure 7.8.
Figure 7.8
parameter
Section 7.2
Subprograms
307
Get up at dawn.
Eat a light lunch.
Write out your will.
Put on bungee-jumping equipment.
Perform bungee-jumping.
Tell all your friends how exciting it was.
Go to bed.
Go do some
dangerous sport
is invoked.
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 programs argument. If you preferred to go skydiving, 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.
Figure 7.9
Program Excitement
Get up at dawn.
Go do some sky-diving.
Tell all your friends how exciting it was.
Go to bed.
SubProgram Go do some dangerous sport
Eat a light lunch.
Write out your will.
Put on dangerous sport equipment
Perform dangerous sport.
This subprogram
and its parameter
remain as is.
To introduce the concept of a data space diagram, lets consider again the
Divide subprogram. We already saw Divide in Chapters 3 and 5, and used it in
many algorithms such as Change Maker, Convert Grams, and Decimal to
Binary. A particular version of the Divide subprogram is shown in Figure 7.10.
308
Chapter 7
Better Blocks
Divisor
Num
Num
Denom
Denom
Divide
Quot
Rem
Quotient
Remainder
Quot
Rem
Count
Divide ( Num, Denom, Quot, Rem )
Set Rem to Num
Set Count to 0
While Rem Denom
Set Count to Count + 1
Set Rem to Rem Denom
Set Quot to Count
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 subprograms 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.
Note:
2.
Passed-in parameters, like Num and Denom, are drawn as boxes at the
top left. Passed-in parameters correspond to the arrows pointing into a
data-flow diagram.
3.
Passed-out parameters, like Quot and Rem, are shown as dotted boxes
at the bottom left. Passed-out parameters correspond to the arrows
pointing out of a data-flow diagram.
4.
Local variables, like Count in our example, are accessible only from
within a subprogram and are drawn at the upper right of the data
space diagrams. Local variables have no meaning outside the
subprogram, and are used to hide or protect any data that have no need
to be accessible from the outside.
5.
Solid boxes used for local variables and passed-in parameters represent
actual memory locations within the subprogram, where the values are
stored.
6.
Dotted boxes used for the passed-out parameters do not represent actual
space. They refer or point to actual memory locations outside the
subprogram.
Section 7.2
Subprograms
309
A
B
C
E
F
G
S
T
Sub ( E, F, G, U, V )
Sub
subprogram body
U
V
Y
Z
Z
End Sub
passed-out
parameters
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.
Figure 7.12 The Change subprogram
Tendered
Cost
T
C
Change
Q
R
Change ( T, C, Q, D, N, P )
subprogram body
Quarters
Nickels
Dimes
Pennies
Q
D
N
P
End Change
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.
Figure 7.13 Change as a program
If Change
were a
main program
...
Change
program body
End Change
R
T
C
Q
D
N
P
310
Chapter 7
An example of
this is the
Change Maker
programs (all 1
through 4) of
Chapter 5,
Section 5.7.
Better Blocks
7.3
Parameter Passing
Passing Parameters In and Out
The actual way in which the data are passed in or out of a subprogram depends
on whether they correspond to input parameters (passed-in) or output
parameters (passed-out):
Input parameter: the parameter behaves as a local variable that is
initialized by the value of the argument. Once this initialization has
taken place, the link between the argument and parameter is broken.
Thus, even though the subprogram may change the value of the
parameter, this has no effect on the corresponding argument. Since only
the arguments value is used, the argument can be a constant, variable or
expression. This mechanism for passing data is called passing
parameters by value.
Output parameter: the parameter is linked to the argument in such a
way that all references to the parameter in the subprogram become
references to the argument, which must be a variable. Any change to
the value of the parameter by the subprogram is a change to the value
of the argument. Thus, the argument and the parameter become
equivalent during this invocation of the subprogram. This mechanism
for passing data is called passing parameters by reference.
These two methods will be illustrated first by a simple program,
AverageExample, that uses the Divide subprogram, and later by another
program, Change, that also uses Divide.
Figure 7.14 give two different views of the subprogram Divide. It includes a dataflow diagram and a data space diagram with a description of the algorithm in
pseudocode. The data-flow diagram shows the invocation:
Divide(A + B, 2, C, D)
where input parameters Num and Denom are initialized with the values A + B
and 2, and where output parameters Quot and Rem are made equivalent to C and D.
Section 7.3
Parameter Passing
311
Pseudocode
A+B
inputs
1
Num
Denom
Num Count
Denom
Divide
Actions
Quot
Rem
Quot
Rem
4
outputs
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.
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 Divides header Divide(Num, Denom, Quot,
Rem)
a. The expression A + B is evaluated to 7 and that value is copied
into Divides variable Num.
b. The value 2 is copied into Divides variable Denom.
c.
312
Chapter 7
Better Blocks
A 2
B 5
C 3
D 7 5 3 1
AverageExample
Set A to 2
Set B to 5
Divide (A+B,2,C,D)
Output C
If D = 0
Output "Exactly"
Else
Output
Approximate"
End AverageExample
5+2=7
A+B
2
C
D
Num
Denom
Quot
Rem
return
7
2
Num Count 0
Denom
4.
Subprogram Divide is executed: its actions are carried out. Each time
the output parameters Quot and Rem are modified (by the Set Rem to
Rem-Denom and Set Quot to Count statements), the actual values that
are changed are those of Average Examples variables C and D.
5.
The memory space for Divides variables, Num, Denom and Count is
released. If the subprogram Divide were re-invoked, a completely new
memory space would be used for these three variables.
6.
This simple example might seem a bit complicated when we look at it with
that much detail! Be sure to understand it completely as it illustrates the two
methods by which data are passed between a program and an invoked
subprogram:
By Value: The arguments (A + B, 2) corresponding to Divides
parameters Num and Denom were passed by value. With this method,
an argument (which can be an expression like A + B or a constant like
2) is evaluated and copied into the temporary space allocated to the
corresponding parameter in the subprogram. If this value is then
changed in the subprogram, the change remains local to the subprogram
and does not affect the original corresponding variable in the calling
program.
By Reference: The arguments (C and D) corresponding to Divides
parameters Quot and Rem, which were underlined in Divides header,
were passed by reference. With this method, the parameters of the
called subprogram become aliases for the actual variables in the
calling program. This requires that arguments be variables. Whenever
the parameters of the subprogram are assigned new values (as in Set
Quot to Count), it is the values of the corresponding arguments in the
calling program that are actually changed (like C in this instance).
To help you remember the difference between these two methods, we can say
that passing parameters between program and invoked subprogram can be done
via two channels of communication:
Section 7.3
Parameter Passing
313
Special Cases
In the previous section, we were introduced to the communications between
programs and subprograms via parameters. Among all possible cases for
subprograms, there are two special cases:
Subprograms with no parameters (only local variables), and
Subprograms with only parameters (no local variables).
We will now take a look at both of these extreme cases in order to improve our
understanding of communications among subprograms.
The case of a parameterless subprogram is illustrated by the example in
Figure 7.16. There, the main program has a global variable A and the
subprogram has one local variable B. The main program communicates with
the subprogram through the global variable A.
Figure 7.16 Parameterless communication
A
Main Program
Set A to 5
Sub1()
Output A
End Main
25
This global
variable is
used to
communicate
with Sub1.
Sub 1 ()
Set B to A x A
Set A to B + 3
End Sub1
In Figure 7.16, A is being used not only to receive the results of the subroutines
calculation, but also send the data to be used by the subroutine. This use of
global variables is fairly common but is not recommended because it makes the
program more difficult to understand. The problem is that when you read the
invocation Sub1(), there is no indication that the global variable A is being
used as a communication channel and that its value will be changed. To
discover this, you must study Sub1 in detail. This is not practical. Such
implicit uses of global variables often lead to hard-to-find problems.
314
Chapter 7
Better Blocks
In the example in Figure 7.16, the names of the variables are different. What
would happen if this were not so and the name of a local variable in the
subprogram were the same as the name of a global variable?
Figure 7.17 Parameterless communication with name duplication
A
B
Main Program
Sub 2()
Output A
Output B
Output C
End Main
Sub 2 ()
Set A to 1
Set B to 2
Set C to 3
End Sub2
B
C
1
??
In Figure 7.17, there is a main program with two variables A and B, and a
subprogram with two local variables B and C. Notice that we have used the
same name B to refer to two different variables, one in the main program and
one in the subprogram. We have done this on purpose to illustrate the
independence of name spaces. In practice, it is not recommended to use identical
names in different parts of a program even though it is allowed. We will say
more about this in a later section.
When we have subprograms nested in the main program or within other
subprograms, access to the various variables is determined by the rules in Figure
7.18.
Figure 7.18 Rules on using variables in subprograms
Rule 1: A (sub)program cannot
access the local variables
of any subprograms nested
within it.
Main Program
Set Local1 to 0
Main Program
Set Global1 to 0
Main Program
Global1
Global2
Local1
Local2
Subprogram
Global1
Global2
Local1
Local2
Subprogram
Set Local 1 to 1
Global1
Global2
Local1
Local2
Subprogram
Set Global1 to 0
Set Extra to 0
Where is Extra? This is
an error in the program.
Section 7.3
Parameter Passing
315
When the main program calls subprogram Sub2, it does so with the
statement Sub2() where the argument list is empty because the
subprogram has an empty parameter list.
2.
3.
The next variable B is found within Sub2 (Rule 2), so that B Sub2
receives the value 2. The outer variable B Main cannot be accessed by
Sub2 since B Sub2 exists and was found first (Rule 3). Its value was
never set and remains undefined, denoted by ??.
4.
5.
6.
7.
It should now be clear that we can use local variables to hide some values, just
as Sub2 hid the values 2, and 3 of B Sub2 and C. This simplifies the program
structureand makes the resulting program much less prone to error. However,
the access to variables at higher levelsglobal variablesprovided by Rule 3
is very dangerous and should be avoided. Why? Because, as we said before,
communication through global variables is not explicit and occurs sometimes
without us being aware of it.
Tip 1: Only use parameters when communicating between programs and
subprograms.
Tip 2: Try to use different variable names whenever possible.
Figure 7.19 Parameter-only communication
X
Y
Main Program
Input X
Sub3(X, Y)
Output Y
End Main
Y
Sub3(Y, Z)
Set Z to Y + Y
End Sub3
No box here
means no
local variables.
Our next example, in Figure 7.19, uses only parameters to communicate, and
Sub3 has no local variables. The main program has two global variables X and
Y, and the subprogram has two parameters Y and Z. Notice that we have again
used the same variable name Y in both the main program and the subprogram,
but there are no ambiguities as there were in Figure 7.13.
316
Chapter 7
Better Blocks
Main Program
Input Q
Input P
Input S
Sub4(Q, R)
Output R
End Main
T
Sub4(R, S)
Set T to R + 3
Set R to T + R
Set S to R + 4
End
Sub4
S
P
Q
R
S
Q is copied
into R.
Each reference to S
refers to Rmain.
Section 7.3
Parameter Passing
317
P
Q
R
S
T
in
Main Program
Paid
Quantity
Result
Sum
in Subprogram
Sub4
Received
Sent
Temporary
Such conflicts in naming can become very confusing for humans, but are not a
problem for computers. Normally, such short and duplicated names are to be
avoided, but if they happen to be chosen, they cause no problem for the
computer and confuse only the reader. Obviously, in our small examples we
could easily have chosen different names that could have helped the reader
understand more easily. The important thing to note is that, in large programs
where different people work on many parts, we do not need to have some
elaborate scheme to prevent programmers from using names already used by
others.
In most cases the names chosen would also be more meaningful, as they have
been in the examples of the preceding chapters. However, here we have used
short names to keep the lists of subprogram parameters and arguments short as
well. In practice, we will always use meaningful names.
Tip:
318
Chapter 7
Better Blocks
Some Examples...
Figure 7.22 Data-flow diagram for Change program
Input Tendered
Input Cost
100
42
Subtract
58
25
Divide
D
Q
2
10
Divide
D
Q
0
N
R
Divide
D
Q
1
N
3
Lets consider an algorithm Change, which calls the subprogram Divide three
times. The Change algorithm inputs the amount Tendered and the Cost and
outputs the number of Quarters, Dimes, Nickels, and Pennies. It was
introduced in Chapter 3 and is shown in the data-flow diagram of Figure 7.22.
Section 7.3
Parameter Passing
319
Change
Input Tendered
Input Cost
Tendered
Cost
Rest
100
42
8
Quarters
Dimes
Nickels
Pennies
2
0
1
3
Snapshots of
58
25
Num Count
Denom
Num Count
Denom
Quot
Rem
8
5
1
3
Num Count
Denom
Quot
Rem
The data space diagram of Figure 7.23 has been extended to show snapshots of
the subprogram calls. Even though the figure shows three instances of the
Divide subprogram, it should be noted that only one Divide subprogram exists at
any time.
The first call to Divide passes the value of the expression Tendered
Cost and the constant 25 as the denominator. Divide then returns the
quotient in Quarters (2) and the Rest of the change (8).
The second invocation of Divide passes the value of Rest obtained from
the first call and the constant 10. Divide then returns the quotient in
Dimes (0), and the same Rest (8). The correspondence between the
arguments Rest, 10, Dimes, Rest and the parameters Num, Denom,
Quot, Rem is established by their order of listing from left to right, as
shown in Pseudocode 7.4. The fact that two arguments are the same
variable (Rest) causes no problem. The value of Rest is used to
initialize Num which is divided. When Rem is set to the remainder,
this actually sets a new value in Rest, as illustrated in Pseudocode 7.4.
The third and last call to Divide passes in the Rest, and the constant 5,
and returns the number of Nickels and also of Pennies.
Divide ( Rest,
10,
Pseudocode 7.4
Quot
Rem
8
10
Calls
Divide
320
Chapter 7
Better Blocks
Normally, the examples we have just seen on how to pass parameters should be
sufficient to understand everything about parameter passing. However, you
will need more practice in actually passing parameters to reach complete
understanding. We will look at a few more examples to help you with it. In
fact, many aspects of parameter passing can be illustrated by the familiar
simple Divide subprogram. We will look at some of these aspects here.
Figure 7.24 The subprogram invocation Divide (A, B, C, D)
A
B
C
D
Main
Set
Set
Set
Set
1
2
3
4
0
1
A to 1
B to 2
C to 3
D to 4
Divide (A,B,C,D)
Output A, B, C, D
End Main
1 Num
2 Denom
copy values
main
A
B
C
D
Count
reference variables
Quot
Rem
Writing the output parameter names inside the dotted boxes can
prevent you from making the common mistake of putting values in
the boxes. Remember that passed-out parameters are only
references to actual data spaces. Also, using arrows to match
arguments with parameters can be very helpful.
We will use this simple Main program to see how changing subprogram
arguments can affect output. The Main program contains 4 variables: A, B, C, D.
These 4 variables can be passed in/out of Divide at lease 4 4 4 4 = 256
different ways (such as AABC, AACB, ABCD, ABDC, ACBD, and so on). The
next few examples illustrate some of these variable combinations.
Section 7.3
Parameter Passing
321
Main
Set
Set
Set
Set
A to 1
B to 2
C to 3
D to 4
A 1 2
B 2
C 3 0
D 4
Divide (D,B,A,C)
4
2
copy values
main
D
B
A
C
Num
Count 0
Denom
Output A, B, C, D
End Main
reference variables
Quot
Rem
Num
Denom
Quot
0
Rem
Divide ( B, B, B, D )
In Figure 7.26, the same value of B, which is 2, is copied into both subprogram
parameters Num and Denom. The action of Divide produces a quotient of 1 and
a remainder of 0, as it is dividing 2 by 2. Now Quot also refers to variable B of
the main program, so that value is now changed to 1. The zero remainder is
assigned to variable D of the Main program, and the output is then 1, 1, 3, 0.
In this case, the main programs variable B was actually used twice to copy a
value into Num and Denom, and that same variable B was also referenced by
Quot, and then modified when a value was assigned to Quot. What would
happen if we used the variable B for all 4 arguments? Try it and see.
Note:
In our next example, illustrated by Figure 7.27, the invocation was changed to
Divide(BD , C + B , A , C ) , and the data space for the invocation shows that
expression values can be passed into a subprogram.
322
Chapter 7
Better Blocks
D, C
B D
A
1
3
C+B
Num
Denom
Quot
Rem
Divide ( B D, C + B,
A, C )
11
Num
Denom
Quot
Rem
Divide ( 11, 7, A, B )
Figure 7.28 shows the data space for the next example where the invocation
has become Divide(11, 7, A, B). This shows that constants can be used as
value arguments. Here, 11 is divided by 7 to yield a quotient of 1 and a
remainder of 4. The subprogram quotient Quot refers to variable A and Rem
refers to variable B, so the output is 1, 4, 3, 4.
Figure 7.29 Data space for the invalid Divide (A,B,C,B+D)
A
Num
Denom
??
Quot
??
Rem
Divide ( A, B, 3, B + D )
The invocation Divide(A, B, 3, B + D), Figure 7.29 has two errors. The
problems are:
The third argument is a constant. Arguments passed by reference must
be variables.
The fourth argument is an expression. Again, arguments corresponding
to output parameters can only be variables.
Section 7.3
Parameter Passing
323
So far in this chapter, we have looked at subprograms and the way they
communicate with their environment through parameters. We have identified
methods of passing parameters: by value and by reference, corresponding to oneway and two-way communications. Lets look at a few more examples that
illustrate the following ways of passing parameters:
Passed-in parameters only,
Passed-out parameters only,
Passed-in and passed-out parameters.
Our first example, subprogram Spellout, is shown in Figure 7.30. It outputs some
small numerical values, not as numbers but spelled out as a word. The
pseudocode shown in the figure only spells out integers in the range 0 to 4, but
you could extend it easily. Here only one parameter, theNumber to be spelled
out, is passed into the subprogram . Nothing is passed out. However, the result
of the invocation is the output of a value.
Figure 7.30 Parameter passing
Cost
Quarters
Changer
Nickels
Input Cost
Dimes
Input Quarters Pennies
etc.
Output "Quarter count is "
Spellout (Quarters)
Output "Dime count is "
Spellout (Dimes)
Output "Nickel count is "
Spellout (Nickels)
Output "Penny count is "
Spellout (Pennies)
End Changer
passing in only
Number
Spellout(Number)
Select
Number < 0:
Output Number
Number = 0:
Output "Zero"
Number = 1:
Output "One"
Number = 2:
Output "Two"
Number = 3:
Output "Three"
Number = 4:
Output "Four"
Otherwise
Output Number
End Spellout
The second example in Figure 7.31 shows another subprogram, EnterPos, which
uses an output parameter, passed by reference, to return a value to the calling
program. The subprograms pseudocode shows that EnterPos first prompts the
user to enter a positive value, and then inputs the Value. As long as this Value
is not positive, the subprogram keeps outputting the message Try again and
inputting a new Value.
Figure 7.31 Parameter passing
Age
Height
Opinion Poll
Output "What is the age?"
EnterPos (Age)
Output "What is the height?"
EnterPos (Height)
End Opinion Poll
324
Chapter 7
Better Blocks
Num1
Num2
Num3
D
Sort3 ( A, B, C ) E
F
Input Num1
Input Num2
Input Num3
Sort2 (A, B, D, E)
Sort3 (Num1,Num2,Num3)
Sort2 (D, F, A, B)
Sort2 (E, C, F, C)
End Sort3
A
B
C
Val1
Val2
Temp
Our third example shows why we can refer to parameters passed by reference as
passed in-out or passed through. This may seem a little confusing at first,
but lets take a look at Figure 7.32. Shown is a Main Program which calls
subprogram Sort3. Sort3 sorts three values A, B, C into non-decreasing order
with the help of another subprogram, Sort2.
Sort3s parameters A, B, C are all passed by reference, as we can see by the
underlining. Remember that parameters passed by reference are aliases of
variables from the calling (sub)program. Here A, B, C are all passed by
reference: they are all aliases of some variables. Which variables? Num1,
Num2, and Num3. What is the calling (sub)program? Main Program.
Since A, B, C are aliases of Num1, Num2, and Num3, Sort3 can perform
whatever operations it wants on Num1, Num2, and Num3. In other words,
Sort3 has total control over those variables. When the variable A is called on
for an operation, the value of A used is that of Num1.
So, it is as if we copied this main program value into Sort3 and then performed
the operation on it, as if we were passing values in and out (hence the name inout or through). But we did not really copy it. To actually copy Num1 into
Sort3, we would have to add a parameter passed by value and Sort3 would
look like Sort3(Z, A, B, C) . Sort3 would have to have an extra box labeled Z
in its top left corner. In fact, we could have made Sort3 with 3 parameters
passed in and A, B, and C passed out. Then we could say that parameters are
passed in and passed out (not in-out).
The interesting thing to note here is that when Sort3(A, B, C) is executed, the
original values of Num1, Num2, Num3 are destroyed. Depending on the
problem to be solved, this may be all right. However, it is usually preferable
to pass the values in by value, and then out by reference, for example: Sort3(Z,
X, Y, A, B, C) . This way the original Num1, Num2, Num3 values would be
preserved.
Section 7.3
For a closer look
at Swap, see
Chapter 5,
Figure 5.18.
7.4
Parameter Passing
325
When examining Figure 7.32 closer, you may notice that subprogram Sort2 sorts
two values with the use of 4 parameters: two passed by value and two passed
by reference. This means that it leaves the original values A, and B (which in
turn reference Num1 and Num2) untouched. Sort2 could just as well been
created with only 2 parameters passed by reference (or in-out as we saw
earlier). You may note that Sort2 functions by swapping two values if Small is
bigger than Big. The actual swapping could have been done by invoking a third
subprogram, Swap.
Deductions(Gross, Total)
Set Tax to Rate Gross
GetMiscDeductions(Misc)
Set Total to Tax + Misc
End Deductions
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 employees pay is calculated.
Finally, MainPay outputs the Total amount paid out.
326
Chapter 7
Better Blocks
NetPay(Amount)
Gross
Deduct
ActualPay
Amount
Pay
Deductions(Gross, Total)
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.
2.
3.
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
327
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 dataflow 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
NetPay
Amount Gross
Hours
Pay
Rate
Total
Total
ActualPay
Gross
Num
Deduct
Deductions
Misc
Actual Pay
Total
Number of
Employees
Gross
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 blockseach 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
329
NetPay(Amount)
Num
EmpNum
Total
Pay
Gross
Rate 20%
Tax
Misc
Deductions(Gross, Total)
Total
Amount
The variable access rules introduced in Section 7.3 apply directly to the blocks.
Lets 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 elseby the application of Rule 3. The
same is true of EmpNumthey 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.
Tip:
Notes
ActualPay
Defined
Access
Access
Amount
Defined
Access
Access
Break
Deduct
EmpNum
Defined
Gross
Defined
Access
Access
Access
Access
Access
Global
Defined 1
Access 1
Defined 2
Redefined in Deductions
Hours
Misc
Num
Only in GrossPay
Defined
Only in GrossPay
Defined
Defined
Access
Access
Pay
Defined
Rate
Defined 1
Tax
Defined
Only in Deductions
Access
Global
Only in GrossPay
Defined 2
Defined
Total
Defined 1
Access 1
Access 1
Defined 2
Different meaning in
GrossPa y and Deductions
Only in Deductions
Meaning in Deductions different
to meaning everywhere else.
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
331
Parameter Crossing
A Common Mistake
In order to show how destructive global variables can be, we will look here at a
simple mistake that can turn out to be difficult to trace. Figure 7.39 is yet
another variation of the now famous Divide invocation of Figure 7.24. For the
sake of this example, we replaced the name of the counter Count by C.
Figure 7.39 Forgetting to declare a local variable
Main
Set
Set
Set
Set
A 1
B 2
C 3
D 4
copy values
2
0
A to 1
B to 2
C to 3
D to 4
Divide (B, A, D, C)
Output A, B, C, D
End Main
2
1
Num
Denom
No C!
Quot
Rem
332
Chapter 7
Better Blocks
Pseudocode 7.5
Divide(Num, Denom,
Quot, Rem)
Set Rem to Num
Set C to 0
While Rem Denom
Set Quot to C
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.
Figure 7.41 Tight coupling
Block 3
Block 1
Block 2
Block 4
Section 7.4
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 quicklyalmost 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.
Tip:
334
Chapter 7
Better Blocks
Enter Amounts
InCost
InTend
EnterPos
Convert
Plural
CountOut
Size
CheckProper
Some parts of
ChangeMaker
have already
been developed
in pseudocode in
Chapter 4,
Section 4.4.
A more detailed
SpellOut is
shown in Figure
7.30.
Section 7.4
335
Dates Example
So far, we have always tried to develop our various algorithms using a topdown 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.
Figure 7.43 Developing the algorithm ElapsedTime
ElapsedTime
InputDate(Date1)
InputDate(Date2)
ElapsedDays(Date1, Date2, Elapsed)
Output Elapsed
End ElapsedTime
InputDate(Date)
Input Month
Input Day
MakeDate(Month, Day, Date)
End InputDate
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
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
changedthis 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.
7.5
The Solver
algorithm was
first introduced
in Chapter 6,
Section 6.6.
Self-Referencing Subprograms
Section 7.5
Pseudocode 7.6
337
Solver(problem)
If the problem is a base case
Solve the base case directly
Else
Split the problem into subproblems
For each subproblem
Solver(subproblem)
End Solver
Thus, recursion is a process where a subprogram will call itself. Such a selfreferring 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, lets 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.
Pseudocode 7.7
See Pseudocode
6.10 for more
details on
computing the
square of an
integer.
Iterative Version
Iterative Square(Num, Square)
Set Square to 0
For Count going from 1 to Num by 1
Set Square to Square + 2 Count 1
End Iterative Square
Recursive Version
Recursive Square(Num, Square)
If Num = 1
Set Square to 1
Else
Recursive Square(Num - 1, Square)
Set Square to Square + 2 Num 1
End Recursive Square
Recursive Square calls itself.
Point of return
338
Chapter 7
Better Blocks
Stepping
down a level
If 2 = 1
Else
RecursiveSquare(1, Square)
stepping down
another level
If 1 = 1
Set Square to 1
Set Square to 1 + (2 2 - 1) = 4
Set Square to 4 + (2 3 - 1) = 9
lowest level
stepping back
up one level
stepping back up
another level
Each call of the subprogram yields a contour, resembling levels on a map (stairtrace). 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.
See Section 7.3
for more details
on returning
control to the
caller.
Functions
See Figure 5.42
for more details
on Convert
Seconds.
Section 7.5
Pseudocode 7.8
339
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.
Pseudocode 7.9
340
Chapter 7
Better Blocks
Modules
Modules are black boxes. Think of them as walls that surround a part of a
program. These walls enclose (or hide) data, and clearly separate the inside of
the module from the outside. Communication between the inside and the
outside is totally under the control of the programmer.
The major use of modules is to provide a method for breaking up a large program
into semi-independent pieces related by well-defined and simple interfaces.
The resulting modular structure is easier to document, analyze, modify and
maintain. It is also less prone to errors.
An important use of modules is for the creation of libraries of related
subprograms. In most systems, there are typical libraries of mathematical
functions, input/output operations, and others. Libraries can be viewed as
building blocks to be used without knowing the details within them. These
library modules can also make use of other modules.
Generally, the information that is provided to the programmer is a brief
description of what the module does, not how it does it. Programmers do not
need to know how the library module performs its function in order to be able to
use it. We have come back full circle to the idea introduced in Chapters 2 and 3,
that of structuring a solution with black boxes.
Section 7.6
7.6
Review
341
2.
3.
4.
5.
6.
7.
8.
9.
342
Chapter 7
Better Blocks
10.
Section 7.7
7.7
Glossary
343
Glossary
Alias: An identifier that refers to a
variable that is also known by
another name. For example, the
name of a parameter that is passed
by reference; since it refers to a
variable in the calling program, it is
an alias for that variable.
Argument: A variable, expression or
constant that is passed to a
subprogram in the invocation
statement.
Base case: The special case in a
recursive subprogram that causes the
recursion to terminate.
Binding: The association of a name
with a data value.
Block structure: The hierarchical
arrangement of the subprograms that
comprise a program.
Cohesion: The quality of a program
that refers to the degree that all
statements in the subprogram are
concerned with the same objective.
Coupling: The quality of a program
that refers to the degree of
interconnection of the constituent
subprograms.
Function: A subprogram that returns a
single data value through the
execution of a return statement.
Global data: Data that are known
throughout the program.
Julian date: The ordinal of the given
data in the year.
Loosely coupled: A program in which
all the subprograms have the
minimum number of interconnections.
Parameter: A name that is local to a
subprogram and is used to refer to the
arguments in the subprograms
invocation.
344
Chapter 7
7.8
Problems
Better Blocks
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
Main
Input A
Input B
N(A, C)
P(C, B, E)
A
B
C
A
B
P(A, B, C)
Set C to A B
End P
Q(A, B, C)
N(B, D)
N(A, D)
P(A, D, F)
N(B, E)
Q(E, F, G)
P(D, E, F)
Output G
N(F, C)
End Main
3.
A
B
C
D
E
F
G
A
B
N(A, B)
Set B to 1 A
End N
D
E
F
End Q
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.
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:
6.
1.
2.
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.
5.
If D = (5Y Div 4) - X - 10 then March ((-D) Mod 7) is a Sundayif (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.
9.
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.
8.
e.
f.
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.
Divide Again
For the previously defined Divide subprogram and the following Main
Program,
Section 7.8
Problems
347
Problem 10
Main Program
Set A to 1
Set B to 2
Set C to 3
Set D to 4
Divide(
Output A
Output B
Output C
Output D
e. Divide(A, B 2, C, D)
b. Divide(A, B, A, B)
f. Divide(0, 1, 2, 3)
c. Divide(A, A, B, B)
g. Divide(0, 1, B, B)
d. Divide(B C, A D, A, D)
11.
Non-Divide Passing
Indicate the output of the following program if the input values are 1,
2, 3 in that order.
Problem 11
A
B
C
Main Program
Input A
Input B
Input C
Sub(A, B)
Output A
Output B
Output C
End Main Program
Sub(D, C)
Set B to C + D
Set D to B + C
Set C to B + A
Set A to A + C
End Sub
C
Indicate the output if the subprogram call (in the main program) were changed
in each of the following ways:
(Note: The input values are still 1,2,3 in that order. Hint: Use the contour
diagram!)
a. SUB(A, C) (Answer: 6, 2, 5)
d. SUB(B, C)
b. SUB(B, A) (Answer: 8, 2, 3)
e. SUB(C, A)
c. SUB(C, B) (Answer: 7, 6, 3)
f. SUB(B, B)
Recursive Power
Create a recursive subprogram to compute the Nth (positive) power of
X.
348
Chapter 7
Better Blocks
13.
14.
Section 7.8
Problems
349
350
Chapter 7
Better Blocks
Section 7.8
Problems
351
352
Chapter 7
Better Blocks
Section 7.8
Problems
353
354
Chapter 7
Better Blocks
Section 7.8
Problems
355
356
Chapter 7
Better Blocks
Chapter Outline
357
Chapter Outline
8.1
8.2
8.3
8.4
8.5
8.6
8.7
8.8
8.9
Preview....................................................................358
Arrays......................................................................358
What are Data Structures Anyway?..........................358
One-Dimensional Arrays...........................................360
Performing Operations on One-Dimensional Arrays....361
Using One-Dimensional Arrays in Algorithms...........364
Two-Dimensional Arrays..........................................367
Performing Operations on Two-Dimensional Arrays...370
Matrix Multiplication...............................................373
N-Dimensional Arrays..............................................375
Records.....................................................................377
What are Records?....................................................377
Accessing Record Components the Dot Notation........380
Combining Arrays and Records...................................382
Sets..........................................................................384
What are Sets?.........................................................384
A Difficult Sets Example (optional)..........................386
Data Structure Building Tools....................................392
Dynamic Variables...................................................392
Pointers....................................................................392
Abstract Data Types.................................................397
Strings......................................................................399
Stacks.......................................................................401
Queues......................................................................405
Trees.........................................................................407
Review Top Ten Things to Remember........................408
Glossary...................................................................409
Problems...................................................................410
358
8.1
Chapter 8
Data Structures
Preview
In this chapter, we consider the following three basic data structures. These
data structures are created by grouping together smaller items to form larger
items. These three data structures in turn are used to create larger ones in the
next chapter.
Arrays(also called vectors, tables, matrices, n-dimensional lists, and
subscripted variables) are homogeneousgroupings of items all items
are of the same kind. The items within the arrays are accessed by way
of indices. Tables, or arrays having two indices, are common, and will
be considered here. Arrays of three and more indices are less common, so
they will be considered only briefly.
Recordsare very important data structures. They differ from arrays in
that they are groupings of possibly heterogeneouselements (items of
different kinds), whereas arrays are groupings of homogeneous
elements. Also, values are not accessed by using indices, but by using
names for the elements and a dot notation.
Setsare homogeneous collections of distinct elements where the only
relation between elements is that they are either in a set or not in it.
Sets are very useful in a number of applications.
Although arrays, records and sets are very useful in many applications, they
all have one major restriction: their size is static or set at some fixed maximum
value. Because of this, they cannot represent data whose detailed structure or
size are unknown when the program is written. Data structures to represent such
unknown data can be built during program execution through dynamic
variables and pointers. An example with linear lists of undefined length is
used to show how these dynamic variables and pointers can be used.
The chapter also introduces the concept of an abstract data type, which is
defined through its values and operations. Other data structures important in
computer science, like linear lists and trees, are also briefly introduced.
8.2
Arrays
What are Data Structures Anyway?
A data structure is a collection of related items organized in a certain fashion.
It enables us to consider all of the related items as one entity. For example, a
data structure could consist of apples, bananas, and oranges. Notice that these
three items are related and organized alphabetically. They could have been
organized some other way. The important thing to remember is that, because
we are talking about a data structure, we can refer to the whole of these items,
in our case, fruit. Arrays
Data structures range from simple (like the fruit above) to very complex. They
can be viewed in many ways, as shown below.
Section 8.2
Figure 8.1
Arrays
359
Parts of a chair
Parts of Chair
Leg: 2 per chair
Seat: 1 per chair
Rung: 3 per chair
Back: 1 per chair
Attributes of Parts
Price
Quantity
ReOrdered
Status
Size
Etc.
Chairs inventory
Seat
Record
Price
$ 2.50
Quantity
100
Reorder
yes
Status
Table
list of attributes
for each part of
the chair
list of attributes
for the seat of
the chair
Part
Price
Quantity Reorder
Status
Leg
Seat
$ 1.12
$ 2.50
200
100
no
yes
A
C
rung
Back
$ 0.75
$ 3.00
400
300
no
no
B
A
We can make a list of attributes for each part of the chair, as in the lower part
of Figure 8.2. Here, the parts are listed vertically in the left column. The
various attributes (Price, Quantity, etc.) are shown as columns. Each part
corresponds to a row. This representation is called a table. Each row of this
table corresponding to a part is called a record. Each column corresponding to an
attribute is called a f i e l d . In our example, Seat is a record and Quantity is a
field.
Now that you have seen what data structures are, you are ready to discover the
different kinds of data structures used in computer science. In this chapter,
three basic types of data structures are introduced: arrays, records, and sets.
One-Dimensional Arrays
The first type of data structure introduced is an array. An array is a
homogeneouscollection of componentsall the components are of the same kind.
The simplest arrays are linear: they have only one dimension and are called
vectors, n-tuples, single subscripted variables, or more simply, one-dimensional
arrays. An example of such a one-dimensional array is shown in Figure 8.3.
360
Chapter 8
Data Structures
Figure 8.3
name of
array
values in
array
index
Time
12:24
8:55
15:12
2
3
22:30
10:28
4
5
3:45
11:00
6
7
This Time array could represent various times (using the 24-hour
representation) at which a given event will happen over a weeka period of
seven days. An array is also sometimes called an indexed variable, for the
following two reasons:
(i)
(ii)
You may have seen indices used in mathematics in the form of subscripts like
this:
Time 1, Time 2, Time 3, Time 4, Time 5, Time 6, Time 7
In most programming languages the index is written within square brackets as:
Time[1], Time[2], Time[3], Time[4], Time[5], Time[6],
Time[7]
In Figure 8.3, Time [1] refers to 12:24. Generally, the names chosen for indices
can be meaningful in the context of the application being programmed. For
example, we could replace Time [1] by Time[Monday].
Figure 8.4 illustrates another one-dimensional array, giving the body
temperature of a patient, recorded every hour of the day. Temperature[3]
represents the temperature recorded at Hour 3.
Figure 8.4
Temperature vector
Hour
1
Temperature
98.6
2
3
100.0
101.1
23
99.0
24
99.6
Figure 8.5 shows yet another example of a one-dimensional array; this one
stores the grades of all the students in a class. Grades[StudentID] represents
the grade earned by the student whose ID is given by the value of StudentID.
Figure 8.5
Student ID
1
Grades
A
2
3
C
B
34
35
Section 8.2
Arrays
361
Story vector
Position
1
Story
O
2
3
n
c
e
4
5
6
9998
9999
n
d
10000
Similarly, we can retrieve a value from position Position of array Vector and
assign it to variable Value by:
Pseudocode 8.2
We can use these indexed variables anywhere a simple variable can be used, as
in the following statement which computes a running average of 3 adjacent
vector components.
Set Average[Index] to (Vector[Index
1]+Vector[Index]+Vector[Index+1])/3
See Chapters 3
and 5 for a
refresher on the
operations
possible for
different data
types.
An array component can be used in all the operations compatible with its type.
In other words, if an array component is of type Integer, then we can apply
Integer operations to it. Above and beyond these operations, we sometimes need
operations on entire arrays. An example of such an operation might be the input
of an entire array. This input can be done in several ways. For example, lets
input seven times into the Time array from Figure 8.3. One way to do this, is to
use seven input statements, one for each index, as illustrated in Pseudocode 8.3.
362
Chapter 8
Data Structures
Pseudocode 8.3
Input Array 1
Input Time[1]
Input Time[2]
Input Time[3]
Input Time[4]
Input Time[5]
Input Time[6]
Input Time[7]
End Input Array 1
Input Array 2
For Index = 1 to 7 by 1
Input Time[Index]
End Input Array 2
Such input methods are not general, since we have to know how many entries we
need to make ahead of time.
For more details
on using a
terminating
value, see
Chapter 6,
Figures 6.4 and
6.5.
A more general method is shown below. You do not need to know the number of
entries ahead of time anymore. We accomplish this by using a terminating
value(or end-of-data marker), Sentinel, to detect the end of the entries. Input
Array assigns the input values to consecutive entries of the array, counting the
number of entries made. After the loop terminates, the final value of Count is
assigned to the variable Size, so that now we know how many entries were
made.
Pseudocode 8.5
See Chapter 7 to
brush up on
subprograms.
Clearly this method is more suited to large arrays or arrays whose size varies.
Once the data have been put into the array, the Size is known. We can write
the pseudocode to output this array with one a simple loop:
Pseudocode 8.6
In the rare case where this Size is not known, we would have to make use of a
more complex loop with an end-of-data marker.
Using the Temperature array of Figure 8.4, lets develop an algorithm to find
the maximum temperature in the day by inspecting the values stored in the
vector. This algorithm must also indicate the position (Hour) of the first
Section 8.2
Arrays
363
This outline can now be refined to the final solution. The first value of the
array is taken as the temporary Maximum. One by one, the other values are
compared to the Maximum and the first largest value encountered is kept.
Pseudocode 8.8
Change Maker 1
Input Tendered
Input Cost
Set Change to Tendered - Cost
While Change 25
Output a quarter
Decrement Change by 25
While Change 10
Output a dime
Decrement Change by 10
While Change 5
Output a nickel
Decrement Change by 5
While Change 1
Output a penny
Decrement Change by 1
End Change Maker 1
364
Chapter 8
Data Structures
Pseudocode 8.10
Change Maker 2
Input Tendered
Input Cost
Set Change to Tendered Cost
Set Coins[1] to 25
Set Coins[2] to 10
Set Coins[3] to 5
Set Coins[4] to 1
For Index = 1 to 4 by 1
Set Value to Coins[Index]
While Change Value
Output Value
Decrement Change by Value
End Change Maker 2
replaces sequence
of While loops
The new Change Maker 2 algorithm, outlined above, uses an array, Coins,
which contains the denominations 25, 10, 5 and 1 in order. As the for loops
counter, Index, goes from 1 to 4, the variable Value is assigned the
corresponding array values (first 25, then 10, 5, and 1), and the change
corresponding to this Value is computed and output.
Actually the output of Change Maker 2 is not exactly the same as the output of
Change Maker 1. Change Maker 1 outputs quarters, dimes, nickels and
pennies, while Change Maker 2 will output numerical values. It is not
difficult to modify this second version so that its output is identical to the
output of the first version. We will let you do it.
Change Maker 2 is not only shorter than the previous versions of Change
Maker, but most important, it can be modified more easily. Extending it to
apply to more denominations (such as 5 dollar bills, 10 dollar bills, 20 dollar
bills, and even 2 dollar bills) requires only a slight change in the array values
(as well as the size of the Coins array). This algorithm could also be easily
modified to make change in any foreign currency.
Another very common use of arrays is to store numerical data so that the values
are available for repeated access. For example, Figure 8.7 shows the
computation of the variance of a set of numbers.
Figure 8.7
Variance
a first approach
Array to input
Mean
I
1
A[I]
30
2
3
20
40
10
N=4
Sum = 0
14
T
Sum = 30
24 34 44
T
T
T
50
90
100
54
F
Mean = 25
Total = 0
14
T
Total = 25
2 4 34 4 4
T
T
T
50
275
54
F
500
Variance = 125
Section 8.2
Arrays
365
The algorithm of Figure 8.7 requires the calculation of the mean of the numbers
before it can compute their variance. This forces it to make two passes over
the array components, first to compute the mean and then to compute the
variance.
There is another method for computing the variance. This method, shown in
Figure 8.8, does not need to compute the mean first, so only one pass over the
array components is necessary. It is always useful to approach a problem two
different ways, as we have done here. Doing so can help us choose more
efficient solutions like the one in Figure 8.8.
Figure 8.8
Variance
another way
N=4
Sum = 0
Total = 0
14
T
For K = 1 to N by 1
Set Sum to Sum + A[K]
Set Total to Total + A[K] 2
24 34 44
T
T
T
54
F
Sum = 30
50
90
100
Total = 900 1300 2900 3000
Mean = 25
Variance = 125
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.
Figure 8.9
A general array
array name
Matrix
A[I, J]
J
I
1 2
1
2
3
row indices
4
5
3 4
column indices
N
A[2, 3]
A[3, 2]
A[4, 4]
A[M, N]
This element is
found by looking
at the intersection
of row 2 and
column 3.
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.
Figure 8.10 A 4
Q
P
Grades[P, Q]
1
40
60
80
70
30
80
100
100
100
80
60
40
N=3
Grades[2, 3]
Grades[3, 2]
M=4
Charge[Adults, Kids]
Column
Row
1
1
2
3
Kids
2
X
Adults
1
2
3
0
1
2
3
3.00 5.00 7.00 9.00
6.00 8.00 10.00 12.00
9.00 11.00 13.00 15.00
Notice that the values within each of our example arrays are all of the same
kind: the grades are all percentages, the game positions are all characters, the
admission charges are all money values.
We saw in the last section how to scan values into a one-dimensional array.
Lets look at how it is done for a two-dimensional one. The following algorithm
shows how the items of Figure 8.12 can be scanned row by row.
Section 8.2
Arrays
367
10
11
12
Row Traversal
For First Index = 1 to 4 by 1
For Second Index = 1 to 3 by 1
Output Table[First Index, Second Index]
End Row Traversal
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. Lets take a look at the trace of the indices of Row Traversal:
Figure 8.13 Trace of indices from Figure 8.12
First Index = 1 1 1 2 2 2 3 3 3 4 4 4
Second Index = 1 2 3 1 2 3 1 2 3 1 2 3
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.
Pseudocode 8.11
Input Matrix
Input Rows
Input Columns
For First Index = 1 to Rows by 1
For Second Index = 1 to Columns by 1
Input Value
Set Table[First Index, Second Index] to Value
End Input Matrix
368
Chapter 8
Data Structures
Day
1
2
3
1
98.6
100.0
100.1
23
24
99.0
98.6
Hour
Original vector
Weekly Average
Set Sum to 0
For Day = 1 to 7 by 1
For Hour = 1 to 24 by 1
Set Sum to Sum + Temperatures[Hour, Day]
Set Average to Sum / (24 7)
End Weekly Average
Here we sum
the hours one
day at a time.
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
2 different
arrays
Averages
40
60
80
70
30
80
100
100
100
80
60
40
72.5
62.5
75.0
Average Quiz
For all columns
Set Sum to zero
Sum Grade in column
Set Average[Column] to (Sum/Number)
End Average Quiz
Averages are stored in another array.
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.
Lets refine this algorithm by defining how the accumulation of the grades is
done.
Pseudocode 8.14
Average Quiz
For Column = 1 to 3 by 1
Set Sum to zero
For Row = 1 to 4 by 1
Increment Sum by Grades[Row, Column]
Set Average[Column] to Sum / 4
End Average Quiz
Summing each
column, to find
its average.
370
Chapter 8
Data Structures
0.2
0.3
0.5
Final Grades
40
60
80
66
70
30
80
63
100
100
100
100
80
60
40
54
initial arrays
Grades P Q
resulting array
Weighted Averages
For Row = 1 to 4 by 1
Here we sum by row,
instead of by column.
Set Sum to zero
For Column = 1 to 3 by 1
Increment Sum by Grades[Row, Column] Weights[Column]
Set Final Grades[Row] to Sum
End Weighted Averages
Now that we have seen how to add and multiply parts of arrays, lets 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].
Figure 8.17 Array addition
Array Addition
A[I, J]
The 3 shaded
values are all in
the same [1,1]
position.
B[I, J]
5
+
3
C[I, J]
6
10
12
=
7
Array Addition
For Row = 1 to Number of rows by 1
For Column = 1 to Number of columns by 1
Set C[Row, Column] to A[Row, Column] + B[Row, Column]
End Array Addition
Section 8.2
Arrays
371
It is important to note that only arrays of the same dimensions can be added
together.
Figure 8.18 Invalid array addition
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.
Figure 8.19 Mechanism of matrix multiplication
A
Notice that here
the two arrays
need not be of
the same
dimensions. The
rule of
dimensions is
shown in Figure
8.20.
.......... r
...
... n
b1j
b2j
..
.
..
.
..
.
..
.
..
.
a i1 a i2
a ir
...
... n
c ij
..
.
m
ai1 ai2
b1j b2j
..
.
air
+
brj
Note
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
... R
1 2
1
2
3
4
1 2
... N
1
2
.
.
.
.
.
..
.
.
.
= ..
.
R array
N array
... N
1
2
3
4
M N array
8 11
50 62
Example
0 1 2
3 4 5
3 array
6 7
8 9
0 1
2 array
3 6 + 4 8 + 5 0 = 50
2 array
Matrix Multiplication
For Row = 1 to Matrix 1 Rows by 1
We take it one
row at a time.
For Column = 1 to Matrix 2 Columns by 1
Set Sum to zero
For Index = 1 to Matrix 1 Columns by 1
Increment Sum by A[Row, Index] B[Index, Column]
Set C[Row, Column] to Sum
End Matrix Multiplication
N-Dimensional Arrays
Lets 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, lets 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 arrayswe 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
Hour
Layer 2 represents
the 2nd week of
temperatures.
Week
Layer 1 represents
the 1st week of
temperatures.
Monthly Average
Set Sum to 0
For Week = 1 to 4 by 1
added loop
For Day = 1 to 7 by 1
For Hour = 1 to 24 by 1
Set Sum to Sum + Temperatures[Hour, Day, Week]
Set Average to Sum / (24 7 4)
End Monthly Average
8.3
Records
What are Records?
Remember that an array is a homogeneouscollection of components; all
components of the same kind. A record is a heterogeneouscollection of
components. In other words, the components may be of different kinds. A record
is a compound data structure consisting of a number of components, usually called
fields. Think of a record as a template that outlines each of the records fields.
374
Chapter 8
Data Structures
Date
Date
generic
record name
field name
Full Record
(Instance)
MoonDate
Year
Year
Month
Month
Day
Day
20
1969
specific record
name
field values
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.
Figure 8.23 The Ace of Spades card record
Ace of Spades
Card
Suit
Rank
Spade
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.
Figure 8.24 A Complex Number record
3 + 4i
Complex Number
Real
Part
3.0
Imaginary
Part
4.0
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
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.
Figure 8.26 Joe Kings student record
Joe King
Student
ID
1234
Sex
Male
Birth Date
Grade
3.14
Year
Status
Birth Date
Month
Day
1969
7
20
376
Chapter 8
Data Structures
Book
ISBN
Name
0-1234-56789
John Marcobrini
Address
Title Practical Programming
Price
Street
23.45
Author
Received
Date
300 Main
City
Northridge
State
California
ZipCode
91324
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.
Record components are accessed by using a special dot notation. For instance,
the value in the Title component of the Book record in Figure 8.27 is indicated
by the following:
Pseudocode 8.19
Book.Title
record name
record component
For example, consider the two students named Joe and X described in Figure 8.28.
Joes identification number is written Joe.ID and Xs 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.
Pseudocode 8.20
Section 8.3
Records
377
Sue
Student
Student
ID
12345
ID
Sex
Male
Sex
Grade
3.14
Grade
2.17
Status
Status
Birth Date
Year
Month
Day
98765
Female
Birth Date
Year
1969
7
20
1972
Month
Day
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:
Pseudocode 8.21
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:
Pseudocode 8.22
Joe.Spouse.BirthDate.Year
Joe.Address.Street.Number
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.29 Assigning values to entire subrecords
This simple statement replaces the 3 shown at right.
equivalent
Figure 8.30 shows how one of the components of a chair can be described for
inventory purposes.
378
Chapter 8
Data Structures
1234
Price
0.56
Quantity
789
Length
Feet
Inches
Eighths
Size
Length
Diameter
Size
Brand
R
Brand
Phono
Phono
Area Code
123
Prefix
456
Suffix
7890
Etc.
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 suppliers 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 Rungs 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.
Section 8.3
Records
379
Projects
1
2
C
B
3
4
A
A
5
6
B
A
2 arrays nested
in the record
Quizzes
1
2
87
66
3
4
92
70
Records of arrays are simply records whose components are arrays. For
example, Figure 8.31 shows a Pupils 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]
Figure 8.32 Array of records
Workers
Worker[1]
Worker[2]
Worker[3]
40
10
Hours
Rate
50
Hours
10
Rate
20
15
Hours
Rate
168
10
Hours
Rate
array
record nested
in the array
...
Worker[N]
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 onedimensional 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
What are Sets?
In mathematics, sets are collections of items where each item appears only
once. The order of the items is immaterial and the size of the sets may be
infinite. In computer science, we use a similar definition except for the fact that
set sizes cannot be infinite. They also are implementation dependent. Sets are
usually represented using braces as in {2, 4, 6, 8}, or { } for the empty set.
Operations on sets are the usual mathematical set operations: membership,
union, intersection, and difference.
Set membership is denoted by the symbol as in:
1 {1, 2, 3, 4, 5} and 1 {2, 4, 6, 8}
The union of two sets A and B is the set comprising all elements in A and
B, and is denoted by the symbol as in A B, and is illustrated by
Figure 8.33.
Figure 8.33 Set union
A
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.
Figure 8.34 Sets intersection
A
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.
Figure 8.35 Difference of sets
A
Lets look at a few examples to illustrate the various set operations. First, lets
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
382
Chapter 8
Data Structures
{1, 2}
{2, 3}
{2, 3, 4}
{1, 5, 6}
{3, 6}
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:
Pseudocode 8.23
Build Timetable
Get registration data
Find the Conflicting Courses
Build sets of Non-conflicting Courses
End Build Timetable
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
Pseudocode 8.24
Sets
383
Here we set up a
Find Conflicting Courses
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
student at a time.
If Course Num Registration[Student ID]
Set Conflicts[Course Num] to Conflicts[Course Num]
Registration[Student ID]
End Find Conflicting Courses
After
Student 3
After
Student 4
After
Student 5
{1, 2}
{1, 2}
{1, 2, 5, 6}
{1, 2, 5, 6}
{1, 2, 3}
{1, 2, 3, 4}
{1, 2, 3, 4}
{1, 2, 3, 4}
{2, 3}
{2, 3, 4}
{2, 3, 4}
{2, 3, 4, 6}
{}
{2, 3, 4}
{2, 3, 4}
{2, 3, 4}
{}
{}
{}
{1, 5, 6}
{1, 5, 6}
{}
{}
{}
{1, 5, 6}
{1, 3, 5, 6}
Initial
After
Student 1
{}
{1, 2}
{}
{1, 2}
{}
{}
{}
{}
{}
{}
After
Student 2
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 concurrentlybecause 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.
Note
384
Chapter 8
Data Structures
Pseudocode 8.25
Courses
Initializing Unscheduled.
Still to be defined.
The first three lines of this algorithm find the lowest numbered course in
Unscheduled and set Course Num to that value. Lets put these two pieces of
pseudocode together (Figure 8.38).
Section 8.4
385
Sets
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.
Figure 8.39 Trace of Session 1 generation
Session 1
Unscheduled
{1, 2, 3, 4, 5, 6}
Course Num
Session
{1}
Trial Set
Test Course
1, 2
1, 2 {3, 4}?
False
3 {3, 4}?
True
Session
{1}
{1, 3}
{1, 3}
Unscheduled
{2, 4, 5, 6}
Course Num
Session
{2}
Trial Set
Test Course
1, 2, 3, 4
We've already
scheduled courses
1 and 3, as shown
in Figure 8.35.
5, 6
{2, 3, 4, 6} {2, 3, 4}
{1} = { }? {1, 3} = { }?
True
False
Session
{2}
6
6 {5, 6}?
True
{1, 5, 6}
{2} = { }?
True
{1, 3, 5, 6}
{2, 5} = { }?
False
{2, 5}
{2, 5}
{1, 3}
386
Chapter 8
Data Structures
Unscheduled
{4, 6}
Course Num
Session
Trial Set
Test Course
We only have
2 courses left
to schedule.
{4}
{4, 6} - {2, 3, 4} = {6}
1, 2, 3, 4, 5
False
6 {6}?
True
{1, 3, 5, 6} {4} = { }?
True
Session
{4}
{4, 6}
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.
Lets 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
1
2
3
4
5
8.5
Section 8.5
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?
Lets 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.
Figure 8.42 Pointers in a dynamic list
List1
Pointer
Item 1
Item 3
Item 4
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.
Figure 8.43 Two parts of an element record
Part 1: an item
Item 1
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.
Figure 8.44 A sample list element record
Sample list element record
Name
Age
Item
Height
Pointer to Next
Item 1
Pointer
388
Chapter 8
Data Structures
The element record in Figure 8.44 has three information fields: Name, Age,
and Height. Our last field is the pointer to the next element. Using this sample
element record, we could redraw Figure 8.42, now specifying the content of the
Item parts (Figure 8.45).
Figure 8.45 A simple dynamic list of linked element records
List1
Name
Name
Name
Name
Age
Age
Age
Age
Height
Height
Height
Height
Pointer
to Next
Pointer
to Next
Pointer
to Next
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, lets 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
389
List Creation
Set List1 to New(Element)
Input Item 1
Set List1 Information fields to Item 1
Set List1 Next to New(Element)
Input Item 2
Set List1 Next Information fields to Item 2
Set List1 Next Next to New(Element)
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
List 1
Input Item 1
List 1
Item 1
A
B
List 1
Item 1
A
B
A
B
List 1
A
B
Input Item 2
List 1
Item 2
C
D
A
B
List 1
Set List1 Next
Information fields to Item 2
Item 2
C
D
A
B
C
D
A
B
C
D
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
Pseudocode 8.28
391
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
so that it always refers
Set Current Next to NIL
to element being added.
End List Creation
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).
8.6
For a computer
to do this
conversion, we
would need an
algorithm like
the one called
Time difference
in Chapter 5,
Figure 5.43.
If we converted 8:33 a.m. into the total number of minutes elapsed since
midnight, when the day started, we could then represent it as an Integer. For
example, 8:33 a.m. would become 8 60 + 33 = 480 + 33 = 513 minutes.
Time is one of those real-world objects that is hard for a computer to
manipulate. Other real-world objects include names, dates, money, and
meteorological data. Luckily, objects like money are easily represented by
Integers. However, as we have seen above, Time is not easily represented by
either Integers or Real Numbers. We need a data type that more closely models
time as it is used in the real world.
392
Chapter 8
Data Structures
Results
Real-World
Objects
and
Operations
Real-World
Algorithm
Human or
electro-mechanical
interpretation of
results
Conversion to the
computer model
by the programmer
Programming
Language
Objects and
Operations
Real-World
Objects
Computer
Algorithm
Computer
representation
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 realworld objects that cannot easily be modeled with these types, we need to
define new types ourselves, called Abstract Data Types.
Section 8.6
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.
Abstract data type Strings
Values
Sequences of characters
Here are a few examples (we will enclose strings in double quotation
marks).
February 29, 1984
F
For a view of your results, press Enter
Operations
Operation
Example
Explanation
Input
---
Output
---
quantity.
Assign
394
Chapter 8
Data Structures
Concatenate
Set StringC to
Concat(StringA,
StringB)
Count
Search
Insert
Set StringD to
Insert(StringC,
XYZ, 3)
Extract
Set StringE to
3)
Delete
Substring(StringD, 2,
Set StringF to
DeleteString(StringD,
2, 3)
Compare
If Less(Month1, Month2)
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
395
Stack operations
Push
X
Pop
Last one in is
first one out.
Y
8
Top
9
First item
entered
Bottom
Create
Push (X)
Pop (Y)
Is Empty
Is Full
Depth (Z)
396
Chapter 8
Data Structures
S2
S
T
O
P
S
SPOTS
STOPS
Input
EQ
Pour
False
STOPS
S
S1
S3
Input Character
While Character Terminator
If Character ' '
Push Character onto S1
Push Character onto S2
Input Character
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.
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
Pseudocode 8.31
397
2
3
4
Adder
4
1 234
Input
56 789
Input
Digit1
Sum
Output
5
Digit2
8
9
Carry
Carry
0
2
S4
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.
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.
398
Chapter 8
Data Structures
Pseudocode 8.32
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.
Queue
Enter
Exit
3
Rear
Front
Section 8.6
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.
Abstract data type Queues
Values
All of the values of the Queue element type
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.
Queues are used in a great number of computer science applications. They are
needed in all operating systems, to keep track of the various processes that are
active at a given time, and to help allocate the computer resources in an
optimal manner. Queues are also used in all simulation applications.
Simulation is an important field of computer science in which models of various
systems of the physical world are developed. These models help us to better
understand the behavior of complex systems, without having to develop or
alter the real thing.
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.
Figure 8.52 A tree
A - (B + C)
root node
root node
node number
leaf node
leaf node
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
8.7
Review
401
2.
Arrays give a common name to the items they group, and make it
possible to access the different components via indices, and a bracket
notation. One-dimensional arrays are quite common and easy to use.
3.
4.
5.
Records may consist of other records or arrays, and in turn may be part of
other records or arrays. This combination of structures is very powerful
and leads to very useful structures like arrays of records or records of
arrays, and so on.
6.
7.
In computer science, sets are a form of the familiar and useful concept
found in mathematics. The elements of a set are homogeneous, like in
arrays, but the operations on sets are very different. The set operations
include Membership, Union, Intersection and Difference.
8.
9.
Abstract Data Types are defined by the values they represent and the
operations that can be applied to these values. In this chapter, we
defined the following three Abstract Data Types:
Strings,: a sequence of characters that is viewed as one single item,
Stacks,: an ordered collection of items, where the last item placed
in a stack is the first one out (LIFO), and
Queues,: an ordered collection of items, where the first item placed
in a queue is the first one out (FIFO).
10.
402
Chapter 8
8.8
Glossary
Data Structures
Section 8.9
8.9
Problems
403
Problems
1.
Mystery
What does the following algorithm do?
Problem 1
A[I]
For Index = 0 to N by 1
Swap A[Index] and A[N - Index]
0
1
2
3
4
N
2.
404
Chapter 8
Data Structures
3.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* *
* *
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
10.
Problems
405
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
12.
Scale Time
Given a table indicating the time T[I, J] to travel between points I and J
in hours, create an algorithm to convert this time to minutes.
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].
University Record
Create a record of a university. It is described by a name, enrollment,
age, ZIP code, and phone number (having three parts: Area code,
Prefix, and Suffix). The university is also classified as being Private or
Non private.
Write a program to search an array of such universities and output the
names of all those within a given telephone area code.
20.
Play Record
Create a record describing a card game, such as Bridge or Poker, and
indicate various actions which could be performed on such an item.
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
22.
1
2
2
3
5
0
0
A
0
B
Bar Plot
Create an algorithm that draws an histogram (bar plot) where values
are plotted in proportion to some values (given in an array). Do this
Section 8.9
Problems
407
first with the bars plotted horizontally, then again with the bars
plotted vertically.
23.
408
Chapter 8
Data Structures
Section 8.9
Problems
409
410
Chapter 8
Data Structures
Section 8.9
Problems
411
412
Chapter 8
Data Structures
Section 8.9
Problems
413
414
Chapter 8
Data Structures
Chapter Outline
415
Chapter Outline
9.1
9.2
9.3
9.4
9.5
9.6
9.7
9.8
Preview....................................................................416
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
More Complex Sorting...............................................428
Improving Sorts.........................................................428
Recursive Sorts..........................................................432
Searching.................................................................435
Linear Searching.......................................................436
Binary Searching......................................................437
Pattern Matching......................................................438
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
Review Top Ten Things to Remember........................451
Glossary...................................................................453
Problems...................................................................454
416
Chapter 9
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
General Sorting Strategies
Sorting is an extremely common operation in computer applications. Sorting is
the process of putting items in sequence according to some criterion (e.g.
numerical order, or alphabetical order, etc.). The sorted items can be small,
like numbers, letters or character strings, or large records, like a library catalog
where each record contains a lot of information about a book. The items of data
are sorted in increasing or decreasing order of a specific field called the sort key
(numerical or alphabetical). The small sorts that we have seen in Chapter 7,
Sort2 and Sort3, worked with a fixed number of items. Now, we want to be
able to sort any number of items stored in an array.
The sorting process can operate according to three different strategies, as
illustrated in Figures 9.1, 9.2 and 9.3. We will assume that we want to sort
numbers in decreasing order here.
Figure 9.1
General Method
A1
A2
Example
A3
...
An
21
12
54
A1
A2
A3
B2
B3
...
48
...
An
B1
B2
B3
54
52
48
...
Bn
12
sorted
items of
array A
Section 9.2
Sorting
417
A1
A2
A3
...
An
23
11
90
A1
A2
A3
R2
R3
...
47
...
An
R1
R2
R3
18
11
...
Rn
positions of
sorted items
22
A1
A2
Sort in place
A3
...
An
Sort in place
A1
A2
A3
...
11
45
99
A1
A2
A3
78
...
An
A1
A2
A3
99
78
69
...
An
sorted items
11
418
Chapter 9
2.
3.
4.
We will illustrate these basic sorting methods with specific algorithms in the
following sections. In order to simplify the algorithms, we assume that we will
sort positive, non equal integer values into decreasing order. These algorithms
can be modified very easily to sort character strings in alphabetical order. To
illustrate the workings of our algorithms, we will use the first nine decimal
digits as the sequence of numbers to be sorted. The original sequence is as
follows:
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
Figure 9.4
419
Sorting
Count Sort
Before
A[I]
1
2
3
4
5
6
7
8
9
8
5
4
9
1
7
6
3
2
1
C=
1
C=
1
C=
2
C=
2
C=
2
C=
2
C=
2
C=
Rank
R[I]
After
R[I]
2
2
5
2
5
6
2
5
6
1
2
5
6
1
9
2
5
6
1
9
3
2
5
6
1
9
3
4
2
5
6
1
9
3
4
7
2
5
6
1
9
3
4
7
8
After pass = 1
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.
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.
Pseudocode 9.1
We now refine this algorithm by giving the detail of the loop body.
420
Chapter 9
Pseudocode 9.2
Section 9.2
Sorting
421
We say that g(n) is O(f(n)) if there exist two constants, C and k, such that:
|g(n)| < C |f(n)| for all n > k.
If a sort has a complexity of O(n3) it is definitely slower than Count Sort. The
best general sorts have a complexity of O(n log2 n), which is far better than
O(n2). If the sorts are very specific and limited in some way, then their
computing times could be shorter, possibly linear (of order O(n) ) or even
logarithmic (of order O(log n) ).
Space efficiencyis related to the amount of memory required. In the Count Sort
algorithm, a second array R is required for storing the ranks, so this Count Sort
algorithm is not the most economical of space. However, although the extra
array has N elements, if the original array were an array of records, the extra
array is likely to be much smaller since it only has to store Integers. The space
efficiency of the algorithm might be acceptable after all. Of course, in our
specific example, the rank array is as big as the original array (they both
contain Integers), and the space efficiency might be considered to be somewhat
weak.
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 N1 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.). Lets develop the algorithm topdown as usual, starting with a first draft of the algorithm.
Pseudocode 9.3
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
Pseudocode 9.4
Figure 9.5
Bubble Sort
Trace of Pass 1
Before
A[I]
I
1
2
3
5
4
5
4
5
4
5
4
5
4
5
4
9
5
8
5
4
5
9
1
9
1
9
1
9
1
9
7
4
7
4
7
6
7
7
6
7
6
7
6
7
6
1
6
9
7
1
6
5
9
4
7
1
6
1
6
1
6
8
9
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
After the first pass, the largest value 9 "bubbles" to the top position.
After
A[I]
A[I]
1
2
3
5
4
8
7
8
7
8
7
8
7
8
7
8
7
8
7
4
5
9
1
5
4
6
5
6
5
6
5
6
5
6
5
6
5
6
7
7
6
6
1
4
3
4
3
4
3
4
3
4
3
4
3
8
9
3
2
3
2
1
2
2
1
2
1
2
1
2
1
2
1
After pass = 1
5
4
7
1
6
3
We reach the final and complete algorithm by specifying the details of the
comparison.
Pseudocode 9.5
The Swap subalgorithm was
introduced in
Chapter 5,
Figure 5.12.
Section 9.2
Sorting
423
already better than the Count Sort (which required 81 comparisons), and could
be improved still further.
There are many ways to improve this Bubble Sort. Perhaps the easiest
improvement comes from noticing that each pass can be one comparison shorter
than the previous pass (because at the end of each pass one item has bubbled to
its final position and should not be considered any more). So on pass 1 we still
make 8 comparisons, but on pass 2 we need make only 7 comparisons since the 1 is
already in its final position. On pass 3, we need only 6 comparisons, and so on
until the eighth pass where we need make only 1 comparison. The total number
of comparisons for our specific example is then
(8 + 7 + 6 + 5 + 4 + 3 + 2 + 1) = 36
which is less than half of the 81 comparisons of Count Sort.
We can generalize this result for an array of N values. In this case, the number
of comparisons necessary for an improved Bubble Sort is
C = ( N 1) + ( N 2) + (N 3)++3 + 2 + 1
or
C=
N (N 1)
2
Lets compare the new and improved Bubble Sort to the first sort, Count Sort.
In Count Sort, N 2 comparisons were needed. Here, using the new and improved
Bubble Sort, N(N-1)/2 comparisons are needed.
If we were to sort big arrays, where N is very large, we notice two things:
Count Sort would need N2 comparisons
Improved Bubble Sort would only need half as many comparisons:
N 2/2. This is because when N is large, N(N-1) N2.
So we can say that improved Bubble Sort is almost twice as fast as Count Sort,
but both sorts have complexity O(N2). If you do not know the above formula, its
derivation is shown below.
The formula
C =
N ( N 1)
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))
Notice that each of these N1 terms has a value of N, so that
2C = N ( N 1) .
The formula below is equivalent to the one above as an expression for the sum of the first N
natural numbers:
1 + 2 + 3++( N 3) + ( N 2) + ( N 1) + N =
N ( N + 1)
2
424
Chapter 9
2.
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.
Figure 9.6
Select Sort
After
A[I]
8
M=
8
M=
8
M=
9
M=
9
M=
9
M=
9
M=
9
M=
8
5
4
0
1
7
6
3
2
I
1
2
3
4
5
6
7
8
9
Maximum
B[I]
After
B[I]
9
9
8
9
8
7
9
8
7
6
9
8
7
6
5
9
8
7
6
5
4
9
8
7
6
5
4
3
9
8
7
6
5
4
3
2
9
8
7
6
5
4
3
2
1
After pass = 1
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. Lets 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
Pseudocode 9.6
Sorting
425
Lets 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.
Pseudocode 9.7
finding the
Maximum
value in A
Lets 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.
Pseudocode 9.8
finding the
Maximum
value in A
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.
426
Chapter 9
with the first element of the table. Then the Maximum of the rest of
the array is found and is swapped with the second element of the table.
This selection and swapping continues until the entire array is sorted.
This Select Swap Sort involves only one array, the original array,
which is considered during the sort to be split into two parts, a sorted
part initially empty, and the rest of the array which is unsorted. The
sorted part will grow until it occupies the entire array.
Insert Sort
The fourth sorting method, Insert Sort, involves entering one item at a time
from the original array A into a sorted array B by moving the existing items in
B to make room for the inserted item. It is rather like a card player sorting a
hand. Initially, the sorted array B is empty, and the items are inserted into it
one at a time. B grows as the sort proceeds. This algorithm has a form very
similar to all the sorting algorithms we have seen and, for that reason, we
leave it as an exercise.
9.3
Section 9.3
427
before each pass, and set to False whenever we actually do a swap. This way,
if during a pass we do not have a swap we can stop the process because the
values are all in order.
Pseudocode 9.10
If a swap is done,
Finished is set to False.
Shell Sort uses a modified version of Bubble Sort called Distant Bubble Sort.
This version compares subsets of values from the original array, values that are
Distance apart. To do that, we have to modify the part of our latest version of
428
Chapter 9
Bubble Sort shown below so that the comparisons are made between values
Distance apart.
Pseudocode 9.12
The inner For loop above must be changed to a While loop, and the comparison
and swap must be changed so that elements Distance apart (not adjacent
anymore) are considered. Another necessary modification was to make certain
all sequences of spaced values were processed. To do that, we had to repeat this
inner loop Distance times, as the number of such sequences is equal to Distance.
These modifications, the addition of three nested loops, lead to a more
complicated algorithm, Distant Bubble Sort, which makes it harder to
follow. The algorithm is shown in Pseudocode 9.13.
Figure 9.7
A[I]
Before Cycle 1
8
5
4
5
4
5
4
7
4
7
6
7
6
9
1
9
1
9
2
9
2
9
2
9
2
7
6
7
6
7
6
5
6
5
4
5
4
3
2
3
2
3
1
3
1
3
1
3
1
Distance = _9
2
4 apart
A[I]
Before Cycle 2
8
7
6
9
2
5
4
3
1
A[I]
After Cycle 2
8
7
6
9
2
5
4
3
1
8
7
6
9
2
5
4
3
1
8
7
6
9
4
5
2
3
1
Distance = _94
8
7
6
9
4
5
2
3
1
2 apart
8
9
6
7
4
5
2
3
1
8
9
6
7
4
5
2
3
1
8
9
6
7
4
5
2
3
1
Section 9.3
429
A[I]
After Cycle 3
A[I]
Before Cycle 3
8
9
6
8
6
8
6
8
7
8
7
8
7
8
7
8
7
8
7
7
4
7
4
7
4
6
4
6
4
6
5
6
5
6
5
6
5
5
2
5
2
5
2
5
2
5
2
4
2
4
2
4
3
4
3
3
1
3
1
3
1
3
1
3
1
3
1
3
1
2
1
2
1
Distance = _9
8
Pseudocode 9.13
1 apart
As the algorithm is more complex, the analysis of Shell Sort is far from trivial
and is beyond our scope, so we will not do it here. Suffice it to say that the
complexity of Shell Sort is O(n1.2), which makes it better than the sorts we
have seen so far, but still not quite as good as a number of other sorts that are
more efficient, like Radix Sort, Heap Sort, and Quick Sort. Depending on the
data they process, these sorts have complexities going from O(n) to O(n log n).
They will not be presented here, but in the next section dealing with recursion,
we will look at a similarly efficient sort called Merge Sort.
Recursive Sorts
The idea of recursive subprograms was introduced in Chapter 7. A recursive
subprogram is one that invokes itself. Recursionis often a very useful technique
to solve complex problems, and we will use it here for manipulating simple
arrays. Later in this chapter, it will be applied to more complex structures.
Lets start with a simple example to illustrate the use of recursion with an
array. Summing the N numerical elements of a Table array (which was seen in
our mean and variance examples of Chapter 8) can also be done by adding the
last value Table[N] to the sum of the remaining (N1) values. Using function
Sum, this can be formally written as shown below:
Sum(Table, N) = Table[N] + Sum(Table, N - 1)
Function Sum is thus defined recursively (in terms of itself). The base case,
which causes the recursion to terminate, is obtained by realizing that the sum is
zero for an array with no element. The complete recursive summing up
algorithm is shown in Pseudocode 9.14.
430
Chapter 9
Pseudocode 9.14
As another example of the use of recursion with arrays, lets look at how to
reverse the elements of an array. Among the many ways this reversal can be
done, well choose to do it recursively by following two steps:
1
Figure 9.8
1
Left
Recursive Reverse
1
M A R G O R P
7
Right
P A R G O R M
P R R G O A M
.......
P R O G R A M
Lets take now a more complete example of the use of recursion with arrays.
Another Swap Sort method for an array of N elements, Merge Sort, can be
defined as a recursive algorithm by finding the array midpoint, and splitting
the array into two arrays starting at indices First and Middle+1. Then these
two arrays are sorted (by calling this same Merge Sort algorithm!). Once
sorted, the two parts are finally merged together.
Pseudocode 9.16
Section 9.3
431
Figure 9.9 illustrates the Merge Sort method applied to the set of data that
we have been using in the other sorting algorithms.
The left half of the figure shows a succession of array splitting operations,
corresponding to the recursive calls. The right half of the figure shows the
reconstruction of the array through invocations of the Merge subprogram.
Although this Merge Sort mechanism might look complex, this sort is
considerably faster than all the sorting methods considered thus far.
Figure 9.9
8
5
8
Split
Merge
5
8
5
Merge
Split
4
4
9
4
Split
Merge
9
8
5
7
6
Split
1
7
Merge
1
Split
Merge
7
6
Split
3
Split
Merge
3
Split
6
3
Merge
2
Merge
The merging of the two sub-arrays is done simply with an index sliding down
each array, with the maximum value of the two indexed values put into the
array Result, as shown by the following pseudocode:
Pseudocode 9.17
N/2
N/4
N/8
...
N/2P
432
Chapter 9
or
2P = N or
p = log2 N
The number of passes, or the number of times the array is split, is thus log2 N.
Merge Sort must also perform as many merges as there were splits, and each
merge operation is O(N). The performance of Merge Sort is therefore
proportional to the product Nlog2N, and its time complexity is O(N log N).
This complexity is considerably better than the O(N2) performance of all the
previous sorting algorithms.
To obtain a better perspective on algorithm complexity, lets look at the time
complexities of the other recursive algorithms we have seen so far. Algorithms
Sum up and Reverse both have a linear complexity of O(N), while algorithm
Merge Sort has a larger time complexity of O(N log N).
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.
Figure 9.10 Searching for data items
Data items
1
11
2
3
38
23
4
5
19
38
7
...
13
Sample data
Key
38
Item searched
Index
Count
Number found
Position
Number
13
Items in 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
Pseudocode 9.18
Searching
433
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
each time a key is found
Set Position to Index
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.
Pseudocode 9.19
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
We used the
Bisection
method as early
as in Chapter 4
for our guessing
game.
We can use the method of Bisection described in Chapter 6 to keep reducing the
size of the part of the array to be searched until either we find the item, or we
know that it is not present. The binary searchalgorithm proceeds by halving
the search range at each stage. You may wish to create this Binary search
algorithm on your own by modifying the Bisection algorithm described in
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.
Figure 9.11 Pattern matching
S_Index
String =
1
Pattern =
String =
Pattern =
N o w
String =
N o w
Pattern =
N o w
Section 9.4
Searching
435
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.
Pseudocode 9.21
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.
Pseudocode 9.22
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
Pseudocode 9.23
pattern matching
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-MorrisPratt algorithm and the Rabin-Karp algorithm. These algorithms go beyond
our scope and will not be presented here.
9.5
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
437
1
2
3
Method a
Top
Bottom
1
2
3
1
2
3
Top
Bottom
Bottom
Top
Method b
Method c
Bottom
Top
Method d
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 well choose
Method d but we will reverse it in the diagram as shown in Figure 9.13.
Figure 9.13 One stack implementation
Array contains
N elements.
arrays
N
Push
Bottom
3
2
1
Finally
Pop
Initially
Top
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
Pseudocode 9.24
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.
Pseudocode 9.25
To check if the stack is empty, we check to see if the stack Top is zero.
Pseudocode 9.26
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.
Pseudocode 9.27
Push on Stack(Item)
If Stack Full
Output "The stack is full"
Else
Increment Top
Set Stack[Top] to Item
End Push on Stack
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.
Pseudocode 9.28
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
439
Create Stack
Set Stack to NIL
End Create Stack
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.
Figure 9.14 A dynamic stack
Stack
Stack
Bottom of stack
First New Top created
New Top
Item 4
Item 3
Item 2
Item 1
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.
Pseudocode 9.31
Push on Stack(Item)
Set New Top to New(Element)
If memory allocated
Set New Top Information to Item
Set New Top Next to Stack
Set Stack to New Top
Else
Output "No more memory"
End Push on Stack
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
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.
Pseudocode 9.32
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.
Section 9.5
441
2
3
Rear
4
5
9
8
4
-
Size
4
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.
Pseudocode 9.33
Creat Queue
Set Front to 1
Set Reat to 1
Set Size to 0
End Create Queue
The functions to check whether the queue is empty or the queue is full are
obvious, as illustrated by Pseudocode 9.34.
Pseudocode 9.34
The function to count the elements in a queue is trivial since the Size variable
tells us how many there are.
Pseudocode 9.35
442
Chapter 9
Pseudocode 9.36
Enter Queue(Item)
If Queue is full
Output "The queue is full"
Else
Advance Rear
Set Queue[Rear] to Item
Increment Size
End Enter Queue
Item 1
Rear
Item 2
Item 3
Rear
Item 4
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.
Pseudocode 9.38
Enter Queue(Item)
Set New Rear to New(Element)
If memory allocated
Set Rear Next to New Rear
Set New Rear Information to Item
Set New Rear Next to NIL
Set Rear to New Rear
Increment Size
Else
Output "No more memory"
End Enter Queue
Follow this algorithm while adding Item 5 to the queue of Figure 9.16.
Section 9.5
443
The Remove from Queue algorithm is very similar, and is shown below.
Apply this algorithm to the queue in Figure 9.16.
Pseudocode 9.39
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
Figure 9.17 A binary search tree
Tree
15
11
22
18
31
444
Chapter 9
Pseudocode 9.40
Tree Traversal(Tree)
If Tree is not empty
Tree Traversal(Tree Left)
Output Node information
Tree Traversal(Tree Right)
End Tree Traversal
Section 9.6
9.6
Review
445
2.
3.
4.
5.
6.
446
Chapter 9
7.
Order Type
Example algorithms
O(2 n )
Exponential
O(n2)
Quadratic
Select Sort
O(n log n)
N log N (Entropic)
Merge Sort
O(n)
Linear
O(log n)
Logarithmic
Binary search
O(1)
Constant
Factorial
8.
9.
10.
Section 9.7
9.7
Glossary
Execution time: The time that it
takes an algorithm to execute.
In situ: In place, applied to array
manipulations that place the results
in the original array, without the
need for duplicating the array..
Order of complexity: A measure of
the performance of an algorithm,
which shows how the number of
operations required to execute the
algorithm is related to the size of the
problem being solved by the
algorithm.
Rank: In an array, the rank of an
element is the number of array
elements that are of a greater than or
equal to it.
Space efficiency: A measure of the
amount of space required by an
algorithm during execution.
Time complexity: An expression that
gives an estimate of the execution
time of an algorithm
Glossary
447
448
Chapter 9
9.8
Problems
1.
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.
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 2
Queue 1
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
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.
10.
Section 9.8
Problems
451
452
Chapter 9
Section 9.8
Problems
453
454
Chapter 9
Section 9.8
Problems
455
456
Chapter 9
Chapter Outline
457
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
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.
5.
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.
Problem Definition
Programs are written so that computers can solve problems posed by humans.
When faced with having to write a program, you have one thing: a description
of the problem to solve. This description may be very precise or vague, but
nevertheless is present.
The first thing to do, is to make sure that you understand the problem. As
Albert Einstein once said, If you cant explain something to a six-year-old, you
really dont understand it yourself. If you are in this state, you must examine
more closely the imprecise parts of the problem that you do not understand.
For instance, if your teacher asks you to write a program to Find the average of
five grades for each of my students, it might at first sound simple. But, you
should ask yourself:
What does average mean, exactly?
Are the grades in percentages or letters?
Do some grades count more than others so that we have to do a
weighted average?
Asking yourself such questions forces you to define the problem very precisely.
Section 10.2
459
Once you are sure of what the problem entails, you must jot down a list of
specifications. Specificationsare precise definitions of what the program must
do. At a minimum, they must include the following:
Input: what data must be input and in what form
Output: what data must the program produce and in what form (in
order to solve the problem)
Virtually all computerized solutions have the structure shown in Figure 10.1.
Figure 10.1 A typical computerized process
Input
Process
Output
Lets 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.
460
Chapter 10
Step 2
Solution Design
In this step, we break our problem down into a number of smaller, more
manageable parts. We must analyze the original problem, and divide it into a
number of sub-problems. Because these sub-problems are necessarily smaller
than the original problem, they are easier to solve and their solutions will be
the components of our final program. Each sub-problem is itself divided into
smaller sub-problems, and this decomposition is carried on until we have subproblems whose solutions are simple.
If we use a solution structure like the one in Figure 10.1, we can readily
decompose the problem into three sub-problems: input, process, and output. We
can represent this decomposition by a structure chart. As we have seen in
Chapter 4, such a method is called top-down design, and leads to an outline of
the solution, as in Figure 10.2. Note that you can use break-out diagrams
instead, if you are more comfortable with them.
Figure 10.2 Structure chart
Problem
Input
Process
Output
subproblem
Section 10.2
461
This outline will help us write the algorithm since each of the boxes in the
structure chart will typically be implemented as a sub-algorithm.
Note:
At the end of the Solution Design step, you should have a structure
chart describing the hierarchy of your algorithm.
Input Data
& Validate
Process an
Employee
lines of communication
Display
Summary
462
Chapter 10
Input Data
& Validate
Process an
Employee
Compute
Withholdings
Display
Summary
Accumulate
and Display
refinement added
See Chapter 7
for more
information on
developing
interfaces via
parameter use.
Section 10.2
463
Figure 10.5 Modular design chart for a more realistic payroll system
external units
Tax Unit
Benefits Unit
main program
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.
Step 3
Solution Refinement
Now that we have the skeleton of our solution, we can start putting some meat
on its bones. As previously stated, each box in the structure chart corresponds to
a sub-problem. We are now ready to develop one algorithm to solve each subproblem as well as the main problem.
As you have seen so far, algorithms can be represented in many different ways:
by flowblocks, flowcharts, data-flow diagrams, etc. Pseudocode is the most
common type of algorithm representation developed. The advantage of using
pseudocode is that it is programming language independent. It can easily be
translated into most programming languages, particularly imperative
languages such as Pascal, Modula-2 or C.
Since we are now faced with the task of designing the actual algorithms, we
must at the same time decide which types of data structures to use. It is
important to realize that data structure selection and algorithm design are
directly related. If you change your type of data structure, you must accordingly
change your algorithm. This is why both must be developed concurrently.
Note:
464
Chapter 10
arithmetic gives exact results. We will also need a Boolean variable Valid
Data to indicate the result of the data validation.
Using these simple variables, we can begin to refine the high-level solution
defined by the structure chart of Figure 10.4. Using pseudocode, we develop the
algorithms for each functional part of the solution, starting with the main
program: Calculate Payroll.
Pseudocode 10.1
Calculate Payroll
Display title and column headings
Set all totals to zero
While there are data to read
Input Employee Data.Hours
Input Employee Data.Rate
Input Employee Data.Dependents
Input Employee Data.Name
Input Data And Validate(Employee Data, Valid Data)
If Valid Data
Process Employee(Employee Data, Totals)
Display Summary(Totals)
End Calculate Payroll
Pseudocode 10.3
Here, the collective name Withholdings has been used to represent the three
variables Federal Tax, State Tax, Soc Sec Tax.
Section 10.2
Pseudocode 10.4
465
Here we have used the collective name Pay Data to represent the four variables
Net Pay, Federal Tax, State Tax, Soc Sec Tax.
Pseudocode 10.5
Step 4
We have now completed the pseudocode for each part of our program. You
might think that the next step consists of translating this pseudocode into code.
Wrong!
At this point, you need to check your design to see if it will produce the
expected results. It is much easier to check the design now, when we can easily
make the necessary corrections, than later, when the entire code is written. To
check your design, you need to think up a testing strategy. This strategy will be
used for two things: (i) to check your design now, and (ii) once you decide upon a
final design and write the code, to check if the final program works correctly.
The advantage of deciding on a testing strategy now, as opposed to after coding
is completed, is that you are still at the design stage where the specifications
are fresh in your mind. The testing can then be planned with those
specifications in mind, from a relatively objective viewpoint. If changes need
to be done, it will not be as painful as if the whole program were already
written. If the entire program were written, you would be more prone to trying
little fixes to solve the problems rather than thinking about changing the
underlying design.
For smaller programs, it is usually enough to define a variety of test
cases, each case including the input data and the corresponding
expected results. These test cases must include extreme cases and
erroneous cases. For instance, test cases for a grades program should
include a negative grade, an erroneous value, to make sure that the
appropriate error message is produced. A procedure involving a number
of data elements should be tested with zero or the maximum allowed
number. Test data should be included to make sure that all the program
statements, without exception, are executed at least once.
466
Chapter 10
For large programs, the testing and the coding must be planned
together, piece by piece. The approach chosen may be top-down,
bottom-up, or a combination of both.
Top-down testing means to start developing the program component
at the top of the structure chart and working down component by
component, thus the name top-down. In order to be able to do this,
we must use program stubs for the lower level components in the
structure chart during the initial steps of development. A program
stub is a small piece of program that substitutes for a larger piece
that will be written later. It may simply leave a trace of its
execution by printing a message or it may also supply predefined
results.
For example, the structure chart given in Figure 10.4 shows that the
main program component, Calculate Payroll, will have three major
sub-components: Input Data & Validate, Process Employee, and
Display Summary. We could start a top-down development by
writing the main program and one of these three major procedures,
but the other two procedures and the lower level procedures could
merely be stubs.
In pseudocode, a stub for the Display Summary procedure might be
Pseudocode 10.6
algorithm
Display Summary(Totals)
Output "Display summary"
End Display Summary
Section 10.2
467
Normal Values
1.
2.
3.
4.
5.
6.
7.
8.
468
Chapter 10
We will use these cases and combine them to generate test data as follows:
We will use boundary value data, such as $3.50 for a normal value and
$3.49 for a wage less than $3.50.
For erroneous test data we should have cases 1, 2, and 3 individually,
then cases 1 and 2 together, 2 and 3 together, 1 and 3 together, and 1, 2,
and 3 together.
Cases 4 and 5 can be combined with cases 6 and 7 to produce several
normal cases.
Case 8 should be tried alone once to make sure the results are zero.
Using this approach, we define the test data shown below, where we have used
artificial employee names suggestive of the errors.
Figure 10.7 Test Data Definition
Abnormal
values
Normal
values
Name
hours-negative
hours-too-large
rate-too-low
rate-too-high
dependents-negative
dependents-too-large
hours-and-rate
hours-and-dependents
rate-and-dependents
hours-rate-dependnts
no-overtime-no-dep
no-overtime-with-dep
max-overtime-no-dep
maximum-hrs-and-dep
maximum-rate-and-dep
zero-hour-and-dep
Bogus
employee
name
The expected results for these test data have to be computed manually by
following the pseudocode and given here. These computations should give us
some insight into the way our algorithms operate. Here are the expected
results for the test data given above:
Section 10.2
469
Step 5
Starting with our pseudocode algorithms, this step consists of coding the actual
computer program. Then, using our testing strategy, we test the program and
compare our test results with the expected ones. For large programs, the coding
will be done progressively, the various components being coded with the
necessary stubs and drivers, so that they can be tested systematically.
Errors in design or peculiarities of the programming languages used may cause
difficulties in coding, and prevent the implementation of some parts of the
design characteristics. In this case, we must go back to the design step and
modify our design. The programming and coding step is finished when all the
coding has been done and when all the test data have been correctly processed.
Step 6
Documentation Completion
470
Chapter 10
Documentation produced
1.
Problem definition
2.
Solution design
3.
Solution refinement
4.
Testing strategy
development
5.
7.
Program maintenance
All of this documentation must be collected, and must be kept current (with
perhaps the exception of the pseudocode) throughout the lifetime of the
software. In addition to the above documentation produced at each step, some
additional user documentation may be needed. This documentation must
provide the user with enough information to be able to use the program and its
functions fully, without providing the mental burden of implementation
details. This type of documentation is often referred to as a users manual.
It is usually helpful to develop a preliminary version of the user documentation
during the problem definition step and then to refine it once coding and testing
are done. This preliminary version of the user documentation can be given to
the users, to verify that you have correctly understood the problem and are
producing a program that will satisfy the users.
Section 10.2
471
14.25
223.50
Step 7
Program Maintenance
472
Chapter 10
The new test data must be added to the old test data to build a
bigger test suite to be used in future maintenance.
Since most program maintenance is done by someone not involved in the original
design, it is imperative that the programs be well designed and well structured,
as well as readable, and that the documentation be complete and accurate.
Section 10.3
473
Step 1
Problem Definition
2.
Collecting all the significant words of that text together with the page
numbers where the words occur; and
3.
Step 2
10
Solution Design
474
Chapter 10
Like a binary tree, a binary search tree is made of nodes, and each node has a
left and a right descendant (either or both of which can be absent). As we have
seen in the last section of Chapter 9, the main property of a binary search tree
is that all the left descendants of a node have a value that is less than the
node value, and all the right descendants have a value greater than the node
value.
Likewise, the page numbers associated with a word will be kept in a queue,
where each page number is unique and will be output in the order of insertion,
that is from lowest number to highest number. Here again we will define a
separate unit for the ADT queue, to include the definitions and operations of
queues. Remember that queues are first-in-first-out structures: the elements in a
queue are output in the order in which they entered the queue.
Our solution will be illustrated by the modular design chart of Figure 10.10.
This chart illustrates the relationships between the various units of our
solution: Build Index will use types and operations from ADT Binary Search
Trees and ADT Queues.
Figure 10.10
used to store trivial
words and significant
words from text input
Queues
Build Index
Section 10.3
Figure 10.11
475
Traverse
Tree
Create
Tree
Display
Element
Display
Word
Step 3
Count
Queue
Search
Key
Get
Word
Insert
Word
Create
Queue
Enqueue
Insert
Node
Dequeue
Solution Refinement
To refine our solution we will need to define the functional elements of Build
Index, as well as the functional elements of units Binary Search Trees and
Queues. If we are lucky, someone might already have developed such useful
units, and all we will have to do will be to use them, or, more likely, adapt
them before using them. We can also give you a hint. If you have access to
computer science books, you will find such units already defined; use them!
We will also need to define the data structures that will be used in our program.
Obviously, the elements of our index will be kept in a binary search tree. Each
element record will be comprised of (i) the corresponding word and (ii) its list of
page numbers. If we keep the words in the tree nodes, we will have to reserve
enough space for the longest word, and this is not necessarily the most efficient
way to use memory space, as much of this space will be empty.
Instead, well use a well-known technique of storing the words in a long
buffer(storage area), to keep only nontrivial words, and no duplicates. The
buffer will be a big array of characters, and each word in it will be identified
by the index of its first character, as shown in Figure 10.12. Note that every
character has a corresponding index number.
Figure 10.12
Buffer
First
Second
Word 1 Word 2
Third
Fourth
New
Word 3 Word 4
Old Index
New Index
With the buffer, we will keep two special indices, Old Index and New Index.
Old Index always points to the next free space in the buffer. New Index is used
to enter a new word in the buffer, before deciding whether to keep it or not. To
keep a new word in the buffer, Old Index is updated to the value of New Index.
476
Chapter 10
Figure 10.13
12
Last Page
Pages
Pointer
Left
Right
Word 8
Word 6
Pointer
The elements kept in the binary search tree will have the structure illustrated
by Figure 10.13. Each element will have five parts:
an Index to the word buffer, called Key,
a Last Page number (to avoid keeping duplicate page numbers),
a Pages queue,
a Left pointer for the tree structure, and
a Right pointer for the tree structure.
With these data structures established, we can develop the pseudocode for
Build Index as follows.
1.
2.
Then, we read in the trivial words file and build the trivial words tree.
3.
Next, we read the text and insert the nontrivial words in the word
index tree.
4.
Section 10.3
Pseudocode 10.8
477
Build Index
Initialize word Index tree
Initialize Trivial words tree
Set Page number to 1
Set Line number to 1
Set Old Index to 1
building
Trivial
words
tree (2)
reading in
text and
inserting
non-trivial
words into
the Index
tree (3)
Besides some output subprograms, this program uses two important subprograms,
Get Word, to read a word, and Insert Word, to insert a word in a binary search
tree. These two subprograms are repeatedly invoked in the two loops that
build the Trivial and Index trees. The two loops read the text between words
character by character until a letter, denoting the start of a word, is detected.
The loop that builds the Trivial tree ignores all inter-word characters. When
a letter is encountered, the Get Word subprogram is invoked to read the word.
Since all words read from the Trivial File are, by definition, to be inserted into
the Trivial words tree, Insert Word is invoked for every word.
The action of the loop that builds the Index tree is somewhat different. In that
loop, two of the inter-word characters are detected and lead to special actions:
The end-of-line character causes the Line number to be incremented,
and
The end-of-page character causes the Page number to be incremented.
As in the first loop, when a letter is encountered, the second loop invokes the
Get Word sub-algorithm to read the word. However, in the second loop, the
word is not inserted into the Index tree until a search of the Trivial words tree
has shown that the word is not trivial.
Get Word reads in a word, character by character, and stores it in the character
buffer. This storage will only be temporary if it is discovered that the word is
trivial or has already been encountered. Get Word also leaves a special interword marker in the buffer to separate the words. This marker could either be
the size of the word or a special end of word marker. Get Word only modifies
New Index, it does not modify Old Index. Thus, several successive calls to Get
Word will simply overwrite the last word in the buffer and leave no permanent
record of the words that were read.
478
Chapter 10
Pseudocode 10.9
In Insert Word, we first check to see whether or not the word is already in the
binary search tree. If it is, we only need to update its element in the tree by
adding a new page number to its associated queue (if that page number is
already there, we do nothing, since we do not want duplicate page numbers). If
the word is already in the tree, we do not want to keep a duplicate in the buffer
and, for this reason, we do not update Old Index.
If this is a new word, Insert Word creates a new element for the tree and
initializes its associated queue. Since we will also use Insert Word to build
the Trivial tree and since trivial words do not need a page queue, we will use a
zero page number for trivial words. Once the element is ready, we insert it into
the tree and we update the Old Index so that, this time, the word is kept in the
buffer. The pseudocode for the Insert Word sub-algorithm is shown below.
Pseudocode 10.10
Section 10.3
Pseudocode 10.11
479
Display Element(Element)
Display Word(Element.Key)
Set Counter to 0
While Count Queue(Element.Pages) 0
If Counter = Maximum
Terminate line
Set Counter to 0
Display Word length blanks
Dequeue(Element.Pages, Item)
Display Item
Increment Counter
Terminate line
End Display Element
To display a word we only have to display all its characters from the buffer,
and then to pad the rest of the word space with blanks.
Pseudocode 10.12
Display Word(Index)
For all characters in Word
Display character from buffer
For remaining length
Display blank
End Display Word
480
Chapter 10
Figure 10.14
On
on
Had
At
If
To
is
as
her
this
much
the
when
will
whose
whom
who
when
we
was
us
up
to
those
this
they
these
there
them
their
the
that
so
she
ours
our
or
from
The Binary Search Tree external unit implements the ADT binary search tree.
It includes the following operations.
Initialize Tree(Tree)
This is the first operation to call, in order to initialize Tree.
Delete Tree(Tree)
This operation deletes all information about the Tree and its data.
Section 10.3
481
482
Chapter 10
Pseudocode 10.15
Queues Unit
The external unit Queues implements the ADT Queues whose operations are
described below. A queue will be defined as a record with two indices, a
counter, and an array of elements, as shown in Figure 9.15 in Chapter 9.
Initialize Queue(Queue)
Creates an empty Queue.
Enqueue(Queue, Item)
Inserts element Item at the end of Queue.
Dequeue(Queue, Item)
Deletes first element of Queue, returned in Item.
Count Queue(Queue) function
Counts current number of elements in Queue.
Queue Head(Queue, Item)
Returns value of first element of Queue in Item.
These operations have already been described in pseudocode in Chapter 9.
Step 4
To test our program we need a trivial words file and a text file. These are
various cases we can envision:
1.
Empty trivial words file: the index will include a l l the words in the
text.
2.
Only one trivial word: the only trivial word will not appear in the
index.
3.
One-page text file: the page numbers are all the same, and appear only
once for each word.
4.
5.
Text file with only trivial words: the index will be empty.
6.
Text file with no trivial words: the index will include all the words in
the text.
7.
Word found on more pages than fit on a single line: necessary to test the
splitting of the page numbers over several lines.
Section 10.3
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:
Text 2: the same file as Text 1 but with an end-of-page mark between
every word
Sample:
Text 3: a file with only two words repeated thirty times with an endof-page after each occurrence.
Sample:
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
albatross
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty\
beauty
484
Chapter 10
Step 5
The main program follows from our pseudocode. The details of this stage are
covered in the Practice book.
Step 6
Documentation Completion
All the results of our previous steps should be part of our documentation:
problem specifications, solution design and refinement, testing strategy,
program code, and testing results. We must also add a users manual, as shown
below:
Step 7
Program Maintenance
Section 10.4
10.4 Review
485
2.
3.
4.
At the end of the Solution Design step, you should have a structure
chart describing the hierarchy of your algorithm. Developing a
structure chart, using top-down design, will help us write the algorithm
to solve our problem since each of the boxes in the structure chart will
typically be implemented as a sub-algorithm.
5.
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.
6.
At the end of the Testing Strategy Development step, you should have
your testing strategy developed, including the input and expected
output data for all test cases, as well as the pseudocode for any
necessary stubs or drivers.
7.
8.
9.
The complete example to build a text index is relatively small, but still
big enough to show that a larger system is harder to understand, even
under good conditions.
10.
Using what you have learned in this book and in the Practice book, you
will have to write and run real programs using a given programming
language. This is where you will notice that a lack of method is
extremely costly in time.
486
Chapter 10
10.5 Glossary
Buffer: A holding area in memory for
data.
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.
External documentation: A program
description that is designed to serve
the needs of the users of the program.
It thus describes the program in terms
of the way in which it is used and its
observable actions.
External unit: A collection of
subroutines that are compiled
separately from the main program
and are concerned with the
manipulation of a particular type of
data, for example, an abstract data
type is frequently implemented as an
external unit.
Internal documentation: The internal
structure and workings of a program
described in a form to assist
programmers who will have to make
corrections or other modifications to
the program in the future.
Software life cycle: The sequence of
stages that a program passes through
during its useful life, these stages
essentially correspond to the seven
steps of software development
described in this book.
Stub: A temporary version of a
subprogram that provides a very
simplified simulation of the action of
the subprogram until the subprogram
itself is written. Stubs allow early
testing of the routines that will call
the subprogram. A typical action of a
stub program is to output a message
that it has been entered so that the
logic of the calling program can be
checked.
Section 10.6
Problems
487
10.6 Problems
The following is a series of problems and projects to be solved using the sevenstep 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.
2.
488
Chapter 10
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 balls 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).
Problem 3
Height
(inches)
1
0.8
0.64
0.512
0.4
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?
490
Chapter 10
4.
5.
P
1.1
1.05
P
1.05
1
1
1.05 + 1.05 2 = 1.86P
=P
whence
P = $537.63
More generally, if we make a loan of L to be repaid in n payments of P
and an interest rate of r per repayment period, then the n payments P
must be such that
L=
P
1+r
P
2
(1 + r )
P
3
(1 + r )
+... +
P
n
(1 + r )
Section 10.6
Problems
491
P
1+r
P
2
(1 + r )
P
(1 + r )
+... +
P
n 1
(1 + r )
If we subtract the first identity from the second, many terms cancel out
and we are left with
L(1+ r) L = P
P
n
(1 + r )
whence
(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
12y
(1 + MonthlyRate)
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
12y
(1 + MonthlyRate)
AnnualRate
= 1+
2y
which leads to
6
(1 + MonthlyRate) = 1 +
AnnualRate
or
AnnualRate
2
and finally
MonthlyRate) = e
log(1+AnnualRate/2)/6
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
Payment#
6.
Interest
Capital
Acc. Int.
Balance
97.59
44.21
97.59
9955.79
97.16
44.65
194.75
9911.14
7.
Section 10.6
Problems
493
Word: Occurrences
A
18
At
1
Words table is full, no room for xxxxxx
Hint: Although this problem can easily be solved with arrays, if you
are smart and have understood the Build Index case study, it might be
easier for you to re-use and adapt that case study!
8.
494
Chapter 10
9.
Plot for y = x
|
#
|
#
|
#
|
#
1.50 |
#
|
#
|
#
|
#
|
#
1.00 |
#
|
#
|
#
|
#
|
#
0.50 |
#
|
#
| #
| #
|#
0.00 -------------------|
|
|
0.00
1.00
2.00
Section 10.6
10.
Problems
495
Languages
Language Concepts
Language Landscape:...
Language Structures
Languages for Softw...
Languages: Design a...
Languages: Design, ...
Languages
Languages
Languages
Languages
Languages
where the titles have been aligned on the word that is being used for
the alphabetical ordering and sufficient other words are provided to
give some context. Also appearing would be a citation to allow the
reader to find the work.
The KWIC program accepts an ordered set of lines, each line being an
ordered set of words, and each word being an ordered set of characters.
Each line consists of two parts: a Title Part and a Reference Part. The
Reference Part is enclosed in brackets. It is assumed that brackets never
occur in either the Title Part or the Reference Part other than as
identification of the Reference Part. An example of input data is:
Software Engineering with Ada [Booch 1983]
The Mythical Man Month [Brooks 1975]
An Overview of JSD [Cameron 1986]
Nesting in Ada is for the Birds [Clark et al.1980]
Object Oriented Programming [Cox 1986]
496
Chapter 10
11.
Section 10.6
Problems
497
12.
498
Chapter 10
Newton-Raphson method
F(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
Section 10.6
Problems
501
502
Chapter 10
Section 10.6
Problems
503
504
Chapter 10
Section 10.6
Problems
505
506
Chapter 10
Appendix
Solutions
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
Chapter
Chapter
Chapter
Chapter
Chapter
Chapter
Chapter
Chapter
1
2
3
4
5
6
7
8
9
Solutions
Solutions
Solutions
Solutions
Solutions
Solutions
Solutions
Solutions
Solutions
1-3......................................................508
1-3......................................................508
1-7......................................................510
1-3......................................................511
1-3......................................................512
1-3......................................................514
1-3......................................................515
1-3......................................................516
1-3......................................................517
507
508
Appendix
Solutions
b.
c.
d.
e.
Solution to Problem 2
a.
b.
c.
d.
e.
Solution to Problem 3
a.
b.
c.
It is not clear who designed and built the first electronic digital
computer. The contributor is not in the list.
d.
e.
f.
g.
Appendix
Table of
Values
begin
Input Q
Original
True
False
Q3
12
12
Solutions
509
Total Cost
24
20
16
12
Price P
is $3
Price P
is $4
T = P Q
15
18
Output T
4
2
P
24
21
24
20
end
16
12
8
4
Replace
Original by:
Extended
True
Original
False
Q>5
T
24
Price P
is $2
Original
20
16
12
8
4
Replace
Replace
Extended
Original by:
Failsafe
Extended
True
Error
Message
Q<0
False
Extended
Original
Failsafe-Extended by:
True
Failsafe
Extended
Original
Q=0
False
Bin
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
13
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
2
N
Divide
R
1
2
N
Divide
D
R
0
2
N
Q
Divide
D
R
1
3. TimeBase
1
Time
100
1430
N
Divide
Q
60
5. Octal: Base 8
a. 11 = 8 + 1 = 9 decimal
b. 23 = 2 8 + 3 = 19
c. 132 = 1 64 + 3 8 + 2 = 90
14
30
6. Hex: Base 16
a. 11 = 16 + 1 = 17
b. CC = 12 16 + 12 = 204
c. F00 = 15 16 16 = 3840
Multiply
840
Add
7. Other Bases
5, 10, 20 are from anatomy
12, 20, 60 have many divisors
(used for time and arc measure)
870
Mins
(C < 0) OR (T < C)
Output
Message
Give
Change
(C < 0) OR (T < C)
Output Message
Input Cost C
Give Change
Appendix
Solutions
511
Solution to problem 2
Input H, M
True
M=0
False
True
M = 30
True
False
0 < M < 30
True
Solution to problem 3
Input C
Set Sum to C
Input C
C=5
F
Sum < 15
Input C
Input C
Input C
C=5
F T
C=5
Add C to Sum
Input C
etc
T
Output Item
etc
C=5
F Output
Item
etc
etc
etc
etc
Sum > 15
T
Output
Change
False
H = 12
False
min
D
min
E
Conditions
min
2
2
Max
2
2
M1
Input
Values
AB C
D E F
A<B<C
1 2 3
1 2 1
A<C<B
1 3 2
1 2 1
B<A<C
2 1 3
1 1 2
B<C<A
2 3 1
2 1 2
C<A<B
3 1 2
1 1 2
C<B<A
3 2 1
2 1 1
Output
M1
Solution to problem 2
False
A<B
True
B<A
False
C<B
True
False
C<A
True
True
C <A
Set M to C
False
C<B
True
Set M to B
Set M to C
Set M to A
Solution to problem 3
More Mid
A B C
A B C
Sum3
Max3
Min3
Sum2
Diff2
Mid
Appendix
Solutions
513
Monthly
Calendar
Set MonthDay to 1
For Week = 1 to 6 by 1
DoWeek
For Day = 1 to 7 by 1
DoDay
Output NewLine
If ((Week = 1) AND (Day F)) OR (MonthDay > N)
Output Blanks
Else
Output MonthDay
Set MonthDay to MonthDay + 1
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
X3
3!
X5
5!
X7
7!
+...
Xp
p!
Sine S =
Term T =
Power P =
514
Appendix
Solutions
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
Set SineVal to SineVal
+ TermVal
Else
Set SineVal to SineVal
TermVal
Compute 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.
B
0
A
1
N
C
1
N
1
P
E
D
P
1
F
Q
1
0
0
can
break
out
more
G
Note:
If variables A, B are binary then N
is a NOT, P is an AND, Q is an OR
and M is an eXclusive-OR.
0
1
11
1
1
0
10
0
N
P
N
P
Q
10
1
N
N
P
N
Call Order is N P N P Q N N P N.
For A=0, B=1, the output G is 1.
Appendix
Solutions
515
Solution to Problem 3
A
B
C
D
E
F
G
H
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
Count: Loop through A counting the zeros, then loop again putting in
that many zeros and then filling the rest with ones.
516
Appendix
Solutions
b.
Select: Loop through A, for each zero in A, put a zero into array B, when
done finish B with ones.
c.
d.
Solution to Problem 2
a.
The easy way: Sort the values first and then select the one at the
middle index.
b.
Like Count Sort: Loop through values of the array stopping when half
the values are less than the given value.
c.
Keep selecting the Max and Min values and delete them until only one
value remains.
Appendix
Solutions
517
518
Appendix
Solutions
Index
Index
A
abstract data type 358, 397, 409
abstract data types
array queues 446
array stacks 441
implementing 441
pointer queues 448
pointer stacks 444
Abstraction 134, 164, 166, 234
Abstraction Form 130
Action 65, 119, 128, 165, 166, 176
in programs 180
on data 180
actions
groups of 302
Al-Khwarizmi 23
algorithm 30, 65, 74, 75, 118, 119, 458
algebraic 74, 82, 118
alternate 52, 164
alternative 137
analyze 421
assertions 146
communicating 56
comparing 54
Complete 76, 119
Data-flow diagram 47, 74, 118
decomposing 111
Deterministic 76, 119
dynamic behavior 234
dynamic view 176
Ease of Use 77
Efficiency 77, 198, 232
Elegance 77, 119
Embedding 51
equivalence 53, 135, 164, 187
execute 30, 49
Execution time 453
Extending 48, 131, 186, 257
Finite 76
flowblock 74, 118
Flowchart 45, 74, 118
Foolproofing 50
Generality 77, 119
Generalizing 47
Good Structure 77
Graphs 46
hierarchical 74, 119
high-level 31
low-level 31
modifying 47
notations 78
Order of complexity 453
pseudocode 47, 75, 118
refinement 256
representations 74, 78, 118
reuse 51
Robustness 120
selecting 79
Space efficiency 453
static structure 234
static view 176
tabular 74, 86, 87, 118
test 421
trace 49, 66, 162, 182, 266
Unambiguous 76, 120
Verbal 45, 74, 80, 118
well-structured 120
Alias 350
analysis
Count Sort 421
Select Sort 427
Swap Sort 424
analytical engine 23
argument 307, 350
array 86, 119, 166
Binary search 436, 437
Bubble Sort 422
Count Sort 419
deck of cards 158
homogeneous items 358
indices 358
Linear search 436
Rank 453
Recursive Sort 432
searching 435
Select Sort 425
Sort and copy 417
Sort and rank 417
Sort in place 418
sorting 416
Swap Sort 422
Arrays 358
homogeneous 360
519
520
Index
B
Babbage, Charles 23, 59
Backus, John 57
balloon payment 210
Base case 350
Bell Laboratories 58
Bigger algorithms 290
Bigger Blocks 251, 290
bigger data 290
bigger mixtures of forms 290
Binary
Search 166
binary conversion 159
Binary Counter 268
binary search 437, 477
Binary to Decimal 106, 160
binding 335, 350
operands 92
birds eye view 89, 141, 305
Bisection 281, 282, 283
Search 132, 166
Bisection algorithm 290
black box 75, 89, 119, 305
passed in 91
passed out 91
block structure 300, 348, 350
BOD 41, 65
Boole, George 23, 98
Boolean 179
Bottom-up design 65
Bottom-up testing 468
break-out diagram 39, 65
alternate forms 44
Cohesive 43
complete 143
Consistent 41
important questions 143
Orderly 41
Refined 42
Bubble Sort 422
improving 428
buffer 479, 491
C
Case form 259, 262, 290, 291
Character 178, 235
assignment 196
comparison 276
Character data type 275, 290
coding 65
cohesion 339, 350
compiler 25
compound conjunction 198
computer 14, 65
a look at 18
A to D converter 25
ALU, arithmetic and logic unit 19, 25
analog value 25
basic capabilities 18
bits 153
bus 20, 25
compiler 25
CPU, central processing unit 20, 25
D to A converter 25
execute 14, 25
four units 18
hardware 19, 21, 24, 25
history 21
I/O devices 20
inaccuracy 93
input unit 19, 24
Input/Output 25
instruction register 25
instruction register 19
Memory 24, 25
memory bus 21
memory unit 18, 24
modem 25
operations 14
output unit 19, 24
problem solving 30
processing unit 19, 24
program register 19
register 25
software 19, 21, 24, 66
system 20
concurrency 105
Conjunction 198
Contour diagram 333
essentials 340
control variable 269, 291
conversational mode 271
Index
D
data 128, 165, 166, 176
actions 234
break-out diagram 40, 41
external 252
global 301
heterogeneous 358
hiding and sharing 332
homogeneous 358
structured 153
Data space diagram 309, 322, 324, 348
conventions 310
memory locations inside 310
memory locations outside 310
passed-in parameter 310
passed-out parameter 310
Data Structure 166, 458
array 158
data transfers
program and subprogram 300
data type 91, 119, 177
Boolean 179
character 178
integer 94, 119
logical 179, 279
Real Number 91, 120
string 179
data validation 35, 65
Data-flow diagram 65, 89, 103, 119
bigger blocks 105
black box 47, 101
concurrency 106
Data-flow diagrams 165
Decimal to Binary 107, 159
decision tables 88, 119
Deep Nesting 133
DeMorgans laws
first law 100
second law 101
DeMorgans Rules 199
Data-flow diagram 199
first rule 199
second rule 199
Descartes, Ren 152
design 65
bottom-up 65, 141
modular 464
E
embedding
algorithm 65
end-of-file marker 255
environments
human 20
physical 21
EOF 255, 291
error
in algorithm 36
in coding 36
in design 36
in test results 36
execute 65
execution time 416, 421
expression
arithmetic 91
logical 99, 119, 280
polynomial 93
Time complexity 453
External Data 252, 254, 290, 332
external documentation 471, 491
external unit 463, 491
F
field 359, 409
file 254, 291
EOF 255
flow of control 64, 65, 74, 89, 119, 303
pseudocode 115
flowblock 113, 119
vs. flowchart 135
521
522
Index
J
Jacquard, Joseph 23
Julian date 342, 350
Julius Caesar 87
G
glass box 75, 119, 305
global data 301, 350
Global variable 336
H
hardware 19
heterogeneous 377, 408
hiding and sharing of data 348
Hierarchical programming 166
Hollerith, Herman 23
homogeneous 377, 408
Horizontal views 213
I
I/O devices
transducers 21
identifier 177, 235
if-then-else 129
implementation 36, 66
K
Kemeny, John 56
kludge 208, 235
L
leaf node 407, 409
least significant digit 106
Libraries, Modules 463
linear search 436
linked list 393, 409
Local variables 310
Logical conditions 198
Logical data type 279, 290
logical expression 100, 119
equivalency 203
logical operation
Conjunction (AND) 198
Disjunction (OR) 199, 279
Negation (NOT) 199, 280
Logical type 179
Index
loop
initialization of values 259
loop control variable 264, 267, 291
loop invariant 176, 214, 234, 235
complete body of the loop 231
using 229
Loop-and-Count form 262
Loosely coupled 350
loosely-coupled 338, 339, 349
Lord Byron 59
Lovelace, Ada 59
M
N
n-dimensional list 358, 409
n-tuple 360, 409
Nassi-Shneiderman diagrams 113
Negation 199
nested selections 257
Nesting 166
Nesting Selections
in Fors 269
nests of loops 290
node 407, 409
O
one-dimensional arrays 360
operand 119
operating programs 21
operation
assignment 180
comparing values 181
incrementing 181
modulus 205
operations
on Characters 276
operator 91, 119
precedence 92
operators
AND 99
logical 100
NOT 100
OR 100
Order of complexity 453
output parameter 306, 312
523
P
Packages 463
paradigm 186, 235
parameter 307, 350
Parameter crossing 336
Parameter passing 323, 348
by reference 312, 315
by value 312, 315
parameterized block structure 304
parameters 305
Pascal,Blaise 23
Pass by reference 350
Pass by value 350
Pattern Matching 438
Search and Count 438
Pattern MatchingFind First Match 438
pointer 392, 409
Polya,George 31
precedence 119
precision 283, 291
predicate 99, 119
problem solving 30
coding 35
detailed design 38
development of testing strategy 486
development of testing strategy
application 469
divide and conquer 33, 39
documentation completion 37, 471,
488
documentation completion
application 472
general algorithms 281
Polyas four steps 31
problem definition 32, 458, 476
problem definition application 460
program coding and testing 35, 471,
488
program maintenance 37, 474, 489
program maintenance application 474
seven step method 32, 63, 458
solution design 33, 140, 461, 476
solution design application 461
solution refinement 74, 464, 478
solution refinement application 464
systematic method 32
task 66
test 66
testing algorithms 197
524
Index
Q
queue 399, 405, 406, 409, 445, 446
Queues Unit 486
R
random value 287, 291
rank 417
Real Number 178
inaccuracy 93
operations on 91
Records 166, 358
heterogeneous elements 358
indices 358
Recursion 300, 343, 349, 350, 432
recursive definition 217
Recursive Sort 432
register
instruction 25
program 25
Repeat-Until
condition 204
loop 204
Repetition 166
Repetition Form 109, 120, 130, 164, 176,
234
body 130
flowblock 115
Index
flowchart 115
For Form 262
infinite loop 207
initialization 212
initialization of values 259
initializing loop 110
iteration 110, 205
loop 109
loop body 109, 205
nested 132
nesting 265
Repeat-Until 203
side effect 208
terminating value 258
termination condition 109
trace 205, 266
While loop 205
repetitions 264, 290
Roman numerals 78
Root node 409
S
scientific notation 91, 178, 235
Scope 350
Select Form 259, 260, 261, 290, 291
Select Sort 418, 425
Selection 120, 166
Selection Form 108, 120, 129, 164, 176, 185,
234, 280
flowblock 114
flowchart 114
larger 189
nested 131, 189, 192, 194
proof of equivalence 187, 192
selections 257, 290
sentinel value 255, 291
Sequence 166
Sequence Form 108, 120, 129, 164, 176,
182, 234
flowblock 114
flowchart 114
set 409
difference 385
intersection 385
membership 385
union 385
Sets 358
homogeneous 358
side effect 208, 235, 350
software 19
525
526
Index
T
table 86, 120
indice 88
subscript 88
two-dimensional 88
temporary variable 184
terminal node 407, 409
terminating sandwich 256, 290
terminating value 255, 258, 290, 291, 363
test case 35, 66
test data 469
testing strategy 466, 469, 491
test cases 55
testing strategy development
test case 35
tightly-coupled 339, 349
time complexity 421, 453
Top-down 166
design 128, 164
development 152
refinement 252
testing 467
Trace 66, 235
assertions 214
Four Fundamental Forms 224
state 212
two-dimensional 176, 205, 218
Trace tables 206
tree 399, 407, 409
Trees 449, 477
truth tables 88, 99, 187
Turing, Alan 23
Two-dimensional arrays 367, 408
Two-dimensional plots 273
Two-dimensional tracing 213
U
utility programs 21
V
value
analog 21, 25
binary 106
continuous 21, 65
counting 178
decimal 106
digital 21, 65
discrete 21, 65
Integer 119
measuring 178
Real Number 120
variable 36, 66, 234
actions 234
assigning values 180
components 177
data type 177
global 336
identifier 177
incrementing 181
initialization 212
logical 279
scope 335
temporary 184
using in subprograms 318, 334, 348
variable access rules 318, 334, 348
vector 360, 362, 409
Vertical views 214
von Leibniz, Gottfried Wilhelm 23
Von Neumann, John 23
W
well-structured algorithm 77
While loop 205, 209
Wirth, Niklaus 57, 58
worms eye view 89, 141