OBJECTIVE
The following links will demonstrate -using a visualization- how a Stack works using an Array Implementation and a Linked List Implementation.
The goal for today’s lab is to write a simple application that uses the stack methods in Java’s generic LinkedList class. The application allows the user to type in a string and checks that the parentheses, brackets, and braces that occur in that string are correctly balanced and properly nested.
A string that may contain parentheses, brackets, and/or braces is balanced if it has the same number of left and right parentheses, the same number of left and right brackets, and the same number of left and right braces. These characters are correctly nested if each right-hand parenthesis, bracket, or brace can be paired with a left-hand parenthesis, bracket, or brace that precedes it and matches its shape, in such a way that the only parentheses, brackets, and braces that occur between the paired characters are similarly paired (within the enclosed string).
For example, the string "(a [(b c) d]"
is not balanced, because it has two left parentheses and only one right parenthesis, and the string "(a [b c)]"
is not correctly nested because the parentheses enclose a string containing an unpaired left bracket. But "(a [{b c} (d e)])"
is both balanced and correctly nested.
One conventional method for determining that a string is balanced and correctly nested is to draw arcs above the string connecting the paired left and right characters. If there is a way to draw the arcs so that they do not cross and connect characters that match in shape, leaving no parentheses, brackets, or braces unpaired, then the test succeeds.
This pencil-and-paper method provides the basis for the algorithm that we’ll implement today. The idea is to traverse the string from left to right. Whenever we find a left parenthesis, left bracket, or left brace, we’ll “start an arc” by pushing that character onto a stack. The arc will be terminated when we find the matching character later in the string, at which point we’ll pop it off the stack. The “last-in, first-out” property of stacks will guarantee that we cannot pop anything off the stack until we have successfully paired every parenthesis, bracket, or brace that occurs between the pushing of the arc-starting character onto the stack and the popping of it from the stack.
Use the LinkedList
generic class. The type of data stored in each node/element will be a Character
, e.g., LinkedList<Character> stack
(note that this is capitalized as the reference object rather than the primitive char)
Note: In Java, you could also use the Stack
class, e.g., Stack<Character> stack
BalanceChecker.java
file and write the header and documentation (though not yet the body) for a checkBalance
method that determines whether a given string is balanced and correctly nested with respect to parentheses, brackets, and braces.checkBalance
method to push characters onto a stack and eventually pop them off again.
This stack could either be created once, in the BalanceChecker
constructor, stored in a field of the BalanceChecker
object, and re-used for every call to checkBalance
, or it could be created inside each call to checkBalance
and stored in a local variable of that method. What are tradeoffs between these two ways for creating the stack?
(You may do either one. The design choice is up to you!!)The code that implements checkBalance
could encounter several kinds of problems.
empty
. (In this case, the pop
method throws an exception.) What would this imply about the given string?checkBalance
method.
Use the switch
statement (see BJP - Appendix C pag. 1184 or Switch - Java tutorials) when matching a right parenthesis, bracket, or brace with a character popped from the stack. Note than characters other than parentheses, brackets, and braces need not be pushed into the stack.
checkBalance
method to ensure that the stack is empty before it returns a value.
(This is essential if you are storing the stack in a field of an BalanceChecker
object and reusing it in every call to checkBalance
—you don’t want cruft left over from one call still to be in the stack when the next call begins.) Save and compile BalanceChecker.java
.JUnit
tests. Include some cases in which the bracketing symbols are balanced and correctly nested, and some in which they are not. For each of the possible kinds of error described in the exercises above, include at least one test case that illustrates an error of that kind.BalanceCheckerTester.java
file with a main method that will invoke the
checkBalance
method on a few sample strings and report its findings to the user (use informative user-friendly messages). Compile and run BalanceCheckerTester
and interpret the output to confirm or refute the hypothesis that your implementation handles them all correctly.
For imbalanced or incorrectly nested strings, check your program with the following test cases: "(a[b)c]"
, "(a[b(c)]"
, and "[a(b(c))d]]"
.Note: Change the type of object. Use a Stack
You will submit your files via Gradescope by the end of the week. Please submit the source files, and JUnit class.
I strongly recommend that each student keep a copy of the lab. Therefore, don’t forget to share the files/folder with your lab partner!
Remember: Write your code anticipating errors and print user-friendly error messages, all your public methods should be well documented (use Javadoc comments). Please include comments or organize your code and report in a way that will help the grader to find the answer to the exercises or posted questions.
<(ab)|<c|[d(ef)]>>
is balanced and correctly nested.