算法编程数据结构和算法分析算法

【数据结构】栈

2021-04-11  本文已影响0人  Burnside

本文更新于个人博客Burnside Blog

总的来说,栈(Stack)是一种应用十分广泛的线性数据结构,我们大多数时候可以把它理解成一个杯子,杯子只有一个口,它既是进入的入口,也是退出的出口。的确如此,栈是一种先入后出(LIFO)的数据结构,它支持插入与删除两种操作,且两个操作仅可以在一端进行。

为了方便起见,我们不使用动态方式生成一个栈,或销毁一个栈,我们只考虑一个静态的栈的功能实现。栈中的元素可以是任何的用户自定义类型,为了方便起见,我们假设元素的类型为int,如需要别的类型,只需要灵活处理即可。接下来我们申请一块长度为MaxSize的连续内存来存储这个栈,这时它又被称为顺序栈。

int Stack[MaxSize];

这样我们就成功获得了一个自己的栈。考虑往栈中插入元素或删除元素,所改变的只有最顶部的元素距栈底的距离,这里的距离表示的是元素个数,我们把这个顶部称为栈顶,可以用一个变量top来维护,最顶部的元素为栈顶元素,不难发现,每一次的删除操作,总是删除的栈顶元素。

因此,我们会得到栈的几个操作:

1、插入元素

int push(int x){

    Stack[++top]=x;

    return top;

}

插入一个元素很简单,只需要将栈顶指向数组内的下一个位置,然后把该位置赋值为要插入的值即可,函数中的变量x即为需要插入的值,top为栈顶,此函数返回值为插入后的栈顶。注意,当栈为空的时候,变量top应当等于-1。

2、删除元素

int pop(){

    return --top;

}

删除一个元素更简单,只需要将栈顶下移一个就可以。注意,原来的栈顶元素不需要做任何的改变,因为只要插入到这个位置,这个位置就会立马被赋值上被插入的新的元素,所以只需要让栈顶下移即可,而并不需要改变栈顶元素的值。此函数返回的是删除后的栈顶。要注意,这里有一个潜在的问题,如果这个时候栈已空,但仍然调用了pop(),可能会使以后的操作访问到非法位置,因此,请务必确保栈是非空的,再使用pop(),为了方便确保栈是否为空,我们引入一个新的函数。

3、查询栈是否为空

bool empty(){

    return top==-1?true:false;

}

很简单,栈为空的标志为top等于-1,直接调用即可。

4、查询栈现在的大小(size)

int size(){

    return top+1;

}

也很简单,栈的大小为top+1。

5、查询栈顶元素

int top(){

    return Stack[top];

}

请注意,请务必在栈非空的情况下使用该命令。

6、删除栈内的所有元素

void clear(){

    while(!empty()) pop();

}

很自然的实现,当栈为非空时,一直删除元素就可以了。

以上为栈的所有操作,部分书中还介绍了链式栈,本文中不再涉及,具体的实现思想与上述六个函数一样。

栈有很多实际的应用,其中常见的有:把一个十进制数拆分为二进制,查询一个括号序列是否能够匹配,计算表达式的值等。我们主要来写查询括号序列是否匹配,剩下两个常见功能读者可以自行完成。

括号序列,是仅由(与)构成的序列,匹配的定义如下:

1. ()是一个合法匹配。

2. 如果A是一个合法匹配,则(A)是一个合法匹配。

3. 如果A和B都是合法匹配,则AB是一个合法匹配。

不难发现,()()(())((())())是一个合法匹配,而(()不是一个合法匹配。

判断的过程也很轻松,我们只需要模拟这个匹配的过程就可以了,具体操作步骤如下:

1. 如果当前读取到一个(,进栈,读取下一位。

2. 如果当前读取到一个),如果栈非空,取栈顶的右括号与之匹配,读取下一位;如果栈空,则找不到括号与之匹配,证明其不合法。

3. 如果读完了整个括号序列栈空,则整个括号序列合法,否则不合法。

正确性显然,不过多赘述,代码如下:

#include<iostream>

#include<cstdio>

const int MaxSize=1000;

char Stack[MaxSize];

int top=-1,flag=true;

int main(){

    char c;

    while((c=getchar())!=EOF){

        if(c=='(') Stack[++top]='(';

        else{

            if(top==-1){

                flag=false;

                break;

            }

            top--;

        }

    }

    if(top!=-1) flag=false;

    printf(flag?"legal":"illegal");

    return 0;

}

可能会有人表示输出总是illegal,因为在一开始读的时候把回车也读进去了,可以使用文件输入输出,最后不换行就可以了,或者可以采用其他的输入方式。

在某些特殊应用中,还会使用到单调栈,因为仅在竞赛中常用,因此不在本文中描述。

上一篇 下一篇

猜你喜欢

热点阅读