Hour 9
Programming Algorithms

In this hour, you will learn about programming algorithms that are common across all programming languages. An algorithm is a common procedure or methodology for performing a certain task. In mathematics, an algorithm provides a step-by-step method for solving a problem in a finite number of steps that can require some repetition. To keep things simple, in this hour you’ll see algorithms in Python, but the concepts you’ll learn here are important no matter which programming language you use.

You will learn how to use programs to count data values and accumulate totals. This technique has been touched on in earlier lessons, but this hour will formalize your understanding of the topic. The computer is a perfect tool for counting values such as the number of customers in a day, month, or year or the number of inventory items in a department’s warehouse. A computer is capable of lightning-fast accumulations of totals. You can use a computer to easily determine the total amount of a weekly payroll or the total amount of your tax liability this year.

Computers are masterful at sorting and searching for data. When you sort data, you put it in alphabetical or numerical order. There are different methods for doing this, and this hour presents the most common one. There are also many ways to search a list of data for a specific value. You might give a computer a customer number, have it search a customer list, and then have it return the full name and account balance for that customer. Although computers are fast, it takes time to sift through thousands of data items, especially when searching through disk files (as the disk is much slower than memory). Therefore, it behooves you to gain some insight into some efficient means of performing a search.

After helping you master the sorting and searching techniques, this hour finishes by going a bit deeper with a topic you were introduced to in the last lesson: functions.

The highlights of this hour include the following:

Image Counting with counter variables

Image Storing data in array variables

Image Totaling with accumulator variables

Image Swapping the values of two variables

Image Understanding ascending and descending sorts

Image Using the bubble sort

Image Searching for values in unsorted lists

Image Using a binary search

Image Using functions to divide the jobs in a program

Image Nesting loops to improve a program’s effectiveness

Counters and Accumulators

When you see a statement such as the following, what do you think?

number = number + 1

Your first impression might be that the statement isn’t possible. After all, nothing can be equal to itself plus one. Take a second glance, however, and you will see that in a programming language such as Python, the equal sign acts like a left-pointing arrow. The assignment statement, in effect, says “Take whatever is on the right side of the equal sign, evaluate it, and put it in the variable to the left of the equal sign.” Most other programming languages also use assignment statements that work like the Python assignment.

When Python reaches the statement just shown, it adds 1 to the contents in the variable named number. If number was equal to 7 to begin with, it is now equal to 8. After Python adds the 1 and gets 8, it then stores 8 in number, replacing the 7 that was originally there. The final result is one more than the initial value.

When you see a variable on both sides of an equal sign, and you are adding 1 to the variable, you are incrementing that variable’s value. You might remember from earlier lessons that adding 1 to a variable is useful. Many programmers put such an assignment statement inside a loop to count items. The variable used is called a counter. Every time the loop repeats, 1 is added to the counter variable, incrementing it. When the loop finishes, the counter variable has the total of the loop.

Python (and other programming languages, such as C) have multiple ways to add 1 to a variable, and you’ve seen most of them already. Each of the following two statements adds 1 to the variable count:

count = count + 1;

count += 1;

As an added note, while you cannot use the following statement to increment a variable by 1 in Python, it does work in other languages, such as C and JavaScript:

count++;

For both choices that work with Python, they can add any number to your variable; you just need to change the 1 to the number you’d like to add. That includes integers or floating-point numbers. You can also add a variable in that spot as well, as the following line of code would add newAmount to count:

count += newAmount;

Subtracting 1 is just as easy. Again, the following two statements both subtract 1 from the variable count, and again you can subtract any number by replacing the 1 with that number:

count = count - 1;

count -= 1;

In languages other than Python, just as you can use count++ to add 1, you can use count-- to subtract 1 (but don’t try this in Python, as it does support that operator).

Python Lists

Anytime you find yourself writing two or more sets of statements where the only differences are the variable names, you are probably not taking advantage of a better programming style. The program to check grades that you wrote in Hour 6, “Controlling Your Programs,” was far more effective because you used lists for both the names of the students and their test scores.

