1. 程式人生 > >資料結構學習筆記之棧(含數制轉換,括號匹配,表示式求值轉逆波蘭)

資料結構學習筆記之棧(含數制轉換,括號匹配,表示式求值轉逆波蘭)

#include <iostream>
#include <cstring>
#include <ctype.h>
#include <string>
#include <cstring>
#include <malloc.h>//gcc6.3可不加
#include <stdlib.h>
#include <algorithm>
using namespace std;
typedef int Rank;
#define DEFAULT_CAPACITY 3
#define N_OPTR 9
const char OPSET[N_OPTR] = { '+', '-', '*', '/', '^', '!', '(', ')', '\0' };
const char pri[N_OPTR][N_OPTR] = {
	//橫當前運算子,豎棧頂運算子
	//     +    -    *    /    ^    !    (    )    \0
	/* +*/'>', '>', '<', '<', '<', '<', '<', '>', '>',
	/* -*/'>', '>', '<', '<', '<', '<', '<', '>', '>',
	/* **/'>', '>', '>', '>', '<', '<', '<', '>', '>',
	/* /*/'>', '>', '>', '>', '<', '<', '<', '>', '>',
	/* ^*/'>', '>', '>', '>', '>', '<', '<', '>', '>',
	/* !*/'>', '>', '>', '>', '>', '>', ' ', '>', '>',
	/* (*/'<', '<', '<', '<', '<', '<', '<', '=', ' ',
	/* )*/' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
	/*/0*/'<', '<', '<', '<', '<', '<', '<', ' ', '=',
};

template <typename T>
class Stack {
private:
	Rank _top;
	Rank _buttom;
	int _capacity;
	T *_elem;
protected:
	void expand();
	void shrink();
public:
	Stack(int c = DEFAULT_CAPACITY);
	~Stack();
	Rank GetSize();
	bool isEmpty();
	void push(T const &e);
	T pop();
	T &top();
	void show();
};

template<typename T>
Stack<T>::Stack(int c)
{
	_elem = new T[_capacity = c];
	_buttom = 0;
	_top = 0;
}

template<typename T>
Stack<T>::~Stack()
{
	delete[] _elem;
}

template<typename T>
Rank Stack<T>::GetSize()
{
	return _top - _buttom;
}

template<typename T>
bool Stack<T>::isEmpty()
{
	return (_top == _buttom) ? true : false;
}

template<typename T>
void Stack<T>::expand()
{
	_capacity = max(_capacity, DEFAULT_CAPACITY);
	T *oldelem = _elem;
	_elem = new T[_capacity <<= 1];
	for (int i = 0; i < GetSize(); ++i)
		_elem[i] = oldelem[i];
	delete[] oldelem;
}

template<typename T>
void Stack<T>::push(T const &e)
{
	if (GetSize() >= _capacity) expand();
	_elem[_top++] = e;
}

template<typename T>
T &Stack<T>::top()
{
	return _elem[_top - 1];
}

template<typename T>
void Stack<T>::shrink()
{
	//cout<<"start shrink"<<endl;
	_capacity = max((_top - _buttom) * 2, DEFAULT_CAPACITY);
	T *oldelem = _elem;
	for (int i = 0; i < (_top - _buttom); ++i)
		_elem[i] = oldelem[i];
	delete[] oldelem;
}

template<typename T>
T Stack<T>::pop()
{
	_top--;
	if (GetSize() * 2 < _capacity) shrink();
	return _elem[_top];
}

template<typename T>
void Stack<T>::show()
{
	cout << "top: " << _top << "\tbuttom: " << _buttom << endl;
	cout << "size: " << GetSize() << "\tcapacity: " << _capacity << endl;
	for (int i = 0; i < GetSize(); ++i)
		cout << _elem[i] << "\t";
	cout << endl;
}

