資料結構學習筆記之棧(含數制轉換,括號匹配,表示式求值轉逆波蘭)
阿新 • • 發佈:2018-12-13
#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; }