A scan algorithm answers a question by walking through a sequence of values once. As it goes, it keeps track of information about the sequence of values that it has seen so far.
A key property of a scan algorithm is that the information being kept includes, at a minimum, the answer to the question, assuming that the algorithm is at the end of the input sequence. That way, when it actually does reach the end, the algorithm knows the answer to give.
Here are some examples of problems that are natural candidates for scan algorithms.
Add up a sequence of numbers x1,..., xn. As you scan through the sequence, keep track of the sum of the numbers that you have seen so far. That way, when you reach the end of the sequence, you know the sum of the entire sequence of numbers.
Compute the factorial n! of n. Since n! = 1*2*...*n, just scan through sequence 1, 2, ..., n, keeping track of the product of the numbers seen so far.
Find the largest of x1,..., xn. As you scan, keep track of the largest number that you have seen so far.
Convert a string of digits to an integer. As you scan, remember the number that the digits seen so far stand for. Each time you encounter a new digit d, replace your current number x by 10*x + d. For example, converting string "2545" to an integer works as follows.
Scanned so far | x | |
---|---|---|
"" | 0 | |
"2" | 2 | |
"25" | 25 | |
"254" | 254 | |
"2545" | 2545 |
A loop is an obvious way to implement a scan algorithm, and it is usually the recommended approach. Just be sure to initialize your variables, to scan through the sequence correctly, and to update the information that you are keeping correctly. Here are implementations of problems similar to each of the above problems.
//=============================================== // sum(A,n) returns A[0] + A[1] + ... + A[n-1]. //=============================================== int sum(const int A[], const int n) { int total = 0; for(int i = 0; i < n; i++) { total = total + A[i]; } return total; } //=============================================== // factorial(n) returns n!. //=============================================== int factorial(const int n) { int f = 1; for(int i = 1; i <= n; i++) { f = f * i; } return f; } // largest(A, n) returns the largest // of A[0], ..., A[n-1]. // // Requirement: n > 0. int largest(const int A[], const int n) { int big = A[0]; for(int i = 1; i < n; i++) { big = max(big, A[i]); } return big; } //=============================================== // ___________________________________________________________ // |This example uses the idea of a null-terminated | // |string, which is an array of characters that | // |ends on a null character, '\0'. For example, | // |string "123" is represented as an array s where | // | s[0] = '1' | // | s[1] = '2' | // | s[2] = '3' | // | s[4] = '\0' | // |We will look at null-terminated strings in detail | // |later. | // | | // |If character c is a digit then c - '0' is the integer that | // |c stands for. For example, '2' - '0' = 2. Don't confuse | // |character '0' (the digit 0) with '\0' (the null character).| // |___________________________________________________________| // // convertToInt(s) yields the integer described // by string s. For example, convertToInt("325") // = 325. // // Requirement: s must be a null-terminated string // that only contains decimal digits. //=============================================== int convertToInt(const char s[]) { int x = 0; for(int i = 0; s[i] != '\0'; i++) { x = 10*x + (s[i] - '0'); } return x; }
Remark. There is a library function called atoi that does the same thing as convertToInt. Include <cstdlib> to use atoi.
Sometimes you want accumulate information about only selected values in a sequence of values. To do that, just scan through the sequence, skipping over values that are not of interest. The following illustrates. We assume that a function isPrime(n) is available, which returns true just when n is prime.
//============================================== // sumPrimes(n) yields the sum of the prime // numbers that are less than or equal to n. // For example, sumPrimes(5) = 2 + 3 + 5 = 10. //============================================== int sumPrimes(const int n) { int total = 0; for(int i = 2; i <= n; i++) { if(isPrime(i)) { total += i; } } return total; }
A scan algorithm solves a problem by making one scan over a sequence of values. Examples of scans are adding up a list of numbers and finding the largest value in an array.
Scan algorithms occur frequently in practice. Suppose that A is an array of size n. A boilerplate scan algorithm to scan A is as follows.
initialize result variable(s) for(int i = 0; i < n; i++) { update result variable(s) }
Write a function productOdds(n) that yields the product of the odd positive integers that are less than or equal to n. Assume that n and the result have type int. Answer
Write a definition of function sumcubes(n), which returns 13 + 23 + … + n3. Answer
Write a definition of largestPrime(A, n), which returns the largest of A[0], … A[n−1] that is prime, where A is an array of ints. Assume that function isPrime(n) is available. If none of those integers is prime then largestPrime(A, n) should return 0;
If a prime number that is greater than A[i] has already been found when A[i] is being considered, then largestPrime should not compute isPrime(A[i]) at all, since it is clear that A[i] cannot be the largest prime number in array A.
Answer