我们都知道,栈(stack)具有后进先出的特点,所以在我们思考一个表达式中的左右括号是否匹配问题时,就自然会想到是不是可以利用栈的特点来判断左右括号是否匹配呢?
主要思路如下:
1.扫描整个表达式;
2.判断当前字符是否为括号(左右括号)
①如果不是,则继续扫描下一个字符;
②如果是,则判断当前操作符是否为左括号
若为左括号—>直接入栈。
如果不是左括号,则说明是右括号,这时应该判断栈是否为空。
若栈为空—> 说明此表达式右括号多于左括号。
若栈不为空—>判断当前操作符是否和栈顶操作符匹配,若不匹配—->说明左右括号不匹配,若匹配—–>则继续判断下一个操作符。
3.最后,判断栈是否为空
①栈不为空—–>说明左括号多于右括号
②栈为空—–>说明括号匹配成功。
代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<stack>
#include<cassert>
bool IsOperator(char ch)
{
if (ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == '{' || ch == '}')
{
return true;
}
return false;
}
bool MatchBrackets(char* str)
{
stack<char> s;
assert(str);
//首先扫描字符串,然后判断是否为括号
while (*str != '\0')
{
if (!IsOperator(*str))
{
str++;
continue;
}
if (*str == '(' || *str == '[' || *str == '{')
{
s.push(*str);
str++;
}
else//右括号
{
if (s.empty())
{
cout << "右括号多于左括号" << endl;
return false;
}
if (*str == ')' && s.top() == '(' || *str == ']' && s.top() == '[' || *str == '}' && s.top() == '{')
{
s.pop();
str++;
}
else
{
cout << "左右括号不匹配" << endl;
return false;
}
}
}
if (!s.empty())
{
cout << "左括号多于右括号" << endl;
return false;
}
cout << "左右括号匹配正确" << endl;
return true;
}
void Test()
{
char a[] = "(())abc{[(])}"; // 左右括号次序匹配不正确
char b[] = "(()))abc{[]}"; // 右括号多于左括号
char c[] = "(()()abc{[]}"; // 左括号多于右括号
char d[] = "(())abc{[]()}"; // 左右括号匹配正确
cout << MatchBrackets(a) << endl;
cout << MatchBrackets(b) << endl;
cout << MatchBrackets(c) << endl;
cout << MatchBrackets(d) << endl;
}
int main()
{
Test();
return 0;
}
结果如下:
本篇随笔仅仅是对栈的一个应用。
下面顺便贴上栈的基本操作实现:
说明:栈的基本操作进行适用于任意类型的对象(使用模板),还有利用了模板的特化从而实现了类型萃取,从而使得拷贝栈中对象时,达到如下功能:如果对象为内置类型,那么就使用memcpy函数–>仅仅是值拷贝,如果是自定义类型,那么就用for循环,每个对象的赋值都去调用这个对象所属类型的赋值运算符重载函数实现深拷贝。
也就是提高了效率。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<cassert>
//------------使用类型萃取来拷贝栈内元素-------------
struct _TrueType
{
bool Get()
{
return true;
}
};
struct _FalseType
{
bool Get()
{
return false;
}
};
template<class _Tp>
struct TypeTraits
{
typedef _FalseType _IsPODType;
};
template<>
struct TypeTraits<bool>
{
typedef _TrueType _IsPODType;
};
template<>
struct TypeTraits<int>
{
typedef _TrueType _IsPODType;
};
template<>
struct TypeTraits<unsigned int>
{
typedef _TrueType _IsPODType;
};
template<>
struct TypeTraits<char>
{
typedef _TrueType _IsPODType;
};
template<>
struct TypeTraits< float >
{
typedef _TrueType _IsPODType;
};
template<>
struct TypeTraits< double >
{
typedef _TrueType _IsPODType;
};
template<>
struct TypeTraits<long>
{
typedef _TrueType _IsPODType;
};
template<>
struct TypeTraits< unsigned long>
{
typedef _TrueType _IsPODType;
};
template<class T>
void Copy(T* dst, T* src, size_t size)
{
if (TypeTraits<T>::_IsPODType().Get())
{
memcpy(dst, src, size);
}
else
{
for (int i = 0; i < size; ++i)
{
dst[i] = src[i];
}
}
}
template<class T>
struct TypeTraits< T* >
{
typedef _TrueType _IsPODype;
};
//-------------------------栈的基本操作----------------
template<class T>
class Stack
{
public:
//构造函数
Stack(int capacity = 10)
:_pData(NULL)
, _capacity(capacity)
, _size(0)
{
_pData = new T[capacity];
}
//拷贝构造函数
Stack(const Stack<T>& s)
:_pData(new T[s._capacity])
, _size(s._size)
, _capacity(s._capacity)
{
for (int i = 0; i < _size; ++i)
{
_pData[i] = s._pData[i];
}
}
//赋值运算符函数
Stack& operator=(Stack<T> s)
{
std::swap(_pData, s._pData);
_size = s._size;
_capacity = s._capacity;
return *this;
}
//入栈
void Push(const T& data)
{
CheckCapacity();
_pData[_size++] = data;
}
//出栈
void Pop()
{
if (!Empty())
{
--_size;
}
}
//获取栈顶元素
T& Top()
{
if (!Empty())
{
return _pData[_size - 1];
}
}
const T& Top()const
{
if (!Empty())
{
return _pData[_size - 1];
}
}
size_t Size()const
{
return _size;
}
bool Empty()const
{
return 0 == _size;
}
//析构函数(释放资源)
~Stack()
{
if (_pData)
{
delete[] _pData;
_pData = NULL;
}
}
private:
//增容
void CheckCapacity()
{
if (_size >= _capacity)
{
_capacity = 2 * _capacity + 3;
T* tmp = new T[_capacity];
//拷贝原数据
//释放旧空间
//指向新空间
//需要进行类型萃取
Copy<T>(_pData, tmp, _size);
delete[] _pData;
_pData = tmp;
}
}
T* _pData;