//進位制轉換n進位制轉b進位制(逆序輸出)
void convert(Stack<char> &s, int n, int b)
{
	static char digit[] = { '0', '1', '2', '3', '4', '5',
	'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
	while (n > 0)
	{
		s.push(digit[n%b]);
		n /= b;
	}
}

//括號匹配
bool paren(const char exp[])
{
	Stack<char> s;
	for (int i = 0; i < strlen(exp); ++i)
	{//左括號入棧,遇到右括號pop。棧空還能遇到右括號則不匹配
		if ('(' == exp[i])s.push(exp[i]);
		else if (!s.isEmpty() && ')' == exp[i])s.pop();
		else if (s.isEmpty() && ')' == exp[i])return false;
	}
	return s.isEmpty();//棧空匹配,不空失配
}

//棧混洗的種數為(2n)!/((n+1)!n!)
//對於任意三個元素123出312必非棧混洗(充要條件)
template<typename T>
bool permutation(Stack<T> &s, const T exp[], int expSize)
{//s.pop() -> exp[] s是倒序的,先出棧的後push入
	if (expSize != s.GetSize()) return false;
	Stack<T> t;
	for (int i = 0, j = 0; i < expSize; ++i)
	{
		t.push(s.pop());
		while (t.GetSize() > 0 && t.top() == exp[j])
		{
			t.pop();
			j++;
		}
	}
	return (t.isEmpty() == true) ? true : false;
}

//讀入資料,處理多位數,(從屬於evaluate)
void readNumber(char *&p, Stack<float>& stk)
{
	stk.push(float(*p - '0'));
	while(isdigit(*(++p))) stk.push(stk.pop()*10 + (*p - '0'));
	if('.' != *p)return;
	float fraction = 1;
	while(isdigit(*(++p)))stk.push(stk.pop() + (*p - '0')*(fraction /= 10));
}

//判斷優先順序(從屬於evaluate)
char orderBetween(char &e, char &s)
{
	int i, j;
	for (i = 0; i < N_OPTR; ++i)
		if (e == OPSET[i])break;
	for (j = 0; j < N_OPTR; ++j)
		if (s == OPSET[j])break;
	return pri[i][j];
}

//一二元運算計算(從屬於evaluate)
float calcu(float p1, char op, float p2 = 0)
{
	switch (op) {
	case '+':return p1 + p2;
	case '-':return p1 - p2;
	case '*':return p1 * p2;
	case '/':return p1 / p2;
	case '^': {
		float c = 1;
		while (p2--) c = c * p1;
		return c;
	}
	case '!': {
		if (p1 == 0)return 1;
		else return p1 * calcu(p1 - 1, '!');//遞迴求階乘
	}
	}
}

//將數字寫入逆波蘭
void append(char *&rpn, float opnd)
{
	int n = strlen(rpn);
	char buf[64];
	if(opnd != float(int(opnd)))sprintf(buf, "%.2f \0", opnd); //小數
    else sprintf(buf, "%d \0", int(opnd)); //整數
    rpn = (char*)realloc(rpn,sizeof(char)*(n + strlen(buf) + 1)); //擴充套件空間,需要stdlib.h malloc.h
    strcat (rpn, buf); //RPN加長
}

//將運算子寫入逆波蘭
void append (char *& rpn, char optr) { //將運算子接至RPN末尾
    int n = strlen (rpn); //RPN當前長度(以'\0'結尾,長度n + 1)
    rpn = (char*) realloc (rpn, sizeof(char) * (n + 3 )); //擴充套件空間
    sprintf (rpn + n, "%c ", optr); rpn[n + 2] = '\0'; //接入指定的運算子
}

//中綴表示式求值的主體部分
float evaluate(char *S, char *& rpn)//*&意為陣列引用
{
	Stack<float> opnd;//運算數棧
	Stack<char> optr;//運算值棧
	optr.push('\0');//頭哨兵,和字串結尾的'\0'匹配
	int i = 0;
	while (!optr.isEmpty())
	{
		if (isdigit(*S))//當前字元為運算元,isdigit判斷是否為10進位制數
		{
			readNumber(S, opnd);//讀入數字
			append(rpn, opnd.top());
		}
		else switch (orderBetween(optr.top(), *S))//當前字元為運算子
		{
		case '<': {
			optr.push(*S);
			S++;
			break;
		}
		case '=': {
			optr.pop();
			S++;
			break;
		}
		case '>': {
			char op = optr.pop();
			append(rpn, op);
			if (op == '!') {
				float temp = calcu(opnd.top(), op);//一元運算的情況
				opnd.pop();
				opnd.push(temp);
			}
			else {
				float pOpnd2 = opnd.top();
				opnd.pop();
				float pOpnd1 = opnd.top();
				opnd.pop();
				opnd.push(calcu(pOpnd1, op, pOpnd2));//二元運算的情況
			}
			break;
		}
		}
	}
	return opnd.top();
}

int main()
{
	Stack<char> s;
	s.push('a');
	s.push('b');
	s.push('c');
	s.push('d');
	s.show();
	cout << s.isEmpty() << endl;
	cout << s.top() << endl;
	cout << s.pop() << endl;
	s.show();
	cout << s.top() << endl;
	cout << s.pop() << endl;
	s.show();
	cout << s.top() << endl;
	cout << s.pop() << endl;
	s.show();
	cout << s.top() << endl;
	cout << s.pop() << endl;
	cout << s.isEmpty() << endl;
	s.show();
	cout << endl;
	Stack<char> c;
	convert(c, 2013, 2);
	while (!c.isEmpty())cout << c.pop();
	cout << endl;
	char a[] = "adwasfweef";
	cout << paren(a);
	char b[] = "(!c.isEmpty())cout<<c.pop();";
	cout << paren(b);
	char d[] = "((!c.isEmpty()cout<<c.pop()())";
	cout << paren(d);
	Stack<int> si;
	for (int i = 5; i > 0; i--) si.push(i);
	int arri[] = { 4, 5, 3, 2, 1 };
	cout << permutation(si, arri, 5);
	Stack<int> s2;
	for (int i = 5; i > 0; i--) s2.push(i);
	int arr2[] = { 1, 5, 3, 2, 4 };
	cout << permutation(s2, arr2, 5) << endl;
	char *r = ( char* ) malloc ( sizeof ( char ) * 1 );
	r[0] = '\0';
	char exp1[] = "2+2";
	char exp2[] = "20*(4.5-3)";
	char exp3[] = "5!-6.7";
	char exp4[] = "(1+2^3!-4)*(5!-(6-(7-(89-0!))))";
	cout << evaluate(exp1, r) << endl;
	cout << r << endl;
	r[0] = '\0';
	cout << evaluate(exp2, r) << endl;
	cout << r << endl;
	r[0] = '\0';
	cout << evaluate(exp3, r) << endl;
	cout << r << endl;
	r[0] = '\0';
	cout << evaluate(exp4, r) << endl;
	cout << r << endl;
	return 0;
}