| |
Main Menu | Next Section |
A. Algorithms - One Component of the Design Phase
We now have a general idea of 'what' our program should do to
accomplish its task and it is time to move on to 'how' that task
should be accomplished and some initial discussion of design.
Some of you may be thinking, "Ah, good, now we jump into
the code." Not so fast! There is nothing worse than writing
code before you have taken the time to design the code you are
going to write.
Programming problems always involve two components:
2. A set of actions involving the objects, for example:
The complexity of whatever part of the world (real or imaginary
) we are attempting to model in a program is reflected in the
interactions among the objects modeled in the program. As a programmer
you must have a good handle on that complexity before you proceed
to coding. Humans almost always handle complexity using a divide
and conquer strategy. We break down or decompose complex problems
into easier, more manageable components. Later, we will discover
that there are two basic approaches in the programming world to
this decomposition process. One can focus on the objects in the
problem environment and examine each object separate from others.
Or, one can focus on the actions/tasks involved in a problem and
focus on each task separate from all others. At present, however,
we are not ready to handle any real complexity. Instead, we will
focus on problems that are so simple as to have only one object
and only one basic task. A caution is in order - in reality even
these problems can be further decomposed but let's pretend otherwise
for the moment.
The amazing thing is that even with programming problems this
simple it is unwise to simply start coding. You still have to
make sure that you know how to accomplish the task - after all,
how can you tell a computer how to solve a problem if you do not
know how to solve the problem yourself. Your first goal then is
to come up with some general plan or description for solving the
problem and then express that plan in a systematic way. In other
words, your goal is to state clearly and in order the exact steps
necessary to accomplish the task/problem . In Computer Science terms, your goal is to write an algorithm.
Good recipes, especially those written for beginners, can be considered
algorithms. They are step by step descriptions for solving the
problem of preparing some kind of food.
Whenever you write instructions for someone else, you need to ask
yourself, "What can I leave out?". In other words, how much does
the person already know and how much detail must I provide. For
example, in a cookie recipe, do you need to tell the person to
grease the cookie sheet? The answer is an emphatic 'YES' if you
are writing for someone like at least one of the authors of this
text! You should provide all possible details and you should do
so in as simple a language as possible. .
The same is true for computer based algorithms - algorithms that
will be turned into code in some programming language. Computers
assume nothing. They do not perform any action they are not explicitly
told to perform. In addition, the instructions they perform are
simple and programming languages such as C++ tend to reflect that
simplicity. For that reason algorithms should be written in simple,
concise English. - no compound sentences, no skipping of details.
Think of yourself as writing instructions for a ten year old who
can read, knows the basics of arithmetic and can follow instructions.
In addition, to keep your algorithms as general as possible, try
to avoid writing your algorithms for a specific language such
as C++.
B. Your First Algorithm
Let's start by writing the algorithm for the sixth program from
chapter 2
- the program to calculate the salary for one
employee. Yes, this is a simple program and yes, we are working
backwards by having, in fact, already written the code, but let's
pretend that the program is more complex and that we have not
yet written the code. The first step, of course, is to do an analysis
- something that we have essentially already done in the previous
section. For the moment we will ignore that part of the analysis
that talks about opening and closing screens and about processing
more than one employee. Here is how the algorithm might look:
Get the Rate of Pay for the employee
Get the Hours Worked for the employee
if Hours Worked is greater than 40
{
Regular Salary = 40 * Rate of Pay
Overtime Rate of Pay = Rate of Pay * 1.5
Overtime Salary = Overtime Rate of Pay * (Hours Worked - 40)
Full Salary = Regular Salary + Overtime Salary
}
else
{
Full Salary = Hours Worked * Rate of Pay
}
Output the Full Salary
Compare this with the actual code and you will discover
a number of points. The algorithm goes through the same steps
as the code but it is not written as C++. There are no variable
declarations, the rules for variables are not followed, it uses
words like 'get' and 'output' that are clear English but not part
of C++ and it does not include some of the peculiarities
of C++ syntax. (Some might object to the use of '{' and '}' in the algorithms here, arguing that they should be replaced by English terms such as 'Begin' and "End'. They are used here to support learning C++.)
Also, the algorithm does not worry about special points such as
constants. Actually, we could have written this algorithm with
names such as REGULAR HOURS and OVERTIME ADJUSTMENT for the values
40 and 1.5 respectively and it would have been more general. That
would improve the algorithm. On the other hand, programming languages
include constants to allow programs to be easily modified. At
the algorithm development stage, such considerations are not important.
In this case, it was decided to not include constants simply
to make the algorithm easier to read.
If we had not yet written the code but had carefully worked out
this algorithm, it would be easy to now translate this algorithm
into code. Each variable and constant would be appropriately declared;
the Get instructions would be turned into the appropriate pair
of cout and cin instructions; the 'if' statement would have been
written with the arithmetic instructions inside it; and the output
instruction would have been translated as cout..... The moral
of the story is,
C. Purpose and Goal Statements
But, how does one come up with a correct algorithm, one that captures
all the essential steps in the correct order AND is written in
a way easily translated into a programming language. The answer
has three parts. First, one must know how to solve the problem
independent of any computer considerations. That is an issue in
general problem solving and will not be discussed here. We shall
assume that you could solve any of the problems in this material with
paper and pencil if you had to. If you cannot, please consult
another book or someone who does know how to solve the problem.
Please, NEVER try to write code for a problem that you cannot
solve yourself without a computer. PLEASE!
Second, one must have a sense of what happens when instructions
are executed on a computer. As you write each instruction in an
algorithm you need to ask yourself:
Computers have what is called a state which includes:
Each instruction modifies one or more elements of the state. Instructions that include the assignment statement (=), modify or change memory; 'if' statements may cause the computer to jump to a completely different set of instructions; output (cout) instructions modify what is on the monitor. The purpose of an instruction can be described as the modification of the state of the computer in some way. The goal can be described as the state of the computer AFTER the instruction is executed. The goal can be described as the state of the computer AFTER the instruction is executed, that is, the goal represents the state we want the computer to be in after the line or section of code is executed.
Let's add 'Purpose and Goal' statements
to our salary algorithm.
Purpose: To get the rate of pay for an employee from the user
Goal: The variable Rate of Pay has the rate of pay
Get the Rate of Pay for the employee
Purpose: To get the hours worked for an employee from the user
Goal: The variable Hours Worked has the hours worked
Get the Hours Worked for the employee
Purpose: To decide if the employee has worked overtime
Goal: The program counter will be pointing to the appropriate
set of instructions to determine
the salary
if Hours Worked is greater than 40
{
Purpose: To calculate the overtime rate of pay
Goal: The variable Overtime Rate of Pay holds the overtime
rate of pay
Overtime Rate of Pay = Rate of Pay * 1.5
Purpose: To calculate the overtime salary
Goal: The variable Overtime Salary holds the overtime salary
Overtime Salary = Overtime Rate of Pay * (Hours Worked - 40)
Purpose: To calculate the full salary of the employee (overtime
and regular)
Goal: The variable Full Salary holds the full salary of the
employee
Full Salary = Regular Salary + Overtime Salary
Purpose: To output the employee's salary to the screen
Goal: The screen displays the employee's salary.
Output the Full Salary
This sure is full of redundancy isn't it! In essence we have a series of checks and balances here. (Remember your high school civics class?) The goal captures the purpose and the instruction captures both the purpose and the goal. If the goal and the instruction you write are redundant to the purpose and the purpose is the correct purpose for this point in the algorithm, then the instruction is correct. Because writing out algorithms in this redundant format can be so tedious, we will not do it often. However, to get you used to thinking carefully about the meaning and purpose of instructions, you may be asked to follow this "Purpose, Goal, Instruction" format in some exercises.
| |
Main Menu | Next Section |