Lecture 7 Data Types s1
Total Page:16
File Type:pdf, Size:1020Kb
Lecture 8 – Structured Data Types (Part I) - Arrays
Required Reading – HK (Hanly/Koffman), Chapter 8 (Sections 8.1 – 8.6) Required Assignments – Lab 5Arrays. To be done following Lab 6.
A. Introduction – The Concept of an Array
1. What are arrays?
A collection of contiguous memory cells have the same name and the same data type.
We know how to declare individual memory cells, for example
double g; g
which allocates memory for a single type double memory cell named g: ?
How do we declare an array – for example, a type double array x of size 10:
double x[10]; x //
The cells all contains some data, but we do not know what the values of the data in each cell are. Here x is the name of the array and 10 is the size specifier. This specifier should be a positive integer constant such as 10, or the name of a constant specified in a #define statement:
#define maxItem = 10 double x[maxItem];
2. But now we have a problem.
How do we access the individual elements of an array such as x, given that x now names 10 cells and not just one.
We use a subscript, such as x[1] or x[i].
double x[10]; x // 2. 6. -3 5. 0. 7. -1 4. 1. ?
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] We say: The contents of x[1] is 2.0 The contents of x[6] is –1.0 (the decimal point would not fit in the picture).
B. Manipulating the Elements of an Array 1. Reading data from the keyboard into a type double array. We assume that the size of the array is specified as 100 although any positive integer would do as the array size.
#define size = 100 double x[size];
// Function to read a collection of type float data from // the keyboard and store this data in the array x. // Returns number of elements read if function completes as // intended. // Returns –2 if size <= 0 // Returns –1 if file empty // Returns 0 if too many items in file (array is filled // while data remains to be processed)
int fillArray (double x[], // INOUT: array to be filled int size) // IN: size of array { double item; // Temp cell for each item read int count; // Count of number of items read
if (size <= 0) return (–2);
count = 0; // Execute the “priming” or initial read printf(“Enter the first data item: “); scanf (“%f”, &item); // Repeat until no more data. // We will see a bit later how to determine when there // there is no more data. while (/* not at end of file */) { x[count] = item; count++; if (count >= size) return (0); // array full // Execute the “update” or next read printf(“Enter the next data item: “); scanf (“%f”, &item); }
if (count == 0) return (-1); // file empty else return (count); } // end fillArray 2. Computing the sum of the elements in a double array. The code below provides another example of how we process the elements of an array in sequence, from the start of the array (on the left), up to the number of elements in the array (often named n). Assume that n = 9 in this case.
sum = 0; for (int i = 0; i < n; i++) sum = sum + x[i];
Desk check this code for the array x illustrated above and verify that the value of sum will be 21 after the loop executes. What will be the result of executing this loop for n = 5? For n = 0? For n = 12?
Will this sequence of statements work regardless of the double precision values stored in x?
3. Finding the index of the smallest element in the array x declared earlier.
double x[10]; x // 2. 6. -3 5. 0. 7. -1 4. 1. ?
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
The brute force approach: Step 1: Define a new variable,
ixSmall – (int) the index of the smallest item in the array at any time as we look for the index in the entire array.
Step 2: We begin by assuming that the smallest element in the array is element 0 (since we so far have not looked at any of the cells). We note that should this assumption prove false later during our processing, we will redefine the value of ixSmall. So, for now, ixSmall = 0. Step 3: Now we try the following: if (x[1] < x[ixSmall]) ixSmall = 1; // See if the next element in the array is smaller // than the one in x[ixSmall]. If so, reset // ixSmall. Else, do nothing. if (x[2] < x[ixSmall]) ixSmall = 2; if (x[3] < x[ixSmall]) ixSmall = 3; if (x[4] < x[ixSmall]) ixSmall = 4; if (x[5] < x[ixSmall]) ixSmall = 5; if (x[6] < x[ixSmall]) ixSmall = 6; if (x[7] < x[ixSmall]) ixSmall = 7; if (x[8] < x[ixSmall]) ixSmall = 8; Desk check this algorithm. Do you agree that when it has completed executing ixSmall contains the index of the smallest item in the array x?
What is the value of this index?
The loop approach
Here we note that there is a simple pattern to the statement sequence shown above. The pattern is such that the following loop would accomplish the same thing as the eight statements:
ixSmall = 0; for (int i = 1; i < n; i++) if (x[i] < x[ixSmall]) ixSmall = i;
Desk check this loop for n = 9 and verify that it accomplishes the same as the 8 statements written earlier. Be sure you have separate columns for the value of i and for the value of ixSmall as you trace the execution of the loop, and be sure that ixSmall contains the “index of the smallest item in the array” when the loop has completed execution.
Note that the above loop will work no matter how big n is, whether we have 9 elements in the array, or 1000 elements in a large array or even 10000 elements in an even larger array. It will also work regardless of the data in the array x and regardless of the order of the data in the array.
Suppose the array x shown above contained the value –3.0 in x[8] as well as x[2]. What would be the value of ixSmall after the execution of the above loop in this case?
The Function Approach
I now want to take the above loop and enclose it in a function findIXS to find the index of the smallest item in an array of type double data.
What do we want this function to return to the calling component? What do we need to pass this function to enable it to do its work?
Two things are clear.
1) The function is to return the index of the smallest item in the array. 2) We need to pass the function the array in order for it to do its search.
What may be a bit less clear is that we also need to pass the function the number of elements in the array, n. If we fail to pass this information to the function, then we have no way of properly terminating the loop. The resulting function might look like this.
// Function to find and return the index of the smallest // item in a type double array. // Returns the index of the smallest item. // Otherwise returns –1 if n < 0. int findISX (double x[], // IN – array to be searched int n) // IN – number of elements in x { if (n < 0) return (–1);
int ixSmall = 0; for (int i = 1; i < n; i++) if (x[i] < x[ixSmall]) ixSmall = i; return (ixSmall); } // end of findISX
Note that C allows us to leave the size of the array (x in this case) unspecified when we write a function header. It is therefore up to us, when we write functions such as findISX which manipulate arrays, to pass to the function 1) information about which array is to be manipulated (x in this case) and 2) information telling indicating the number of elements to be manipulated (n).
In C, arrays are passed by address, always … they never passed by value.
What will be the value of k resulting from the execution of findISX for the following calls? k = findISX (x, 9); k = findISX (x, 3); k = findISX (x, 0); k = findISX (x, 12); k = findISX (x, 1); 4. Moving the smallest element in the array x to the front of the array.
double x[10]; x // 2. 6. -3 5. 0. 7. -1 4. 1. ?
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
Once we have determined the index of the smallest element in the array x (this index is 2 in the above example), we need to get this element to the front of the array. If we simply write the statements
k = findISX (x, 9); x[0] = x[k];
We will wipe out the value of x[0] (this value will be lost forever). So we must call our trusty swap function to do this work (assuming we have a version of swap written for double precision data).
k = findISX (x, 9); swap (&x[0],&x[k]);
The result of executing these two statements for the array x is shown below.
x[0] and x[k] contents exchanged (k = 2)
x //-3 6. 2. 5. 0. 7. -1 4. 1. ?
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
Note 1: The version of the swap function that we are using will swap any pair of single type double data items, even if those items are array elements.
Note 2: Although arrays are automatically passed to functions by address, individual array elements are passed by value unless preceded by the ampersand in the function call. Thus x[0] and x[k] are just single elements of the array x and must be explicitly passed by address.
5. Sorting an array in ascending order. There are many algorithms for sorting data. Some are more efficient than others. One such algorithm involves the use of the swap and findISX functions written earlier in our lives as “computerists.” This sort is known as a selection sort, because it systematically goes through the array in sequence, selecting the next smallest element in the array and moving that element to its proper position in the array.
The idea behind this sort is this.
1. Find the index of the smallest item in the array. We could write this a bit more precisely as
Find the index, k, of the smallest item in the array x between item x[0] and x[n].
2. Exchange this smallest item x[k] with the item in x[0].
3. Find the index, k, of the smallest item in the array x between item x[1] and x[n]. 4. Exchange this smallest item x[k] with the item in x[1]. (x[0] now contains the smallest item in the array. We therefore want to start with x[1] and find the next smallest item and swap it with x[1] .)
5. Find the index, k, of the smallest item in the array x between item x[2] and x[n]. 6. Exchange this smallest item x[k] with the item in x[2].
7. Find the index, k, of the smallest item in the array x between item x[3] and x[n]. 8. Exchange this smallest item x[k] with the item in x[3]. …
9. Find the index, k, of the smallest item in the array x between item x[n-1] and x[n]. 10. Exchange this smallest item x[k] with the item in x[n-1].
Clearly, there is a pattern here, and we can accomplish the same thing as shown in these steps with the following loop (assume n = 9):
for (int i = 0; i < n-1; i++) { k = findISX (x, n); swap (&x[i],&x[k]); }
Note that we have employed the same tool here as we used in several previous examples. We replaced the reference x[0] in the lines in the body of the function with a reference to x[i]. In this way, we again take advantage of the changes in the loop control variable i, first swapping x[0] and x[k], then x[1] and x[k] (for whatever the value of k is in the second iteration of the loop), then x[2] and x[k], …).
But a problem still remains, and it lies with findISX. As currently written, this function always looks for the smallest item in the array x, starting with x[0] and working up through x[1], x[2], … x[n]. The repeated calls to findISX shown in the above loop will, after the first iteration, always return the same value – namely 0, since the index of the smallest item in the array will, after the first iteration, always be 0.
The question that remains is this; how do we modify findISX so that we can control where it starts its search – so that we are not always stuck searching from x[0] up through x[n]?
We consider re-writing findISX with an additional argument, as shown below.
// Function to find and return the index of the smallest // item in a type double array between element // x[ixStart] and x[ixEnd]. // Returns the index of the smallest item or –1 if n < 0 int findISX (double x[], // IN: array to be searched int ixStart, // IN: starting point for the search int ixEnd) // IN: ending point for the search { if (ixEnd < 0) return –1
int ixSmall = ixStart; for (int i = ixStart+1; i < ixEnd; i++) if (x[i] < x[ixSmall]) ixSmall = i; return (ixSmall); } // end of findISX
We can now re-write the for loop to do our sort as
for (int i = 0; i < n-1; i++) { k = findISX (x, i, n); swap (&x[i],&x[k]); }
This loop performs the selection sort we need.
Desk check the new function findISX to be sure that it always returns the index of the smallest item in an array between item x[startIX] and x[endIX].
Now desk check the function above to be sure it sorts the array x in ascending order.
Write a function selsort to sort a type double array x in ascending order. The function should return a value of –1 if n < 0. Otherwise it should perform the sort and return a value of 0.
How would you modify the code in findISX so that the sort would arrange the data in x in descending order?