天天看點

用棧實作中綴表達式計算--逆波蘭表達式計算

剛開始學,請大佬們看一看有沒有啥問題。

"MyStack.h"

#pragma once
#include <iostream>
using namespace std;

template<class T>//結點 
class LinkNode
{
public:
	T data;//資料域
	LinkNode* next;//指針域
};

template<class T>
class LinkStack//棧
{
public:
	//初始化鍊棧
	LinkStack();
	//元素入棧
	void Push(T c);
	//元素出棧
	void Pop();
	//判斷棧是否為空
	bool isEmpty();
	//擷取棧頂元素,并用x接收
	T GetTop();
	//擷取棧長度
	int Length();
private:
	LinkNode<T>* HeadNode;//頭結點
	int len;
};

template<class T>
LinkStack<T>::LinkStack()
{
	HeadNode = new LinkNode<T>();
	HeadNode->next = NULL;
	len = 0;
}

//元素入棧
template<class T>
void LinkStack<T>::Push(T c)
{
	LinkNode<T>* p = new LinkNode<T>();
	p->data = c;
	p->next = HeadNode->next;
	HeadNode->next = p;
	++len;
}

//元素出棧
template<class T>
void LinkStack<T>::Pop()
{
	LinkNode<T>* p = HeadNode->next;
	if (p == NULL)
		return;
	HeadNode->next = p->next;
	delete p;
	--len;
}

//判斷棧是否為空
template<class T>
bool LinkStack<T>::isEmpty()
{
	LinkNode<T>* p = HeadNode->next;
	if (p == NULL)
		return true;
	else
		return false;
}

//擷取棧頂元素,并傳回
template<class T>
T LinkStack<T>::GetTop()
{
	if (!isEmpty())
		return HeadNode->next->data;
	else
		return NULL;
}

//擷取棧的長度
template <class T>
int LinkStack<T>::Length()
{
	return len;
}
           

 BracketMatch.h

#pragma once
#include <iostream>
using namespace std;

//判斷輸入的計算式括号是否合法
bool Bracket_isMatched(string str);
//輸入計算式,儲存在字元串str中
string EnString();
           

 BracketMatch.cpp

#include"MyStack.h"
#include"BracketMatch.h"
#include <iostream>
#include<string>
using namespace std;

//判斷括号是否合法
/*
	1.初始化一個鍊棧,周遊傳進來的字元串,
		遇到左括号則入棧,遇到右括号則:
			判斷棧是否為空,若為空則表明不比對;
			若棧不為空,将棧頂元素出棧,并檢驗是否與目前右括号比對;
	2.周遊完成後,檢驗棧是否為空,若為空則括号比對成功;否則,括号比對失敗
*/

//輸入計算式,儲存在字元串str中
string EnString()
{
	string str;
	getline(cin, str);
	return str;
}

//判斷輸入的計算式括号是否合法
bool Bracket_isMatched(string str)
{
	LinkStack<char> S;
	for (int i = 0; i != str.length(); ++i)
	{
		if (str[i] == '(' || str[i] == '[' || str[i] == '{')
			S.Push(str[i]);
		else if (str[i] == ')' || str[i] == ']' || str[i] == '}')
		{
			if (S.isEmpty())
				return false;
			else
			{
				char temp = S.GetTop();
				S.Pop();
				if (temp == '(' && str[i] != ')' || temp == '[' && str[i] != ']'
					|| temp == '{' && str[i] != '}')
					return false;
			}
		}
	}
	return S.isEmpty();
}
           

 Calculate.h 

#pragma once
#include <iostream>
#include"MyStack.h"
using namespace std;

//用棧計算中綴表達式
int Calculate();
//運算
int opera(int left, int right, char c);
//判斷運算符優先級,判斷c1優先級是不是小于或等于c2
bool Priority(char c1, char c2);
//彈出并擷取一個運算符,彈出并擷取操作數,計算之後将結果壓入操作數棧
void GetCalculate(LinkStack<char>& S_char, LinkStack<int>& S_int);
           

 Calculate.cpp

#include<iostream>
#include"Calculate.h"
#include"BracketMatch.h"
#include"MyStack.h"

using namespace std;

