Understanding Dijkstra's Two Stack Algorithm
Inroduction
I wrote an article about stacks and how to evaluate postix expressions using a single stack. Since stacks has many applications, we know what we can do with a single stack. And now let’s see what we can do with two stacks.
In Computer Science two stacks has an important application called Two Stack PDA which is beyond the scope of this article but worth to look at. Fortunately or unfortunately, we’re not going to talk a lot about Computer Science here, so if you just want to evaluate a mathematical expression without using a third party library then this article is for you.
Evaluating an expression
Let’s say we have an infix expression (a mathematical expression where operators are between operands) like this where we want to evaluate the expression with also preserving presedence. How would you do it?
( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
Now, before we move to the solution think a little bit about how you can solve it on your own. Or if you want to directly dive into the solution then let’s begin.
The two stack algorithm, which was invented by Edsger Dijkstra, is a method for evaluating fully patenthesized mathematical expressions. As the name suggests it uses two stacks, and the algorithm is simple:
- We have two stacks: a value stack and an operator stack
- We read the expression string from left to right
- If the current symbol is a value, push it to the value stack
- If the current symbol is an operator, push it to the operator stack
- If the current symbol is left (opening) parenthesis, just ignore it
- If the current symbol is right (closing) parenthesis
- Pop an operator from operator stack and pop two values from value stack
- Apply the operator to that values
- Push the result to the value stack
To see it visually I would recommend to take a look at this video on Coursera. If we write JavaScript code for this algorithm it would look something like this:
function evaluate(str) { |
I believe the code is clear to you since it is fairly simple algorithm, so let’s test it with the expression that we considered earlier:
evaluate("( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )"); // output is 101 |
Surprisingly, if you put every operator after operands, the algorithm will also output the correct answer:
evaluate("( 1 ( ( 2 3 + ) ( 4 5 * ) * ) + )"); // output is 101 |
In this kind of expressions parentheses are redundant and removing them will give us a postfix expression (a mathematical expression where operators follow operands).
However, this expression will not be evaluated by our function since there is no any closing parenthesis to stop and make us calculate.
Conslusion
Dijkstra is popular with his shortest path algorithm but it too was an interesting, simple and powerful algorithm that we learnt. I believe, getting familiar with a lot of such algorithms will make you a better problem solver. Since problem solving is a very important aspect of a software engineer, this kind of topics are worth to learn.
The content of this article is based on Algorithms Part I course on Coursera which is presented by Princeton University and is completely free. I strongly recommend to take a look at that course.
Thanks for reading.