棧的儲存結構及相關操作
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;
}
}