/*
	1.用棧實作中綴表達式轉字尾表達式
		初始化一個棧,用于儲存暫時還不能确定運算順序的運算符
		從左到右處理各個元素,直到末尾。可能遇到三種情況:
			①遇到操作數。直接加入字尾表達式;
			②遇到界限符。遇到"("直接入棧;遇到")"則一次彈出棧内運算符并加入
			字尾表達式,直到彈出"("為止。注意"("不加入字尾表達式
			③遇到運算符。依次彈出棧中優先級高于或等于目前運算符的所有運算符,
			并加入字尾表達式
*/
/*
	2.用棧實作字尾表達式計算
		1.從左往右掃描下一個元素,直到處理完所有元素
		2.若掃描到操作數則壓入棧,并回到1.;否則執行3.
		3.若掃描到運算符。則彈出棧頂的連個元素,執行相應的運算,運算結果壓回
		棧頂,回到1.
*/

/*
	3.用棧實作中綴表達式的計算
		初始化兩個棧,操作數棧和運算符棧
		若掃描到操作數,則壓入操作數棧
		若掃描到運算符或界限符,則按照“中綴轉字尾相同的邏輯壓入運算符棧(
		期間也會彈出運算符,每當彈出一個運算符時,就需要彈出兩個操作數棧的
		棧頂元素并執行相應運算,運算結果再壓回操作數棧)”
*/

//運算
int opera(int left,int right,char c)
{
	if (c == '+')
		return left + right;
	else if(c=='-')
		return left - right;
	else if(c=='*')
		return left * right;
	else if(c=='/')
		return left / right;
}

//彈出并擷取一個運算符,彈出并擷取操作數,計算之後将結果壓入操作數棧
void GetCalculate(LinkStack<char>& S_char, LinkStack<int>& S_int)
{
	char c = S_char.GetTop();
		S_char.Pop();
		int left, right;
		//擷取操作數
		right = S_int.GetTop();
		S_int.Pop();
		left = S_int.GetTop();
		S_int.Pop();
		//進行計算,并壓入操作數棧
		S_int.Push(opera(left, right, c));
}

//判斷運算符優先級,判斷c1優先級是不是小于或等于c2
bool Priority(char c1, char c2)
{
		if ((c1 == '*' || c1 == '/') && (c2 == '+' || c2 == '-'))
			return false;
		else
			return true;
}

//用棧計算中綴表達式
int Calculate()
{
	string str = EnString();
	if (Bracket_isMatched(str))
	{
		LinkStack<char> S_char;//運算符棧
		LinkStack<int> S_int;//操作數棧
		int num = 0;
		int flag = 0;
		for (int i = 0; i != str.length(); ++i)
		{
			if(str[i] >= '0' && str[i] <= '9')//若遇到數字則将字元轉換為數字
			{
				num = num * 10 + str[i] - '0';
				++flag;
				if (flag != 0 && i == str.length() - 1)
				{
					S_int.Push(num);//數字轉換結束後壓入操作數棧
					num = 0;//num清零
					flag = 0;
				}
			}
			else
			{
				if (flag != 0)//說明num被修改過
				{
					S_int.Push(num);//數字轉換結束後壓入操作數棧
					num = 0;//num清零
					flag = 0;
				}
				if (str[i] == '(')//遇到'('直接入運算符棧
					S_char.Push(str[i]);
				else if (str[i] == ')')
				{
					while (S_char.GetTop() != '(' )
					{
						GetCalculate(S_char, S_int);
					}
						S_char.Pop();
				}
				else if (str[i] == '+' || str[i] == '-' || str[i] == '*' ||
					str[i] == '/')
				{
						while (S_char.GetTop() != '('&& !S_char.isEmpty()
							&& Priority(str[i], S_char.GetTop()))
						{
								GetCalculate(S_char, S_int);
						}
						S_char.Push(str[i]);
				}
			}
		}
		while (!S_char.isEmpty())//判斷操作符棧是否空,不空則進行計算
		{
			GetCalculate(S_char, S_int);
		}
		return S_int.GetTop();
	}
	else
	{
		cout << "括号不比對" << endl;
		return -9999;
	}
}
           

 main.cpp

#include <iostream>
#include"MyStack.h"
#include"BracketMatch.h"
#include"Calculate.h"
using namespace std;

int main()
{
    cout << Calculate() << endl;
    return 0;
}