This exercise is somewhat unsettling. On the one hand, a stack, as part of a pushdown automaton, is the canonical way to decide balanced languages such as this one; on the other hand, there are much more efficient, idiomatic and practical ways to solve that particular exercise. It is unclear whether it's a computer science exercise or a language learning exercise, one to make concepts sink in or one to discover C++'s expressiveness.
A stack would have been more easily justified if the function argument had been a std::istream& for instance, since it can be traversed only once; or if starting / ending tags had come of different kinds (if they're all the same an integer makes for a perfect stack and counting shouldn't be discriminated).
As @Mike Borland said, the trick to answer that question is to avoid explicit counting by popping the stack filled with as while you iterate over the rest of the string. Something along the lines:
#include <stack>
#include <string>
bool is_ab_balanced(const std::string& str) {
if (!str.size()) return false;
auto it = str.begin();
std::stack<char> as;
while (*it == 'a') as.push(*it++);
while (!as.empty()) {
if (it == str.end() || *it != 'b') return false;
as.pop(); ++it;
}
return it == str.end();
}
By the way, you'll notice that:
it always is better to use standardized containers unless you need customized behavior:
std::stackis certainly better optimized and tested thanlinkedStackType<>you shouldn't take a
stringby value as an argument, unless you intend to modify it while keeping the original string unchanged. Here, there's no modification, so use aconstreference instead.you should get rid of unused variables (see
aandbin your second version). Those superfluous variables probably are a by-product of bad habits: declaring variables too far ahead of their use, and not enabling all warnings when you compile your code.iterators are a better way to iterate over a range: it's more idiomatic, it's necessary to leverage the power of the STL, and it also avoids that extrasizevariable.A few more key-strokes are better than
using namespace std, which is is a bad idea
But, as I said, a good exercise should look more like real life. In real life, you use a stack only if it is the best way to go. So how would you check if a string belongs to the language if you could choose without restriction?
My take on that would be:
#include <string>
#include <algorithm>
using Iterator = std::string::iterator;
bool is_balanced(Iterator first, Iterator last) {
auto middle = std::next(first, std::distance(first, last) / 2);
return std::equal(first, middle, middle, last, [](auto a, auto b) {
return a == 'a' && b == 'b';
});
}
Or, other more meaningful exercises would have been:
how would you check if parenthesis are balanced in an expression (I wouldn't use a stack here either)?
how would you check if html tags are correctly balanced (here using a stack is meaningful)?