數據結構 學習筆記 棧

首先明確,棧和隊列 是特殊的線性表。

 

棧(STL : STACK)

一、定義

棧是隻能在一端進行插入和刪除操作的線性表

日常例子:

洗碗摞一堆; 書摞成一堆; 一些槍支子彈夾中子彈的操作方式等。

1.1一些基本概念

棧頂(top)  進行插入和刪除操作的一端

棧底(bottom) 相對棧頂的另一端

入棧(push) 插入操作

出棧(pop) 出棧操作

空棧:無元素的棧

1.2棧的特性

後進先出 ( LIFO-- Last In  First Out ),或 先進後出 ( FILO-- First In  Last Out )

 

二、順序棧

2.1基本運算函數

#define MAXLEN 105
typedef struct {            //結構體定義順序棧
    int data[MAXLEN];
    int top;
}seqStack;
void initStack(seqStack *S) {        //初始化棧,將棧頂置於-1,這樣開始時從0插入
    S->top = -1;
}
bool stackEmpty(seqStack &S){        //判斷棧是否爲空
    if(S.top == -1) return true;
    else return  false;

    //return(S->top==-1);
}
bool stackFull(seqStack *S) {        //判斷棧是否爲滿
    if(S->top == MAXLEN - 1) return true;
    else return false;
}
void stackTop(seqStack *S, int *x) { //X取爲棧頂元素
    if(S->top == -1) {cout << "EMPTY ERROR" <<endl;return;}
    else *x = S->data[S->top];
}
void push(seqStack *S, int x) {       //插入
    if(S->top == MAXLEN - 1) {
        cout <<"ERROR"<<endl;
        return;
    }else {
        S->top++;
        S->data[S->top] = x;
    }
}
void pop(seqStack *S,int &x) {   //彈棧同時取到彈出元素
    if(stackEmpty(*S)) {cout <<"ERROR" <<endl; return;}
    else {
        x = S->data[S->top--];
    }
}

 

2.2 順序棧的特點

所有運算的時間複雜度均爲O(1); 通常一次性申請空間,只能按最大空間需求分配,容易造成空間浪費。-- 使用鏈式棧。

 

三、鏈棧

 

 

(以下運算爲不帶頭結點的運算)

typedef struct {
    int data[MAXLEN];
    int top;
}seqStack;
typedef struct listNode{
    int data;
    struct listNode *next;
}node;
void initStack_1(node *&top) {
    top = NULL;
}
bool stackEmpty_1(node *top) {
    return (top == NULL);
}
bool stackTop(node *top, int x) { //由於頭插法top僅跟着棧頂
    if(!top) return false;
    else {
        x = top -> data;
        return true;
    }
}
void push_1(node *& top, int x) { //頭插
    node *s;
    s = new node;
    s->data = x;
    s->next = top;
    top = s;
}
bool pop_1(node *& top, int &x) {
    node *u;
    if(!top) return false;
    else {
        x = top->data;          //取彈出元素
        u = top;                //臨時指針指到top
        top = top->next;        //top 後移
        delete(u);              //刪除結點
        return true;
    }
}
void DeleteStack(node *&top) {
    node *p, *u;
    p = top;
    while(p) {
        u = p;
        p = p->next;
        delete(u);
    }
    top = NULL;
}

時間複雜度上,銷燬鏈棧是O(N),其餘均爲O(1)

鏈棧的特點
·使用連續或不連續的儲存空間
·各數據元素獨立儲存,依靠指針鏈接邏輯相鄰關係
·對每個數據元素都單獨申請結點
·不會存在棧滿溢出的問題
·每個棧頂指針top唯一確定一個鏈棧

 

棧的應用舉例

一、單鏈表的就地逆置

方法一、使用中間結點頭插法建立新表

void reverse(node *&L) {        //STACK APPLICATION-1
    node *P = NULL;     //P指向i-1
    node *u;            //u指向i
    while(L) {
        u = L;          //u指向待分離的表頭
        L = L->next;    //未逆置部分的表頭指針L後移指向i+1
        u->next = P;    //新分離的i結點的next指向P 形成逆置
        P = u;          //已逆置部分的頭指針P指向i
    }
    L = P;              //原表頭指針指向新表頭
}

方法二、使用棧

將元素結點存在棧中,依次彈棧後用尾插法建立鏈表

void reverse1(node *&L) {       //STACK APPLICATION-2
    node *R, *u;
    seqStack S;
    initStack(&S);
    u = L;
    while(u) {
        push(S,u);              //結點壓入棧
        u = u->next;
    }
    if(stackEmpty(S)) {
        return;
    }
    stackTop(&S,u);             //取棧頂元素
    L = u;                      //新的表頭元素
    R = u;                      //表尾指針
    u->next = NULL;
    pop(S,u);
    while(!stackEmpty(S)) {
        stackTop(S,u);
        R->next = u;
        u->next = NULL;
        R = u;
        pop(S,u);
    }
}

 

逆波蘭表達式

#include <iostream>
#include <stack>
using namespace std;
const int MAXN = 1000 + 5;
char s[MAXN];
int pos;        //數組下標
int trans(int &pos) {
    int ans = 0;
    while(s[pos] >= '0' &&s[pos] <= '9') {
        ans *= 10;
        ans += (s[pos] -'0');
        pos++;
    }
    return ans;
}
int Level(char ch) {
    switch (ch) {
        case '+':
        case '-':
            return 1;
        case '*':
        case '/':
            return 2;
        case '(':
            return 0;
        case '#':
            return -1;
    }
}
int Op(int a1, char op, int a2) {
    switch (op) {
        case '+':
            return a1 + a2;
        case '-':
            return a1 - a2;
        case '*':
            return a1 * a2;
        case '/':
            return a1 / a2;
    }
}
int Computer() {
    stack<int> op1;
    stack<char> op2;
    op2.push('#');
    int len = strlen(s);
    bool minus = true;
    for(pos = 0; pos < len;) {
        if(s[pos] == '-' && minus) {
            op1.push(0);
            op2.push('-');
            pos++;
        }
        else if (s[pos] == ')') {
            minus = false;
            pos++;
            while(op2.top() != '(') {
                int a2 = op1.top();
                op1.pop();
                int a1 = op1.top();
                op1.pop();
                char op = op2.top();
                op2.pop();

                int res = Op(a1,op,a2);
                op1.push(res);
            }
            op2.pop();
        }
        else if(s[pos] >= '0' && s[pos] <= '9') {
            minus = false;
            op1.push(trans(pos));
        }
        else if (s[pos] == '(') {
            minus = false;
            op2.push(s[pos]);
            pos++;
        }
        else {
            while(Level(s[pos]) <= Level(op2.top())) {
                int a2 = op1.top();
                op1.pop();
                int a1 = op1.top();
                op1.pop();
                char op = op2.top();
                op2.pop();

                int res = Op(a1,op,a2);
                op1.push(res);
            }
            op2.push(s[pos]);
            pos++;
        }
    }
    while(op2.top()!='#') {
        int a2 = op1.top();
        op1.pop();
        int a1 = op1.top();
        op1.pop();
        char op = op2.top();
        op2.pop();

        int res = Op(a1,op,a2);
        op1.push(res);
    }
    return op1.top();
}
int main() {
    cin >> s;
    cout << "The Result is that:" << Computer() << endl;
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章