栈 -- 顺序栈、链式栈的实现 及其应用(函数栈,表达式求值,括号匹配)
生活随笔
收集整理的這篇文章主要介紹了
栈 -- 顺序栈、链式栈的实现 及其应用(函数栈,表达式求值,括号匹配)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 實現
- 順序棧實現
- 鏈式棧實現
- 應用
- 函數棧 的應用
- 表達式求值中 的應用
- 括號匹配中 的應用
我們使用瀏覽器的時候經常會用到前進、后退功能。
依次訪問完一串頁面 a – b – c之后點擊后退功能,則能夠依次看到c – b – a的頁面。
但是這個過程中,如果后退到了頁面b,點擊了新的頁面d,則再點擊前進無法回到頁面c。
這個過程的實現就是我們 “棧”數據在其中起作用了。
實現
棧的基本實現有如下兩種:
- 順序棧 – 基于數組的實現
- 鏈式棧 – 基于鏈表的實現
順序棧實現
#include <iostream>
#include <assert.h>using namespace std;class ArrayStack{
private:int size; // stack sizeint count; // stack element countint *arr; // 數組,保存棧中元素public:ArrayStack(int n) {size = n;count = 0;arr = new int[n];}ArrayStack(ArrayStack &obj) = delete;~ArrayStack() {delete []arr;}; //析構掉new出來的數組bool push(int element); // push元素到棧中int pop(); //從棧中彈出元素,并返回彈出到數值bool isEmpty(); //棧是否為空void show(); //打印棧中元素int get_size() { return size;} //獲取棧的大小
};bool ArrayStack::push(int element) {assert(count != size );arr[count] = element;count ++;return true;
}int ArrayStack::pop() {assert(count != 0);int tmp = arr[count];count --;return tmp;
}bool ArrayStack::isEmpty() {if(count != 0) {return true;}return false;
}void ArrayStack::show() {if(!this->isEmpty()) {cout << "stack is empty " << endl;}cout << "stack size is: " << count << " element is :";for (int i = 0;i < count; ++i) {cout << arr[i] << " ";}cout << endl;
}typedef struct Link{int val;struct Link *next;
}list;class ListStack {
private:int size; // stack的大小int count; // stack的長度list *head; // 鏈表public:};int main() {ArrayStack st(5);int ele;int len = st.get_size();while (len != 0) {cin >> ele;st.push(ele);len --;}st.show();st.pop();st.show();st.pop();st.show();return 0;
}
輸出如下:
#輸入
2 3 4 5 6#輸出
stack size is: 5 element is :2 3 4 5 6
stack size is: 4 element is :2 3 4 5
stack size is: 3 element is :2 3 4
鏈式棧實現
#include <iostream>
#include <assert.h>using namespace std;/*鏈式棧的功能實現*/
template <class T> //模版類,用來創建任意數據類型的棧
class ListStack {
private:int size; // stack的大小int count; // stack的長度/*鏈式棧的數據結構*/struct Link{T val;struct Link *next;Link(T x = T()): val(x), next(nullptr){}};Link *head; // 鏈表public:ListStack(){} //默認構造函數ListStack(int n):size(n),count(0){head = new Link;}~ListStack();bool push(T x); //向棧中push元素T pop(); //pop元素bool isEmpty();void show();int get_size() { return size;}
};template <class T>
ListStack<T>::~ListStack() {Link *p, *tmp;p = head;while(p->next) {tmp = p -> next;p -> next = p -> next -> next;delete tmp;}delete head;size = 0;count = 0;
}template <class T>
bool ListStack<T>::push(T x) {if(count == size) {return false;}auto *p = new Link;p ->val = x;p -> next = head -> next;head -> next = p;count ++;return true;
}template <class T>
T ListStack<T>::pop() {if (count == 0 || head == NULL) {return -1;}auto *p = head -> next;T val = p -> val;head -> next = head -> next -> next;count --; // 棧中元素個數自減delete p; // 需要將pop的元素空間釋放return val;
}template <class T>
bool ListStack<T>::isEmpty() {return count == 0;
}template <class T>
void ListStack<T>::show() {if(isEmpty() || head == NULL) {cout << "stack is empty" << endl;}auto *p = head -> next;cout << "stack size is : " << count << " element is :";while(p) {cout << p -> val << " ";p = p -> next;}cout << endl;
}
int main() {ListStack<int> *st = new ListStack<int>(5); //初始化鏈式棧的大小為5int ele;int len_stack = st -> get_size();cout << "stack length is " << len_stack << endl;while(0 != len_stack) {cin >> ele;st->push(ele);len_stack --;}st->show();st->pop();st->show();st->pop();st->show();return 0;
}
輸出如下:
stack length is 5#輸入元素
2 3 4 5 6#輸出
stack size is : 5 element is :6 5 4 3 2
stack size is : 4 element is :5 4 3 2
stack size is : 3 element is :4 3 2
應用
函數棧 的應用
操作系統在進程運行的時候會為進程中的每個線程分配獨立的內存空間,這塊內存被組織成獨立的棧的數據結構,用來存儲函數調用時的臨時變量。每進入一個函數,就會將臨時變量作為一個棧幀入棧,當被調用函數執行完成,返回之后,這個函數對應的棧幀就會出棧。
如代碼:
int main() {int a = 1;int ret = 0;int res = 0;ret = add(3, 5); res = a + ret; printf("%d", res);return 0;
}
int add(int x, int y) { int sum = 0;sum = x + y;return sum;
}
從代碼中可以看到main()調用add()函數,獲取計算結果,并與臨時變量a相加,最后打印res的數值。
棧幀的組織圖基本如下:
表達式求值中 的應用
要求支持帶括號的四則元算,可以使用數據棧和符號棧進行實現
過程如下:
實現過程如下:
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>using namespace std;void print_erro(string s,int line) {cout << s <<" " << line << endl;exit(-1);
}void calculate(stack<int> &num_stak, stack<char> &oper_stack) {int num1;int num2;int result;num1 = num_stak.top();num_stak.pop();num2 = num_stak.top();num_stak.pop();if (oper_stack.top() == '+') {result = num1 + num2;} else if (oper_stack.top() == '-') {result = -(num1 - num2);} else if (oper_stack.top() == '*') {result = num1 * num2;} else if (oper_stack.top() == '/') {if (num1 == 0) {print_erro("divide num is 0 \n", __LINE__);}result = num2 / num1;} else {print_erro("operator failed\n", __LINE__);}oper_stack.pop();num_stak.push(result);
}int state_change(string s) {static const int BEGIN_STATE = 0;static const int NUM_STATE = 1;static const int OPE_STATE = 2;int STATE = BEGIN_STATE;map<char,int> prio;stack<int> num_stack;stack<char> oper_stack;int cacl_flag = -1;int number = 0;prio['+'] = 1;prio['-'] = 1;prio['*'] = 2;prio['/'] = 2;prio['('] = 3;int i;if (s.empty()) {print_erro("string is empty\n",__LINE__);}for(int i = 0;i < s.size(); ++i) {if (s[i] == ' ') {continue;}switch (STATE){case BEGIN_STATE:if (s[i] >= '0' && s[i] <= '9') {STATE = NUM_STATE;} else if(s[i] == ')'){print_erro("string is not leagal\n",__LINE__);} else {STATE = OPE_STATE;}i--;break;case NUM_STATE:if (s[i] >= '0' && s[i] <= '9') {number = number*10 + s[i] - '0';} else {num_stack.push(number);if (cacl_flag == 2) {calculate(num_stack,oper_stack);}STATE = OPE_STATE;number = 0;i--;}break;case OPE_STATE:if(prio[s[i]] == 1) {oper_stack.push(s[i]);cacl_flag = 1;} else if(prio[s[i]] == 2) {oper_stack.push(s[i]);cacl_flag = 2;} else if (prio[s[i]] == 3) {cacl_flag = 3;STATE = NUM_STATE;break;} else if (s[i] == ')') {calculate(num_stack,oper_stack);break;} else if(s[i] >= '0' && s[i] <= '9') {STATE = NUM_STATE;i--;} else {print_erro("string is not leagal \n",__LINE__);}break;default:break;}}if (number != 0) {num_stack.push(number);calculate(num_stack,oper_stack);}if (number == 0 && num_stack.empty()) {return 0;}while(!oper_stack.empty() && num_stack.size() != 1) {calculate(num_stack,oper_stack);}if (!oper_stack.empty()) {print_erro("string is not leagal", __LINE__);}return num_stack.top();
}int main() {string s;cout << "input the string " << endl;cin >> s;int a = state_change(s);cout << "calcute the result is " << a << endl;return 0;
}
編譯運行如下:
input the string
(((1+5)/2+6*9+10)-(2+3)*100)
calcute the result is -433
括號匹配中 的應用
給定一個由括號組成的字符串,判斷該字符串是否是一個合法的括號序列
假設給定的字符串中只包含三種括號:花括號{},方括號[],圓括號(),它們可以任意嵌套,如:{[{}]}或則[{()}([])]都為合法括號,{[}()]或則[({)]為不合法括號。
這個時候我們可以使用棧來保存未匹配的左括號,基本實現過程如下:
- 從左到右依次掃描字符串,當遇到左括號的時候入棧
- 遇到右括號 則從 棧頂取一個左括號,如果能夠和當前右括號匹配(比如"(“和”)“匹配,”[“和”]“匹配,”{“和”}"匹配),則棧頂左括號可以從棧頂彈出。
- 繼續掃描后續字符串,如果遇到不能配對的右括號,或者棧中沒有數據,則說明當前括號序列不合法。
實現如下:
bool isValid(string s) {if(s.length() == 0) return true;stack<char> S;for (int i = 0;i < s.length(); ++i) {switch(s[i]) {case ')':{if(!S.empty()) {if(S.top() == '('){S.pop();} else {return false;}}else {return false;}break;}case ']':{if(!S.empty()) {if(S.top() == '['){S.pop();} else {return false;}}else {return false;}break; }case '}':{if(!S.empty()) {if(S.top() == '{'){S.pop();} else {return false;}}else {return false;}break; }case '(':{S.push(s[i]);break;}case '[':{S.push(s[i]);break;}case '{':{S.push(s[i]);break;}}}if (S.size() != 0) {return false;}return true;
}
總結
以上是生活随笔為你收集整理的栈 -- 顺序栈、链式栈的实现 及其应用(函数栈,表达式求值,括号匹配)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构和算法 -- 学习导图
- 下一篇: ceph bluestore 源码分析: