数据结构——栈

来源:互联网 发布:aris软件下载 编辑:程序博客网 时间:2024/06/04 18:39

数据结构——栈

1、栈的定义
栈是一种特殊的线性表。其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行。该位置是表的末端,叫做栈顶(top
图像模拟

左边的栈的示意图 右边为用铁路调度站表示栈
2、栈的基本运算
构造空栈:InitStack(S)
判栈空: StackEmpty(S)
判栈满: StackFull(S)
进栈: Push(S,x) 可形象地理解为压入,这时栈中会多一个元素
退栈: Pop(S) 可形象地理解为弹出,弹出后栈中就无此元素了。
取栈顶元素:StackTop(S) 不同与弹出,只是使用栈顶元素的值,该元素仍在栈顶不会改变
3、栈的存储结构
1)顺序存储
顺序存储也叫数组存储。
潜在问题:
需要提前估计一个数组的大小,其实在实际应用中,这个不难做到;对错误的检测严重影响执行的效率问题
(在顺序栈中有"上溢"和"下溢"的概念。顺序栈好比一个盒子,我们在里头放了一叠书,当我们要用书的话只能从第一本开始拿(你会把盒子翻过来吗?真聪明^^),那么当我们把书本放到这个栈中超过盒子的顶部时就放不下了(叠上去的不算,哼哼),这时就是"上溢","上溢"也就是栈顶指针指出栈的外面,显然是出错了。反之,当栈中已没有书时,我们再去拿,看看没书,把盒子拎起来看看盒底,还是没有,这就是"下溢"。"下溢"本身可以表示栈为空栈,因此可以用它来作为控制转移的条件。)
简单应用:平衡符号
算法思想:做一个空栈。读入字符直到文件结尾,如果字符是一个开放符号,将其入栈。如果是一个封闭符号,则当栈空时报错,否则,将元素弹出,如果弹出的符号不是其对应的开放符号,则报错。到了文件尾,如果栈非空则报错。

    #include <iostream>    #include <string>    const int maxn = 100;    using namespace std;    struct *Stack    {        int Capacity;//栈的容量        int Top_of_stack;//栈的下标        char *Array; //存放栈中元素的数组    }; //栈的数组实现    typedef struct Mystack *Stack;    Stack CreateStack(int Max);//创建一个栈    void DisposeStack(Stack S);//释放栈    int IsEmpty(Stack S);//判断一个栈是否是空栈    int IsFull(Stack S);//判断一个栈是否是满栈    void Push(int x, Stack S);//入栈    void Pop(Stack S);//出栈    char Top(Stack S);//获取栈顶元素    Stack CreateStack(int Max)    {        Stack S;        S = (Stack)malloc(sizeof(struct Mystack));        if(S == NULL)            cout << "Create stack error!" << endl;        S->Array = (char *)malloc(sizeof(char) * Max);        if(S->Array == NULL)            cout << "Create stack error!" << endl;        S->Capacity = Max;        S->Top_of_stack = 0;        return S;    }    //释放栈    void DisposeStack(Stack S)    {        if(S != NULL)        {            free(S -> Array);            free(S);        }    }    //判断一个栈是否是空栈    int IsEmpty(Stack S)    {        return !S->Top_of_stack;    }    //判断一个栈是否为满栈    int IsFull(Stack S)    {        if(S->Top_of_stack == S->Capacity - 1)            return 1;        else            return 0;    }    //数据入栈    void Push(int x, Stack S)    {        if(IsFull(S))            cout << "The Stack is full!" << endl;        else            S->Array[S->Top_of_stack++] = x;    }    //数据出栈    void Pop(Stack S)    {        if(IsEmpty(S))            cout << "The Stack  is empty!" << endl;        else            S->Top_of_stack--;    }    //将栈顶返回    char Top(Stack S)    {        if(!IsEmpty(S))            return S->Array[S->Top_of_stack - 1];        cout << "The Stack is empty!" << endl;        return 0;    }    int main()    {        char str[maxn];        cin >> str;        int len = strlen(str);        //根据序列的长度来创建栈        struct Mystack *my_stack = CreateStack(len + 1);        for(int i = 0;i < len; i ++)        {            //如果字符时开放符号,则将其推入栈中            if(str[i] == '{' || str[i] == '[' || str[i] == '(')                Push(str[i],my_stack);            //如果字符时一个封闭符号,则当栈空时报错,否则将栈弹出来            if(str[i] == '}')            {                if(Top(my_stack) == '{')                    Pop(my_stack);                else                    break;            }            else if(str[i] == ']')            {                if(Top(my_stack) == '[')                    Pop(my_stack);                else                    break;            }            else if(str[i] == ')')            {                if(Top(my_stack) == '(')                    Pop(my_stack);                else                    break;            }        }        //如果最后占空则序列是合法的,否则是不平衡的        if(IsEmpty(my_stack))            cout << "The symbol that you input is balance!" << endl;        else            cout << "The symbol that you inut is imbalance!" << endl;        DisposeStack(my_stack);        return 0;    }

2)链式存储
栈的操作诗线性表操作的特例:
若是栈中元素的数目变化范围较大或不清楚栈元素的数目,就应该考虑使用链式存储结构。人们将用链式存储结构表示的栈称作"链栈"。链栈通常用一个无头结点的单链表表示。

简单应用:平衡符号

