9.3 Stack ApplicationsThe Stack ADT is required by a number of applications encountered in computer science. In this section, we examine two basic applications that traditionally are presented in a data structures course. Balanced DelimitersA number of applications use delimiters to group strings of text or simple data into subparts by marking the beginning and end of the group. Some common examples include mathematical expressions, programming languages, and the HTML markup language used by web browsers. There are typically strict rules as to how the delimiters can be used, which includes the requirement of the delimiters being paired and balanced. Parentheses can be used in mathematical expressions to group or override the order of precedence for various operations. To aide in reading complicated expressions, the writer may choose to use different types of symbol pairs, as illustrated here: {A + (B * C) - (D / [E + F])} The delimiters must be used in pairs of corresponding types: (A + [B * C)] - {D / E} Another common use of the three types of braces as delimiters is in the C++ programming language. Consider the following code segment, which implements a function to compute and return the sum of integer values contained in an array: int sumList( int theList[], int size ) { int sum = 0; int i = 0; while( i < size ) { sum += theList[ i ]; i += 1; } return sum; } As with the arithmetic expression, the delimiters must be paired and balanced. However, there are additional rules of the language that dictate the proper placement and use of the symbol pairs. We can design and implement an algorithm that scans an input text file containing C++ source code and determines if the delimiters are properly paired. The algorithm will need to remember not only the most recent opening delimiter but also all of the preceding ones in order to match them with closing delimiters. In addition, the opening delimiters will need to be remembered in reverse order with the most recent one available first. The Stack ADT is a perfect structure for implementing such an algorithm. Consider the C++ code segment from earlier. As the file is scanned, we can push each opening delimiter onto the stack. When a closing delimiter is encountered, we pop the opening delimiter from the stack and compare it to the closing delimiter. For properly paired delimiters, the two should match. Thus, if the top of the stack contains a left bracket
Table 9.3.1: The sequence of steps scanning a valid set of delimiters: the operation performed (left column) and the contents of the stack (middle column) as each delimiter is encountered (right column) in the code.
So far, we have assumed the delimiters are balanced with an equal number of opening and closing delimiters occurring in the proper order. But what happens if the delimiters are not balanced and we encounter more opening or closing delimiters than the other? For example, suppose the programmer introduced a typographical error in the function header: int sumList( int theList)], int size ) Our algorithm will find the first set of parentheses correct. But what happens when the closing bracket
Table 9.3.2: Sequence of steps scanning an invalid set of delimiters. The function header contains more closing delimiters than opening.
Delimiters can also be out of balance in the reverse case where there are more opening delimiters than closing ones. Consider another version of the function header, again containing a typographical error: int sumList( int (theList[], int size ) The result of applying our algorithm to this code fragment is illustrated in the bottom chart in Table 9.3.2. If this were the complete code segment, you can see we would end up with the stack not being empty since there are opening delimiters yet to be paired with closing ones. Thus, in order to have a complete algorithm, we must check for both of these errors.
Table 9.3.3: Sequence of steps scanning an invalid set of delimiters. The function header contains more closing delimiters than opening.
A Python implementation for the validation algorithm is provided in the listing below. The function Program Listing
A stack is used to store the opening delimiters and either implementation can be used since the implementation is independent of the definition. Here, we have chosen to use the linked list version. As the file is scanned, we need only examine the characters that correspond to one of the three types of delimiter pairs. All other characters can be ignored. When an opening delimiter is encountered, we push it onto the stack. When a closing delimiter occurs, we first check to make sure the stack is not empty. If it is empty, then the delimiters are not properly paired and balanced and no further processing is needed. We terminate the function and return
|