When we examined recursion, we introduced the concept of a named subalgorithm. Here we look at these in the nonrecursive context and discuss how we pass information back and forth between algorithm and subalgorithm. Because we are talking about actual language constructs, we call these structures subprograms rather than subalgorithms.
Many subprograms are available as part of a high-level language or as part of the library that comes with the language. For example, mathematical problems often need to calculate trigonometric functions. Subprograms that calculate these values are available in most high-level languages in one way or another. When a program needs to calculate one of these values, the programmer looks up the name of the subprogram that calculates the value and just calls the subprogram to perform the calculation.
If one of these subprograms needs to have information passed to it, the calling unit sends over the values for the subprogram to use. For example, the following two statements set x to m times the sine function of t and y to the absolute value of z. The sine function and the absolute value function are built into many languages. The information sent to the sine function is t; the information sent to the absolute value function is z. Both of these functions are value-returning subprograms.
The same is true when you write your own subprograms. We now look at the mechanism used for passing information back and forth between the calling program and subprogram.
We have assumed these capabilities in the algorithms relating to the abstract data types we have examined. Take, for example, the following list algorithm:
Insert needs a list and a value to insert into it. Reset needs the list to reset. MoreItems needs the list to see if more items remain to be returned. GetNext needs the list as input and returns the next item in the list. This communication is done through the concept of a parameter list.
A parameter list is a list of the identifiers or values with which the subprogram is to work; it appears in parentheses beside the subprogram name. Because a subprogram is defined before it is called, it does not know with which variables from the calling unit it is to work. To solve this dilemma, we specify a list of variable names in parentheses beside the subprogram name. These identifiers are called parameters. When the subprogram is called, the calling unit lists the subprogram name, followed by a list of identifiers in parentheses. These identifiers are called arguments. The arguments represent actual variables in the calling unit with which the subprogram is to work.
You can think of a parameter as being a temporary identifier that is used within a subprogram. When a subprogram is called, the calling unit sends the names of the actual identifiers the subprogram is to use. The action in the subprogram is defined using the parameters; the action is executed using the arguments. When the action takes place, the arguments are substituted one by one for the parameters. This substitution can be done in several ways, but the most common practice is by position. The first argument substitutes for the first parameter, the second argument substitutes for the second parameter, and so on.
We have promised not to look at too many implementations, but this one is easy. We can implement a list using an array and a length field. When we add an item to the list, we store it in the array (values) at the length – 1 position and increment length. We bind the values and the length together into a record called list, which we pass to the subprogram that needs it.
list is the parameter and mylist is the argument. When Insert is executed, myList replaces list.
The substitution mechanism acts much like a message board. When a subprogram is called, a list of the arguments is given to the subprogram (put on the subprogram’s message board). These arguments tell the subprogram where to find the values to use. When a parameter is used in the body of the subprogram, the subprogram accesses the argument through its relative position on the message board. That is, the subprogram looks for its first parameter in the first position on the message board and for its second parameter in the second position on the message board.
The number of arguments in the call must match the number of parameters in the subprogram heading. Because the arguments and parameters are matched by position, their names don’t have to be the same. This is very helpful when a subprogram is called more than once, with different arguments in each call. Parameters passed in this fashion are often called positional parameters.
There are two basic ways of passing parameters: by value and by reference (or address). If a parameter is a value parameter, the calling unit gives a copy of the argument to the subprogram. If a parameter is a reference parameter, the calling unit gives the address of the argument to the subprogram. This very fundamental difference means that a subprogram cannot change the content of a value argument because it receives only a copy of the argument. The subprogram can modify the copy, but the original variable will not be changed. In contrast, any argument passed by the calling unit to a reference parameter can be changed by the subprogram because the subprogram manipulates the actual variable, not a copy of it. In the previous example, the record being passed as list must be a reference parameter. If it is not, items would be inserted into the copy, not the original.
Think of the difference this way: To access a reference parameter, the subprogram accesses the contents of the address listed on the message board. To access a value parameter, the subprogram accesses the contents of the message board. Clearly, both the calling unit and the subprogram must know which parameter/argument is to be passed by value and which is to be passed by reference. Not all high-level languages allow both kinds of parameters, but those that do have some syntactic schemes to label parameters as value or reference.
Before we leave subprograms, let’s look at an example that illustrates the difference between value and reference parameters. We have already written an algorithm that swaps the contents of two places in memory. Here is the solution without problem-dependent variable names:
Now suppose that the calling unit (the part of the program that wants the contents of the two places exchanged) calls Swap with data1 and data2 as parameters.
Now let’s say that data1 is stored in location 0002 and data2 is stored in location 0003. These locations contain the values 30 and 40, respectively. FIGURE 8.15 shows the content of the message board when the parameters are passed by value and passed by reference. When a parameter is a value parameter, the subprogram knows to manipulate the value on the message board. When a parameter is a reference parameter, the subprogram knows to manipulate the contents of the address on the message board. Should the parameters for subprogram Swap be value or reference parameters?
Before we leave the topic of subprograms and parameters, let’s implement three more of the list subprograms: getLength, IsThere, and Delete. If the list items are not to be kept in sorted order, we can just put the first one in the length position and increment length. For this example, let’s assume that only one copy of each item can be in the list.
IsThere is a subprogram that returns a value—in this case, a Boolean value. Thus it would be used in an expression such as
This type of subprogram is called a value-returning subprogram. Delete and Insert, in contrast, do not return a specific value. However, they do return the changed list through its parameters. If we assume that the item to be deleted is in the list, the implementation is simple: When we find the item to be deleted, we just exchange it with the last item in the list and decrement length.
IsThere can be used to make sure that the item to be deleted is in the list.
Value-returning subprograms include the RETURN statement followed by a value to be returned. Non-value-returning subprograms may have a RETURN statement, but it is unnecessary. To conclude this section, here is a code segment that reads values into the list and then deletes some values:
Lists, stacks, queues, trees, and graphs are all useful abstract composite structures. Each has its own defining property and the operations that guarantee that property. All of these abstract structures include operations to insert items and to remove items. Lists and trees also have operations to find items within the structure.
Lists and trees have the same properties: Items can be inserted, deleted, and retrieved. Items can be inserted in a stack, but the item removed and returned is the last item inserted into the stack—that is, the item that has been in the stack the shortest time. Items can be inserted into a queue, but the item removed and returned is the first item put into the queue—that is, the item that has been in the queue the longest time.
Lists, stack, queues, and trees are merely holding structures, but graphs are more complex. A wealth of mathematical algorithms can be applied to information in a graph. We examined three of these: the breadth-first search, the depth-first search, and the single-source shortest-path search.
Subprogram statements allow subalgorithms to be implemented independently. A subprogram may be value returning, in which case it is called by placing its name and arguments within an expression. Alternatively, a subprogram may be non-value-returning (void), in which case the subprogram name is used as a statement in the calling program. Data sent to and from subprograms are transmitted by the use of parameter lists. Parameters may be either reference or value parameters. An argument is passed to a value parameter by sending a copy of the argument to the subprogram. An argument is passed to a reference parameter by sending the address of the argument to the subprogram.
For Exercises 1–10, indicate which structure would be a more suitable choice for each of the following applications by marking them as follows:
Stack
Queue
Tree
Binary search tree
Graph
For Exercises 11–30, mark the answers true or false as follows:
True
False
The following algorithm (used for Exercises 31–33) is a count-controlled loop going from 1 through 5. At each iteration, the loop counter is either printed or put on a stack, depending on the result of Boolean function RanFun(). (The behavior of RanFun() is immaterial.) At the end of the loop, the items on the stack are popped and printed. Because of the logical properties of a stack, this algorithm cannot print certain sequences of the values of the loop counter. You are given an output and asked if the algorithm could generate the output. Respond as follows:
True
False
Not enough information
The following algorithm (used for Exercises 34–36) is a count-controlled loop going from 1 through 5. At each iteration, the loop counter is either printed or put on a queue, depending on the result of Boolean function RanFun(). (The behavior of RanFun() is immaterial.) At the end of the loop, the items on the queue are dequeued and printed. Because of the logical properties of a queue, this algorithm cannot print certain sequences of the values of the loop counter. You are given an output and asked if the algorithm could generate the output. Respond as follows:
True
False
Not enough information
Exercises 37–50 are short-answer questions.
Exercises 51–55 are short-answer questions based on the following directed graph.
Exercises 56–60 are short-answer questions based on the following directed graph.
Exercises 61–69 are short-answer exercises.
A spreadsheet is a table with rows and columns. Think about an ADT spreadsheet. Which operations would you need to construct the table? Which operations would you need to manipulate the values in the table?
Binary trees, binary search trees, and graphs are visualized as nodes and arrows (pointers) that represent the relationships between nodes. Compare these structures in terms of the operations that are allowed. Can a list ever be a tree? Can a tree ever be a list? Can a tree ever be a graph? Can a graph ever be a tree? How do the structures all relate to one another?
Before computers, water-cooler conversations were thought to be private. How has computer technology changed this assumption?
How do the rights of employees collide with privacy rights in the workplace?
18.191.223.123