Tip

Another advantage to using lists for a set of similar variables is that you can take advantage of the powerful loop statements you learned in Hour 6. The goal of programming is to make your life simpler, not harder. Whenever you can put repetitive code into a loop, you save wear and tear on your fingers.

Dictionaries

In Hour 6, you saw how to use lists to create a grading program. You created two lists—one with student names and another with the grades—and then printed the two, using the same index. This technique works well as long as you keep the two arrays aligned. Another way to handle this in Python is with a dictionary.

A dictionary is a collection of data with key/value pairs. It’s easy to visualize if you consider an actual dictionary, which has words and then their definitions. The word is the key, and the definition is the value. If you were using Python to create a dictionary of the dictionary, it would look like this:

Webster = {"ant":"A small insect", "car":"a motor vehicle"}

A dictionary that defines only two words isn’t the greatest, but you can make the dictionary as long as you want, and you can easily add additional entries. If you decided to add a third word to your Webster dictionary, you could easily do so, like this:

Webster["guitar"] = "a stringed musical instrument"

Now your dictionary has three elements. Unlike with strings or lists, you do not access an individual element by using a number; with a dictionary, you use the key. So if you want the definition of the third word, you don’t use Webster[2], as that generates an error message. You use Webster["guitar"].

Accumulators for Total

It’s not terribly useful to just print the monthly sales total, so the program in Listing 9.3 adds the sales for the year as well as an average monthly sales total. You could take it even further and add quarterly totals or multi-year totals, but to do that, you’d need to specify the month and year in the keys as you cannot repeat keys in dictionaries. If you try to do so, you will just overwrite the previous entry.

LISTING 9.3 A sales-reporting and averaging program can use an accumulator for sales totals

# SalesTotals2.py

# A program that initially creates a dictionary of months
# with 0 sales totals per month and then obtains the
# sales from the user, finally printing out
# It then prints a total and an average


# Dictionary created with the first six months and no sales
SalesMonths = {"Jan": 0, "Feb": 0, "Mar": 0, "Apr": 0, "May": 0, "Jun": 0}

# We forgot the second half of the year, so add them to the dictionary
SalesMonths["Jul"] = 0
SalesMonths["Aug"] = 0
SalesMonths["Sep"] = 0
SalesMonths["Oct"] = 0
SalesMonths["Nov"] = 0
SalesMonths["Dec"] = 0

# Loop through all the months to get actual sales
for x in SalesMonths:
    Question = "What were the Sales in " + x + "? "
    SalesMonths[x] = float(input(Question))