#include <stdio.h>#include <stdlib.h>#define Error(Str) fprintf(stderr,"%s\n",Str),exit(1)struct Node{    char elem;    struct Node *next;};//栈的链表实现typedef struct Node *Stack;int CheckSymbol(Stack S);//检测平衡符号的函数Stack CreateStack(void);/*创建一个空栈*/void MakeEmpty(Stack);int IsEmpty(Stack);//测试栈是否是空栈void Push(char ,Stack);//入栈void Pop(Stack);//出栈char Top(Stack);//获取栈顶元素void DisposeStack(Stack);//销毁栈int main(){    Stack S;    S=CreateStack();    if(CheckSymbol(S))        printf("wrong\n");    else         printf("right\n");    DisposeStack(S);    return 0;}int CheckSymbol(Stack S){    char ch;    printf("input characters as {,} or (,)or [,] \n");    printf("and # to quit\n");    while((ch=getchar())!='#')//输入平衡字符    {        if(ch=='{'||ch=='['||ch=='(')        /*开放符号*/            Push(ch,S);        else if(ch=='}'||ch==']'||ch==')')    /*封闭符号*/            {                if(IsEmpty(S))        /*栈里无字符*/                    Error("stack is empty.");                else                 {                    switch(ch)                    {                        case '}':                            if(Top(S)!='{')//不匹配                            Error("not match");                            else                             break;//匹配成功                        case ')':if(Top(S)!='(')                            Error("not match");                            else                             break;                         case ']':if(Top(S)!='[')                            Error("not match");                            else break;                     }                    /*匹配成功,将栈中匹配成功的符号弹出*/                    Pop(S);                }            }    }    if(!IsEmpty(S))//如果最后栈里还有字符,则说明未匹配完,即出错        Error("the stack is not empty last");    else         return 0;//成功}/*栈的基本操作——链表实现*/Stack CreateStack(void){    Stack S;    S=malloc(sizeof(struct Node));    if(S==NULL)        Error("out of space");    S->next=NULL;    MakeEmpty(S);    return S;    }void MakeEmpty(Stack S)//设置Next指针指向NULL{    if(S==NULL)    //未创建栈        Error("must usr CreateStack first");    else        while(!IsEmpty)            Pos(S);}int IsEmpty(Stack S){    return S->next==NULL;}void Push(char ch,Stack S)//向前链表前端进行插入实现{    Stack tmp;    tmp=malloc(sizeof(struct Node));    if(!tmp)        Error("out of space");    tmp->elem=ch;    tmp->next=S->next;    S->next=tmp;    }void Pop(Stack S)//通过删除表的前端元素而实现{    Stack tmp;    if(IsEmpty(S))        Error("empty stack");    else    {        tmp=S->next;        S->next=tmp->next;        free(tmp);    }}char Top(Stack S)//通过考查表的第一个位置上元素而完成的{    if(!IsEmpty(S))        return S->next->elem;    Error("empty stack.");    return 0;}void DisposeStack(Stack S){    if(S==NULL)        Error("no stack");    MakeEmpty(S);    free(S);}

4、C++ STL—stack
1)stack 模板类的定义在<stack>头文件中。
2)stack 模板类需要两个模板参数,一个是元素类型,一个容器类型,但只有元素类型是必要的,在不指定容器类型时,默认的容器类型为deque。
3)定义stack 对象的示例代码如下:stack<int> s1; stack<string> s2;
4)stack 的基本操作有:
入栈,如例:s.push(x);
出栈,如例:s.pop();注意,出栈操作只是删除栈顶元素,并不返回该元素。
访问栈顶,如例:s.top()
判断栈空,如例:s.empty(),当栈空时,返回true。
访问栈中的元素个数,如例:s.size()
简单应用:中缀到后缀的转换
算法思路:
①遇到数字:直接输出
②遇到'(':压栈
③遇到')':持续出栈,如果出栈的符号不是'('则输出,否则终止出栈。
④遇到符号:判断该符号与栈顶符号的运算优先级,如果栈顶符号的运算优先级高,则出栈并输出,直到优先级相等或栈为空;如果栈顶符号的运算优先级低于或等于当前符号的运算优先级,则将当前符号压栈。
⑤处理完字符串后将栈中剩余的符号全部输出。
样例:中缀表达式:6*[5+(2+3)*8+3] 后缀表达式:6523+8*+3+*

#include<iostream>#include<string>#include<sstream> //基于字符串的流#include<stack>  //STL堆栈容器using namespace std;int main(){    //输入字符串    string in;    cin >> in;    stack<char> stack;    for(size_t i = 0; i != in.size(); ++i) //size_t是在标准C库中定义,为unsigned int    {        if(in[i] == '(' || in[i] == '*' || in[i] == '/') //遇到'('入栈,由于*/优先级别比栈顶高,直接入栈        {            stack.push(in[i]);        }        //持续出栈        else if(in[i] == ')')        {            while(1)            {                char tmp = stack.top();                stack.pop();                if(tmp != '(')                {                    cout << tmp;                }                else                    break;            }        }        else if(in[i] == '+' || in[i] == '-')        {            if(stack.top() == '*' || stack.top() == '/')            {                while(stack.top() == '*' || stack.top() == '/')                {                    cout << stack.top();                    stack.pop();//比栈顶优先级低,直接出栈并且输出                }                cout << in[i];            }            else                stack.push(in[i]);        }        else            cout << in[i]; //遇到数字直接输出    }    while(stack.size())    {        cout << stack.top();        stack.pop();    }}

更多应用:
UVa514 Rails(铁轨)
UVa442 Matrix Chain Multiplication(矩阵链乘)
参考文献与链接:
《数据结构与算法分析——C语言描述》
《算法竞赛入门经典》
堆栈概念
C++ STL


0 0
原创粉丝点击