栈的储存结构及相关操作
栈的储存结构及相关操作
1.实现栈的存储结构及相关操作:进栈、出栈、取栈顶元素等
2.使用该栈完成一个字符串的逆序输出
3.使用该栈完成表达式的括号是否匹配?
4.对算术表达式求值
主要的相关实现函数
template <class T>
class Stack{
private:
T* elements;//存放栈中元素的数组
int top;//栈顶元素的指针
int maxSize;//栈的最大容纳元素个数
//void overflowProcess();//栈的溢出处理操作
public:
Stack(int size=basesize)//构造函数
{
if(size>0){
maxSize=size;
top=-1;
creatStack(size);
}
}
~Stack(){delete []elements;}//析构函数,释放栈的空间
void creatStack(int n);//创建一个大小为n的栈,并为其动态分配空间
void Push(const T& x);//元素x入栈
bool Pop(T& x);//栈顶元素出栈
bool isFull();//判满函数
bool isEmpty();//判空函数
int getMaxsize()//得到栈的最大体积
{return maxSize;}
T getTopelements();//得到栈顶元素
int getTop()//得到栈的top指针的地址,因为是采用数组类型储存,因此top指针可以利用数组的下标得到
{return top;}
void print(string tape);//展示各种类型的数据,控制格式
bool writeToFile(string filename);//将数据写入指定文件
bool readFromFile(string filename);//将数据从指定文件读入
};
栈的各个函数的实现
创建一个大小为n的栈
template <class T>
inline void Stack<T>::creatStack(int n)
{
elements = new T(n);
if(elements==NULL){
cout<<"动态分配错误!"<<endl;
}
}
元素x入栈
//如果栈isFull(),则进行溢出处理,否则将其插入到栈顶
template <class T>
inline void Stack<T>::Push(const T &x)
{
if(isFull()==true){
//overflowProcess();//溢出处理,调整空间大小
}
else{
elements[++top]=x;//将x入栈
}
}
### 栈顶元素出栈,以x的引用返回
```cpp
//栈顶元素出栈,如果栈为空返回false;若栈不为空,栈顶元素出栈,top指针减一
template <class T>
inline bool Stack<T>::Pop(T& x)
{
if(isEmpty())return false;
else{
x=getTopelements();
top--;
return true;
}
}
判满函数
//判断栈是否满,如果满返回true,未满返回false
template <class T>
inline bool Stack<T>::isFull()
{
if(this->getTop()<this->getMaxsize()){
return false;
}
else{
return true;
}
}
判空函数
//判断栈是否空,如果满返回true,未满返回false
template <class T>
inline bool Stack<T>::isEmpty()
{
if(this->getTop()==-1){
return true;
}
else{
return false;
}
}
打印
template <class T>
inline void Stack<T>::print(string tape)
{
if(isEmpty()){
cout<<"This Stack is empty!"<<endl;
}
for(int i=0;i<getTop();i++)
{
cout<<"["<<elements[i]<<"]<-";
}
cout<<"["<<elements[getTop()]<<"]"<<endl;
}
得到栈顶元素
template <class T>
inline T Stack<T>::getTopelements()
{
return elements[getTop()];
}
文件相关读写操作
template <class T>
inline bool Stack<T>::writeToFile(string filename)
{
ofstream writefile(filename);
T temp[basesize];
T x;
int i,count;
count=getTop()+1;
writefile<<count<<endl;
for(i=0;i<count;i++){
temp[i]=getTopelements();
Pop(x);
}
for(int j=count-1;j>=0;j--)
{
writefile<<temp[j]<<endl;
}
return true;
}
template <class T>
inline bool Stack<T>::readFromFile(string filename)
{
ifstream readfile(filename);
int len;
readfile>>len;
for(int i=0;i<len;i++)
{
T temp;
readfile>>temp;
this->Push(temp);
}
return true;
}
利用栈实现字符串的逆序
void reverseString(char temp[])
{
int len=strlen(temp);
Stack<char> st;
char x;
char str[len+1];
//str[len]='\0';
for(int i=0;i<len;i++)
{
st.Push(temp[i]);
}
for(int i=0;i<len;i++)
{
str[i]=st.getTopelements();
st.Pop(x);
}
str[len]='\0';
cout<<"逆序后的字符串为:"<<str<<endl;
}
利用栈实现括号是否匹配的判断
void bracketMatching(char expression[])
{
Stack<int> stack;
int j;
int len=strlen(expression);
for(int i=1;i<=len;i++){
if(expression[i-1]=='('){
stack.Push(i);
}
else if(expression[i-1]==')'){
if(stack.Pop(j)==true){
cout<<"第"<<j<<"个 “(” 与第"<<i<<"个 “)” 匹配!"<<endl;
}
else{
cout<<"没有与第"<<i<<"个 “)” 匹配的 “(” !"<<endl;
}
}
}
while(stack.isEmpty()==false){
stack.Pop(j);
cout<<"没有与第"<<j<<"个 “(” 匹配的 “)”!"<<endl;
}
}
利用栈实现表达式的求值
(满足小数,多位数,整数的计算)
其中最重要的算法实现,中缀表达式转后缀表达式,利用容器保存各个操作数,以便实现多位数,小数的实现
//中缀表达式转后缀表达式
vector<string> convert(string input){
Stack<char> stk;//存储操作符栈
vector<string> temp;
char s;
string tmp = "";
int length = (int)input.length();//获取表达式的长度
for(int i = 0; i < length; i++){
tmp = "";
if((input[i]>='0' && input[i]<='9')){
tmp += input[i];
while((i+1<input.size() && input[i+1]>='0' && input[i+1]<='9')||input[i+1] == '.')
{
tmp += input[i+1];//若是连续数字
++i;
}
temp.push_back(tmp);
}
else if(input[i] == '('){
//遇到左括号直接入栈
stk.Push(input[i]);
}
else if(input[i] == ')'){
//如果遇到右括号的话,就把一直到最近的左括号之间的都弹出来加入temp中
while(stk.getTopelements() != '('){
tmp += stk.getTopelements();
temp.push_back(tmp);
stk.Pop(s);
tmp="";
}
stk.Pop(s);//把左括号弹出栈
}
else if(isMark(input[i])){
//如果是运算符的话,比较他们的优先级再决定是否入栈
while( prior(input[i])<=prior(stk.getTopelements()) ){
//如果当前的优先级小于等于栈顶操作符的话,栈顶操作符弹出,加入temp
tmp += stk.getTopelements();
temp.push_back(tmp);
stk.Pop(s);
tmp="";
}
//如果当前的优先级大于栈顶操作符的话,入栈
stk.Push(input[i]);
}
}
//如果已经扫描到中缀表达式的末尾,就把栈中的操作符都弹出来加入到temp中
while(!stk.isEmpty()){
tmp="";
tmp += stk.getTopelements();
temp.push_back(tmp);
stk.Pop(s);
tmp="";
}
return temp;
}
计算表达式的最终结果
//计算后缀表达式的最终数值
double calculate(vector<string> retu){
int i = 0;
Stack<double> optNum;//定义一个操作数栈
double s;
double x1,x2 = 0;
double num;
for(int i = 0;i < retu.size(); i++){//没有遇到结束标志#,即进行表达式的计算
string tmp = retu[i];
if(tmp[0] >= '0'&&tmp[0] <= '9'){
num = atof(tmp.c_str());
optNum.Push(num);
}
else if(retu[i] == "+"){
x1 = optNum.getTopelements();
optNum.Pop(s);
x2 = optNum.getTopelements();
optNum.Pop(s);
optNum.Push(x1+x2);
}
else if(retu[i] == "-"){
x1 = optNum.getTopelements();
optNum.Pop(s);
x2 = optNum.getTopelements();
optNum.Pop(s);
optNum.Push(x2-x1);
}
else if(retu[i] == "*"){
x1 = optNum.getTopelements();
optNum.Pop(s);
x2 = optNum.getTopelements();
optNum.Pop(s);
optNum.Push(x1*x2);
}
else if(retu[i] == "/"){
x1 = optNum.getTopelements();
optNum.Pop(s);
x2 = optNum.getTopelements();
optNum.Pop(s);
optNum.Push(x2/x1);
}
else if(retu[i] == "%"){
x1 = optNum.getTopelements();
optNum.Pop(s);
x2 = optNum.getTopelements();
optNum.Pop(s);
optNum.Push((int)x2%(int)x1);
}
else if(retu[i] == "^"){
x1 = optNum.getTopelements();
optNum.Pop(s);
x2 = optNum.getTopelements();
optNum.Pop(s);
optNum.Push(pow(x2, x1));
}
}
return optNum.getTopelements();//返回最终的计算结果
}
double result(string str){
str = format(str);
vector<string> bh = convert(str);
double k = calculate(bh);
return k;
}
对“-”号的特殊化处理
string format(string str){
for(int i = 0;i < str.length(); i++){
if(str[i] == '-')
{
if(i == 0){
str.insert(0,1,'0');
}
else if(str[i-1] == '('){
str.insert(i,1,'0');
}
}
}
return str;
}
操作符的优先级
int prior(char op){//求运算符优先级
switch (op) {
case '#':
return -1;
break;
case '(':
return 0;
break;
case '+':
return 1;
break;
case '-':
return 1;
break;
case '*':
return 2;
break;
case '/':
return 2;
break;
case '%':
return 2;
break;
case '^':
return 3;
break;
default:
return -1;
}
}