# Print out the sales by month
print("

")
for y in SalesMonths:
    print(y, SalesMonths[y])

# Calculate both total sales and average sales by month
TotYear = 0
Entries = 0
for y in SalesMonths:
    TotYear += SalesMonths[y]
    Entries += 1
print("Total year's sales were ", TotYear)
print("An average month's sales were ", (TotYear/Entries))

Figure 9.3 shows the results of running Listing 9.3.

images

FIGURE 9.3
You can use accumulator variables to calculate totals and averages.

The program in Listing 9.3 is almost the same as the one in Listing 9.2. The major difference is that Listing 9.3 totals all sales, prints that out, and calculates an average. This is a common method of development: adding functionality to a program that works. When you know a program works, you can add a little bit more and ensure that is still works. Users of a program may reach out and say, “this is great, but could it also...,” and then you have to decide whether to put the time in to add the code needed to make it do more.

Swapping Values

The cornerstone of any sorting algorithm is data swapping. As you sort data, you have to rearrange it, swapping higher values for lower values. As Figure 9.4 shows, swapping values simply means replacing one variable’s contents with another’s and vice versa.

images

FIGURE 9.4
Swapping the values of two variables.

Suppose you assigned two variables named variable1 and variable2 with the following statements:

variable1 = 65
variable2 = 97

How would you swap these variables? It’s simple:

variable1 = variable2
variable2 = variable1

Can you see why these two assignment statements don’t swap the values in the two variables? The first statement assigns variable2 to variable1, which wipes out variable1’s original value. The second statement is then redundant because after the first statement, both variables already hold the same value.

An accurate approach to swapping variables is to use a third variable, often called a temporary variable because you don’t use its value after you swap the original variables. Here is the code to perform the swapping accurately:

temp = variable1
variable1 = variable2
variable2 = temp

Sorting

The following list of numbers isn’t sorted:

10
54
34
21
23

Here is the list sorted in ascending order (from lowest to highest):

10
21
23
34
54

Here is the list sorted in descending order (from highest to lowest):

54
34
23
21
10

You can also sort character string data, such as a list of names. Here is a list of five sorted names (unless otherwise specified, an ascending sort is always used):

Adams, Jim
Fowler, Lisa
Kingston, William
Stephenson, Mike
Williams, Pete

Using the Bubble Sort

There are several ways to sort lists of data. The most popular one for beginning programmers is to use the bubble sort. The bubble sort isn’t the most efficient sorting algorithm. As a matter of fact, it is one of the slowest. However, the bubble sort, unlike other sorting algorithms (such as the heap sort and the quick sort) is easy to understand and to program.

Note

Lists in Python actually have a sort() function built right in! But how will you learn anything if you just use the built-in methods?

In Python, the data that you want to sort is typically stored in a list. Using the list subscripts, you can rearrange the array elements, swapping values until the list is sorted in the order you want.

In the bubble sort, the elements of an array are compared and swapped two at a time. Your program must perform several passes through the list before it is sorted. During each pass through the list, the bubble sort places the lowest value in the first element of the array. In effect, the smaller values “bubble” their way up the list—hence the name bubble sort.

After the first pass of the bubble sort (which is controlled by an outer loop in a nested for loop, as you will see in the following program), the lowest value, 10, is still at the top of the array (as it happened to be there already). In the second pass, 21 is placed right after the 10 and so on until no more swaps take place.

Analyzing the Bubble Sort

To give you a better understanding of the bubble sort routine used in this program, Figure 9.5 shows a flowchart of the bubble sort process. By using the flowchart and by following the program, you should be able to trace through the bubble sort and better understand how it works. At the heart of any sorting algorithm is a swapping routine, and you can see one in the body of the bubble sort’s for loops.

images

FIGURE 9.5
The flowchart of the bubble sort routine shows the swapping of values.

If you really want to see the bubble sort in action, you can add print() statements to your program to see a printout of the list before the sort begins and also see a printout after each step along the way. It can get a little tedious to see a printout after each step of the sort, but adding the print lines to Listing 9.4 would result in the following code:

# Filename bubblesort.py
# Uses the bubble sort algorithm to sort a
# set of values

values = [10, 54, 34, 21, 23]
temp = 0

# Outer loop
print("Here is the loop before sorting...")
print(values)

for x in range(len(values)):
    # Inner loop for comparisons
    for ctr in range(len(values)-1):
        if (values[ctr] > values [ctr+1]):
            temp = values[ctr]
            values[ctr] = values[ctr+1]
            values[ctr+1] = temp
        print("Here is the loop as the sort continues...")
        print(values)

print("Here is the loop after sorting...")
print(values)

Running the updated program would yield the following output:

Here is the loop before sorting...
[10, 54, 34, 21, 23]
Here is the loop as the sort continues...
[10, 54, 34, 21, 23]
Here is the loop as the sort continues...
[10, 34, 54, 21, 23]
Here is the loop as the sort continues...
[10, 34, 21, 54, 23]
Here is the loop as the sort continues...
[10, 34, 21, 23, 54]
Here is the loop as the sort continues...
[10, 34, 21, 23, 54]
Here is the loop as the sort continues...
[10, 21, 34, 23, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop as the sort continues...
[10, 21, 23, 34, 54]
Here is the loop after sorting...
[10, 21, 23, 34, 54]

Tip

If you want a descending sort, you only have to change one statement in Listing 9.4’s program—the first statement inside the for loops. Instead of swapping the values if the second item of the pair is lower, you can swap them if the second item of the pair is higher. The new line looks like this:

if (values[ctr] < values[ctr + 1])

Searching Lists

There are many ways to search lists for a specific value. Suppose you have several parallel lists with inventory data. The first list, partNo[], holds all your inventory item part numbers. The second list, desc[], holds a description of each of those parts. The third list, price[], contains the price of each corresponding part. You might keep all the inventory data in the cloud and then read that data into the parallel arrays when it is time to work with the data.

One use for an inventory program that uses parallel lists is a lookup routine. A user could type a part number, and the computer program would search the partNo[] list for a match. When it finds one (for example, at element subscript number 246), you could then print the 246th element in the desc[] and price[] arrays to show the user the description and price of the part number just entered.

There are several ways to search a list for values. The various searching methods each have own advantages. One of the easiest to program and understand, the sequential search, is also one of the least efficient. The search method you decide on depends on how much data you expect to search through and how skilled you are at understanding and writing advanced searching programs. The next few sections walk you through some introductory searching algorithms that you might use someday in the programs you write.

Note

Again, as with sorting, in Python, lists, sets, tuples, and dictionaries have built-in methods to make searching easier, but the point of this exercise is to get you to figure out how to write code to solve a problem.

Performing the Sequential Search

The sequential search technique is easy but inefficient. With it, you start at the beginning of the list and look at each value, in sequence, until you find a value in the list that matches the value for which you are searching. (You then can use the subscript of the matching element to look in corresponding parallel lists for related data.)

Tip

The list being searched doesn’t have to be sorted for the sequential search to work. The fact that sequential searches work on unsorted lists makes them more useful than if they required sorted lists because you don’t have to take the processing time (or programming time) to sort a list before each search.

Figure 9.6 shows a flowchart of the sequential search routine. As with most of the other flowcharts in this hour, only the new technique—in this case, the sequential search routine—is described, not the now-trivial task of filling the array with data through disk input/output (I/O) or user input. Study the flowchart and see if you can think of ways to improve the searching technique being used.

images

FIGURE 9.6
Flowcharting the sequential search technique.

Performing the Binary Search

If your list is already sorted, you can use another technique that offers tremendous searching speed advantages over the sequential search shown in the previous section. This technique is known as the binary search. The binary search is more complex to understand and program than the sequential search, but, as with most other things in the programming world, it is worth the effort in many cases.

The binary search technique uses a divide-and-conquer approach for searching. One of the primary advantages of the binary search is that with every comparison you make, you can rule out one-half of the remaining array if a match isn’t found. In other words, if you are searching for a value in a 100-element list, and the first comparison you make fails to match, you only have at most 50 elements left to search; with the sequential search, you would still have a possible 99 elements left to search. On the second search, assuming that there is no match, you rule out one-half of the remaining list, meaning that there are only 25 more items to search through.

The multiplicative advantages of a binary search will surprise you. If you have a friend write down a number from 1 to 1,000 and then use the binary search technique to make your guesses (your friend will only have to tell you if you are “too low” or “too high” with each guess), you can often zero in on the number in 5 to 15 tries. This is an amazing feat when there is a pool of 1,000 numbers to choose from!

The binary search technique is simple. Your first guess (or the computer’s first try at matching a search value to one in the list) should be exactly in the middle of the sorted list. If you guess incorrectly, you only need to know if you were too high or too low. If you were too high, your next guess should split the lower half of the list. If you were too low, you should split the higher half of the list. Your new list (one-half the size of the original one) is now the list you split in the middle. Repeat the process until you guess the value.

Suppose your friend thinks of the number 390. Your first guess would be 500 (half of 1,000). When your friend says “too high,” you would immediately know that your next guess should be between 1 and 499. Splitting that range takes you to your second guess, 250. “Too low,” replies your friend, so you know the number is between 251 and 499. Splitting that gives you 375. “Too low” means the number is between 376 and 499. Your next guess might be 430, then 400, then 390—and you’ve guessed it. One out of 1,000 numbers, and it only took six guesses.

Listing 9.6 uses the binary search technique to find the correct inventory value. As you can see from the code, a binary search technique doesn’t require a very long program. However, when you first learn the binary search, it takes some getting used to. Therefore, the flowchart in Figure 9.7 will help you understand the binary search technique a little better.

LISTING 9.6 A binary search can speed searching tremendously

# Filename: searchbin.py

# Binary search for an item's description and price.
# (This assumes the arrays have been filled
# and SORTED in PartNum order elsewhere.)

#  This code would be part of a larger inventory program.
# ** This program assumes that the variable named TotalNumber
# contains the total number of items in the inventory,
# and therefore, in the arrays as well.

# for testing, here is the same parts as before, just in correct order
TotalNumber = 5
PartNo = [12, 34, 40, 87, 99]
Desc = ["monitor", "mouse", "keyboard", "printer", "graphics card"]
price = [99.99, 19.99, 35.00, 49.50, 103.75]

# First, get the part number the user wants to look up

searchPt = int(input('What is the number of the part you want to see? '))

first = 0 # Set the lower bound of your search
last = TotalNumber - 1 # The upperbound of the search
found = 0 # The flag that the part was found

while (first <= last):
    mid = int((first + last) / 2) # Set the middle and make it an int
    if (searchPt == PartNo[mid]):
        print("Part number", searchPt, "'s description is ")
        print(Desc[mid])
        print("With a price of $",price[mid])
        found = 1 # Turn the flag on
        break # Exit the while loop
    elif (searchPt < PartNo[mid]): # Check the lower half of the array
        last = mid - 1
    else:
        first = mid + 1 # Check the upper half of the array

if (found == 0): # The part was not in the array
     print("** Sorry, but that part number is not in the inventory.")
images

FIGURE 9.7
Flowcharting the binary search.

Taking Functions Further

User-created functions, introduced in Hour 6, deserve a bit more discussion. A function is like a detour; it is a side trip your program makes for a few statements, often to accomplish a specific task, and then the program gets back on the path it was executing and continues from there.

The function is a set of code that works as a unit, as a method works. Functions (also called subroutines in some programming languages) are available for all languages, and they aren’t difficult to understand. The algorithms presented in this hour make perfect candidates for functions. A function turns your program into a collection of modules that you can integrate. Instead of being one long program, your program becomes lots of little sets (functions) of code.

Understanding the Need for Subroutines

Suppose you’re writing a program that prints your name and address several times. Without using a function, you would write code similar to the snippet shown in Listing 9.7. The program repeats the same printing code over and over.

LISTING 9.7 A program outline that doesn’t use functions can be hard to maintain

# Long program that prints name and address throughout
#  (The rest of the code is not shown.)

# # Program statements go here

print("Mark Cunningham")
print("1244 West Oak")
print("Canton, NH 63443")

#  More program statements go here

print("Mark Cunningham")
print("1244 West Oak")
print("Canton, NH 63443")

#  More program statements go here

print("Mark Cunningham")
print("1244 West Oak")
print("Canton, NH 63443")

#  More program statements go here

print("Mark Cunningham")
print("1244 West Oak")
print("Canton, NH 63443")

# Rest of program finishes up here

Caution

Not only is repeating the same code tedious, but by requiring more typing, it is extremely susceptible to errors. If you only have to type in the code once but can execute that code repeatedly whenever you want (as in a function), your chances of making typing errors decrease. Also, if your address ever changes, you only have to change it in one place (inside the subroutine) rather than everywhere it appears in the program.

If you put print() statements in a function, you can save yourself some typing. It also becomes easier to transfer the code to another program. All you need to do is write the function and then call it as often as you like.

Listing 9.8 is an improved version of the previous program. Notice that a statement begins the subroutine’s name and address printing code. This is a label that you make up that names the subroutine’s location.

LISTING 9.8 A program outline that uses functions is simple

# Function Example

def function printAddress():
"Here's where we print the address"
       print("Mark Cunningham")
       print("1244 West Oak")
       print("Canton, NH 63443")
       return
          }


# Long program that prints name and address throughout
# (The rest of the code is not shown.)


# Program statements go here

printAddress() # Runs the function

# More program statements go here

printAddress() # Runs the function

# More program statements go here


printAddress() # Runs the function

# More program statements go here

Tip

As mentioned in Hour 8, “Structured Techniques,” you can put your commonly used functions in a separate .py file that you can then import into any other Python file that needs to use those functions.

Tip

By asking users how many numbers they want to enter, the program has far more value than a program that can only sort a set number of values. Printing the numbers before and after the sort shows the value of functions, as you’ve called the function twice in the program but had to write the code only once.

Nested Loops

As with almost all other statements, you can nest two or more loops inside one another. Several listings in this hour, including Listing 9.9, have done just that. As a programmer, you must make sure you understand the concept of nested loops. Anytime your program needs to repeat a loop more than once, use a nested loop. Think of the inside loop as looping “faster” than the outside loop. The inside loop iterates faster because the counter variable of the inside loop goes through all its iterations before the outside loop’s first iteration has completed. The outside loop doesn’t repeat until its block of code is complete. When the outside loop finally does iterate a second time, the inside loop starts all over again.

So, if you have an outer loop that is set to run 5 times and an inner loop that is set to run 10 times, the inner loop executes a total of 50 times. The outside loop iterates 5 times, and the inside loop executes 10 times for each iteration of the outer loop.

Summary

The techniques you learned in this hour will be useful throughout your programming career. Sorting, searching, and functions are needed for useful data processing. The computer, thanks to your programs, can do these mundane tasks while you concentrate on more important things.

The next hour gives you a break from algorithms and shows you how to write some programs that use graphics. Programming can be fun, and graphics are quite possibly the most fun part of programming.

Q&A

Q. How do functions improve a program’s accuracy?

A. A program is easier to write and maintain when you group routine code into functions. The functions help you focus on specific parts of the program that you need to change or fix if bugs exist in the code. When your program is composed of small routines, in functions, you make your code more modular, which helps ensure that code in one part of the program doesn’t affect code in another part of the program.

Workshop

The quiz questions are provided for your further understanding.

Quiz

1. What is an accumulator?

2. True or false: The following statement is an accumulator statement:

num = num - 1

3. What is the difference between the terms ascending sort and descending sort?

4. Why is a third variable needed when you want to swap the values of two variables?

5. Which sort is the easiest to write and understand?

6. True or false: A counter statement is a special kind of accumulator statement.

7. What is the simplest kind of search technique?

8. Which is more efficient: the binary search or the sequential search?

9. Write a function that doubles a number, adds 2, and returns the new value.

10. True or false: Using functions prevents you from typing the same code over and over throughout a program.

Answers

1. An accumulator is a variable whose value is updated.

2. False. Although the statement might actually be using an accumulator variable, the statement happens to be decreasing the value stored there, whereas accumulators are usually added to.

3. An ascending sort puts lists in order from low to high, and a descending sort puts lists in order from high to low.

4. The third variable is needed to hold one of the values temporarily.

5. The bubble sort is one of the simplest sorts to write and understand.

6. True

7. A sequential search is the simplest type of search.

8. The binary search is far more efficient than the sequential search.

9. Your answer might be slightly different but this is one possible answer:

def changenumber(x):
        var y = x * 2
        z = y + 2
        return (z)

10. True

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset