一、 栈的定义:
栈是重要的线性结构。从数据结构角度看,栈也是线性表,其特殊性在于栈的基本操作是线性表操作的子集,它们是操作受限的线性表(线性表中数据元素是一对一的关系),因此,可称为限定性的数据结构。
栈(stack)是限定仅在表尾进行插人或删除操作的线性表。因此,对栈来说,表尾
端有其特殊含义,称为栈顶(top),相应地,表头端称为栈底(bottom)。不含元素的空表称为空栈。
假设栈S=(a1, a2,…, an),则称a1为栈底元素,an为栈顶元素。栈中元素按a1,a2,…an的次序进栈,退栈的第一个元素应为栈顶元素。换句话说,栈的修改是按后进
先出的原则进行的(如下图所示)。因此,栈又称为后进先出(last in first out)的线
性表(简称LIFO结构)。
栈的基本操作除了在栈顶进行插入或删除外,还有栈的初始化、判空及取栈顶元素
等。
二、栈的顺序存储结构
和线性表类似,栈也有两种存储表示方法——顺序存储结构和链式存储结构。
下面我们主要介绍前者:
顺序栈,即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top指示校顶元素在顺序校中的位置。通常的习惯做法是以top=o表示空栈。一般来说,在初始化设空栈时不应限定栈的最大容量。一个较合理的做法是:先为栈分配一个基本容量,然后在应用过程中,当栈的空间不够使用时再逐段扩大。
为此,我们可以设定两个常量:STACK._INIT_SIZE(存储空间初始分配量)和STACKINCREMENT存储空间分配增量),并以下述类型说明作为顺序栈的定义。
typedef struct (
Selemtype * base;
Selemtype * top;
int stacksize;
}Sqtack;
其中,stacksize指示栈的当前可使用的最大容量。校的初始化操作为:按设定的初始分配量进行第一次存储分配,base可称为栈底指针,在顺序栈中,它始终指向栈底的位置,若base的值为NULL,则表明栈结构不存在。称top为栈顶指针;其初值指向栈底.即tops=base可作为栈空的标记,每当插人新的栈顶元素时,指针top增1;删除栈顶元素时,指针top减1,因此,非空栈中的栈顶指针始终在栈顶元素的下一个位置上。下图展示了顺序栈中数据元素和栈顶指针之间的对应关系。
三、栈应用举例之括号的配对问题
今天在在南阳理工学院的在线ACM测试上发现的,难度适中,自认为具有一定代表性,上题:
解题思路如下:
因为字符串中仅含有圆括号和方括号,其嵌套的顺序随意,即()或[([]])]等为正确的格式,[(])或([())或(()])均为不正确的格式。检验括号是否
匹配的方法可用”期待的急迫程度“这个概念来描述。例如考感下列括号序列:
当计算机接受了第一个括号后,它期待着与其匹配的第八个括号的出现,然而等来的却是第二个括号,此时第一个括号”[“只能暂时靠边,而迫切等待与第二个括号相匹配的、第七个括号”)”的出现,类似地,因等来的是第三个括号”[“,其期待匹配的程度较第二个括号更急迫,则第二个括号也只能靠边,让位于第三个括号,显然第二个括号的期待急迫性高于第一个括号;在接受了第四个括号之后,第三个括号的期待得到满足,消解之后,第二个括号的期待匹配就成为当前最急迫的任务了,……,依次类推。可见,这个处理过程恰与栈的特点相吻合。由此,在算法中设置一个枝,每读人一个括号,若是右括号,则或者使置于栈顶的最急迫的期待得以消解,或者是不合法的情况;若是左括号,则作为一个新的更急迫的期待压人校中,自然使原有的在校中的所有未消解的期待的急迫性都降了一级。
通俗地讲,我们利用栈后进先出的特点,当接受的是左括号(‘(’或‘]’)时,我们将其插入栈中为栈顶元素,当接受的是右括号(‘)’或‘]’)时,若与栈顶元素配对成功,则对计数变量累加,接着删除栈顶元素,使其次紧迫的元素成为新的栈顶元素。
另外,在算法的开始和结束时,栈都应该是空的。
#include <stdio.h>
#include<stdlib.h>
#include <malloc.h>
#define STACK_INIT_SIZE 12000 //存储空间初始分配量
#define STACKINCREMENT 100 // 存储空间分配增量
#define EleType char
//栈的节点声明
typedef struct Stack{
EleType *top;
EleType *base;
int stacksize;
}Sqtack;
void Init_Stack(Sqtack *s){
s->base=(EleType *)malloc(STACK_INIT_SIZE*sizeof(EleType));//top为0表示空栈
if(!s->base)exit(-1); //存储分配失败
s->top=s->base;
s->stacksize=STACK_INIT_SIZE;
}
EleType Gettop(Sqtack *s){
//若栈不空,则e返回s的栈顶元素,
EleType e;
if(s->top==s->base)
return 0;
else
e=*(s->top-1);
return e;
}
void Push(Sqtack *s,EleType e){
//插入元素e为新的栈顶元素
if(s->top-s->base>=s->stacksize) {//栈满追加存储空间
s->base=(EleType *)realloc(s->base,(s->stacksize+STACKINCREMENT)*sizeof(EleType)); //realloc 函数:指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。
if(!s->base)exit(-1);
s->top=s->base+s->stacksize;
s->stacksize+=STACKINCREMENT;
}
*s->top++=e;
}
void Pop(Sqtack *s){
//若栈不为空,则删除s的栈顶元素
if(s->top!=s->base)
--s->top;
}
int main(){
int N,n;
scanf("%d",&N);
n=N;
while(N--)
{
char f[10001]={'\0'};
Sqtack ss,*s;
int i=0,t=0;
EleType ce,ch;
s=&ss;
Init_Stack(s);
if(N==n-1)
ch=getchar();
gets(f);
while(f[i]!='\0'){
ch=f[i];
if(ch=='('||ch=='[')
Push(s,ch);
ce=Gettop(s);
if(ch==')'){
if(ce=='(')
t++;
Pop(s);
}
if(ch==']'){
if(ce=='[')
t++;
Pop(s);
}
i++;
}
if(i%2!=0)
{printf("No\n"); continue;}
else
{
if(t!=(i/2))
{printf("No\n"); continue;}
printf("Yes\n");
}
}
return 0;
}
本文为自己在学习数据结构过程中一点不太成熟的想法,主要参考了严蔚敏老师的《数据结构(c语言版)》,若有不当之处还望大佬们批评指正!