栈是数据结构中非常重要的一种,它的最大特点就是先进后出,我们利用这个特点解决很多问题时都会比较方便。比如:括号匹配问题,逆波兰表达式求值等问题,有时候也需要借助栈将递归转化成循环。
下面我们将通过顺序存储来简单实现栈:
template <class T>
class Stack
{
public:
Stack()
: _data(new T[3])
, _size(0)
, _capacity(3)
{}
void Push(const T& data)
{
_CheckCapacity();
_data[_size++] = data;
}
void Pop()
{
assert(_size);
_size--;
}
T& Top()
{
return _data[_size - 1];
}
T& Top()const
{
return _data[size - 1];
}
size_t Size()const
{
return _size;
}
bool Empty()const
{
return 0 == _size;
}
~Stack()
{
if (_data)
{
delete[] _data;
_data = NULL;
_size = 0;
_capacity = 0;
}
}
private:
void _CheckCapacity()
{
if (_size == _capacity)
{
T* tmp = new T[_capacity * 2];
for (size_t i = 0; i < _capacity; i++)
tmp[i] = _data[i];
delete[] _data;
_data = tmp;
_capacity = _capacity * 2;
}
}
T* _data;
size_t _size;//有效元素个数
size_t _capacity;
};
栈的简单应用
1.括号匹配问题
检查一段表达式中的左右括号是否匹配,如果匹配,返回true,如果不匹配,返回false;不匹配主要包括:左右次序不匹配,左括号多,右括号多三种情况
#include <stack>
bool IsBrackets(char p)
{
if (p == '(' || p == ')'
|| p == '[' || p == ']'
|| p == '{' || p == '}')
return true;
return false;
}
bool MatchBrackets(char* pStr)
{
const char* p = pStr;
stack<char> s;
for (int i = 0; p[i] != '\0'; ++i)
{
if (!IsBrackets(p[i]))
continue;
else
{
if (p[i] == '(' || p[i] == '{' || p[i] == '[')
{
s.push(p[i]);
continue;
}
if (p[i] == ')' || p[i] == '}' || p[i] == ']')//右括号
{
if (s.empty())
{
cout << "右括号多于左括号" << endl;//abc)))))
return false;
}
else if (s.top()=='('&&p[i]==')' || s.top()=='{'&&p[i]=='}' || s.top()=='['&&p[i]==']')
s.pop();
else
{
cout << "左右括号次序不匹配" << endl;
return false;
}//else
}//if右括号
}
}//for
if (s.empty())
{
cout << "匹配成功" << endl;
return true;
}
else
{
cout << "左括号多于右括号" << endl;
return false;
}
}
2.逆波兰式求值
逆波兰式也称后缀表达式,将运算符写在操作数之后,这种表达式,方便于计算机。
#include <stack>
enum OPERATOR
{ADD, SUB, MUL, DIV, DATA};
struct Cell
{
OPERATOR _op;
int _data;
};
int CalcRPN(Cell* RPN, int size)
{
stack<int> s;
for (int i = 0; i < size; i++)
{
if (RPN[i]._op == DATA)
s.push(RPN[i]._data);
else
{
int right = s.top();
s.pop();
int left = s.top();
s.pop();
switch (RPN[i]._op)
{
case ADD:
s.push(left + right);
break;
case SUB:
s.push(left - right);
break;
case MUL:
s.push(left * right);
break;
case DIV:
if (right != 0)
s.push(left / right);
break;
}//switch
}
}//for
return s.top();
}
void FunTest()
{
Cell RPN[] = { { DATA, 12 }, { DATA, 3 }, { DATA, 4 }, { ADD, 0 }, { MUL, 0 }, { DATA, 6 }, { SUB, 0 }, { DATA, 8 }
, { DATA, 2 }, { DIV, 0 }, { ADD, 0 } };
int tmp = CalcRPN(RPN, sizeof(RPN) / sizeof(RPN[0]));
cout << tmp << endl;
}