栈的定义
栈是限定仅在表尾进行插入删除操作的线性表。因此,表尾对栈有特殊的意义,称为栈顶,相应地,表头称为栈底,不含元素的空表叫空栈。
顺序栈的表示和实现
栈的定义
由于我们在栈中只对栈顶插入和删除,所以我们需要一个栈顶指针,当满栈的时候,我们需要对栈进行扩容,所以也需要一个参数来表示当前栈的大小,当我们在进行删除操作的时候,要判断栈是否下溢,这就需要一个栈底指针,这就是定义顺序栈的基本元素。
#define STACKsize 100//存储空间初始分配量
#define STACKIN 10//存储空间分配增量
#define OK 1
#define over -2
typedef int SDatatype;
typedef int status;
typedef struct{
SDatatype *base;//栈底指针,在栈构造之前和销毁之后,base为NULL
SDatatype *top;//栈顶指针
int stacksize;//当前已分配的空间,以元素为单位
}sqstack;
栈的初始化
每次创建一个新栈的时候,栈顶指针总是和栈底指针相等的。
//初始化顺序栈
status Inistack(sqstack &s){
s.base = (SDatatype *)malloc(STACKsize*sizeof(SDatatype));//申请内存空间
if(!s.base){
return over;//初始化失败
}
s.top = s.base;
s.stacksize = STACKsize;
return OK;
}
入栈
只要是入栈的时候,都要判断栈是否满了,满了就得扩容
//入栈
status push(sqstack &s,SDatatype e){
SDatatype *p;
//判断是否满栈
if(s.top-s.base == s.stacksize){
p = (SDatatype *)realloc(s.base,(STACKsize+STACKIN)*sizeof(SDatatype));
if(!p){
return over;
}
s.base = p;//系统会将原来的栈复制过来
s.top = s.base+s.stacksize;//使top指向新的栈顶
s.stacksize += STACKIN;
}
*(s.top)++ = e;//入栈
return OK;
}
出栈
每次出栈,都得判断栈是否为空了
//出栈
status pop(sqstack &s,SDatatype &e){
//判断是否发生下溢
if(s.top != s.base){
e = *--s.top; //先将栈顶减1
}
else return 0;
return e;
}
判断是否为空栈
//判断是否为空栈
bool stacknull(sqstack &s){
if(s.top == s.base){
return true;
}
else return false;
}
取栈顶元素
//取栈顶元素
SElemType GetTop(SqStack S)
{
if (S.top != S.base) //非栈空时返回
return *(S.top - 1); //++会改变指针自身值,而-1不会改变
}
栈的遍历
//遍历输出栈
void printStack(SqStack S)
{
printf("base:");
SElemType* p = S.base;
while (p != S.top)
{
printf("%d ", *p);
p++;
}
printf("\n");
}
栈的销毁
//栈的销毁
SElemType DestroyStack(SqStack& s)
{
free(s.base);
s.base = NULL;
s.top = NULL;
s.stacksize = 0;
return 1;
}
完整代码
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef int SElemType;
//顺序栈的存储结构
typedef struct
{
SElemType* base;
SElemType* top;
int stacksize; //可用最大容量
}SqStack;
//初始化
void InitStack(SqStack& S)
{
S.base = new SElemType[MAXSIZE];
if (!S.base) exit;
S.top = S.base;
S.stacksize = MAXSIZE;
}
//入栈
int Push(SqStack& S, SElemType e)
{
if (S.top - S.base == S.stacksize) return 0; //栈满
*S.top = e;
S.top++;
return 1;
}
//出栈
int Pop(SqStack& S, SElemType& e)
{
if (S.top == S.base) return 0; //栈空
S.top--;
e = *S.top;
return 1;
}
//取栈顶元素
SElemType GetTop(SqStack S)
{
if (S.top != S.base) //非栈空时返回
return *(S.top - 1); //++会改变指针自身值,而-1不会改变
}
//遍历输出栈
void printStack(SqStack S)
{
printf("base:");
SElemType* p = S.base;
while (p != S.top)
{
printf("%d ", *p);
p++;
}
printf("\n");
}
int main()
{
SqStack S;
int e;
InitStack(S);
printf("Please input a number to push(-1 end):");
scanf("%d", &e);
while (e != -1)
{
Push(S, e);
printf("Please input a number to push(-1 end):");
scanf("%d", &e);
}
printStack(S);
printf("pop test:");
Pop(S, e);
printStack(S);
printf("GetTop test:");
e = GetTop(S);
printf("The top number is:%d\n", e);
}
运行结果:
栈的应用
进制转换
核心思想:
每次将N对a的余数进栈,再将N/a,最后依次出栈
#include<stdio.h>
#include<malloc.h>
#define STACKsize 100
#define STACKIN 10
#define OK 1
#define over -2
typedef int SDatatype;
typedef int status;
typedef struct{
SDatatype *base;
SDatatype *top;
int stacksize;
}sqstack;
//初始化顺序栈
status Inistack(sqstack &s){
s.base = (SDatatype *)malloc(STACKsize*sizeof(SDatatype));
if(!s.base){
return over;
}
s.top = s.base;
s.stacksize = STACKsize;
return OK;
}
//入栈
status push(sqstack &s,SDatatype e){
SDatatype *p;
//判断是否满栈
if(s.top-s.base == s.stacksize){
p = (SDatatype *)realloc(s.base,(STACKsize+STACKIN)*sizeof(SDatatype));
if(!p){
return over;
}
s.base = p;//系统会将原来的栈复制过来
s.top = s.base+s.stacksize;//使top指向新的栈顶
s.stacksize += STACKIN;
}
*(s.top)++ = e;//入栈
return OK;
}
//出栈
status pop(sqstack &s,SDatatype &e){
//判断是否发生下溢
if(s.top != s.base){
e = *--s.top; //先将栈顶减1
}
else return 0;
return e;
}
//判断是否为空栈
bool stacknull(sqstack &s){
if(s.top == s.base){
return true;
}
else return false;
}
void conversion(){
sqstack s;
int e,N;
Inistack(s);
printf("请输入一个十进制数:\n");
scanf("%d",&N);
printf("请输入想转换的进制:\n");
int a;
scanf("%d",&a);
while(N){
push(s,N%a);
N /= a;
}
printf("转换后是:\n");
while(!stacknull(s)){
pop(s,e);
printf("%d",e);
}
}
main(){
conversion();
}
括号匹配
核心思想:
遇到做左括号就进栈,遇到右括号就判断栈顶的左括号是否匹配,匹配就出栈,最后如果括号是匹配的,栈就一定是空的,只要判断栈是否为空,就可以真的括号是否匹配了。
#include <stdlib.h>
#include "stdio.h"
#include "malloc.h"
#define OK 1
#define OVERFLOW -1
#define ERROR 0
#define STACK_INI_SIZE 100
#define STACKINCREMENT 10
typedef char ElemType;
typedef int Status;
typedef struct{
ElemType *base;
ElemType * top;
int stacksize;
}SqStack;
Status InitStack(SqStack *S){
// 构造一个空顺序栈 S
S->base = (ElemType *)malloc(STACK_INI_SIZE* sizeof (ElemType));
if (!S->base) exit (OVERFLOW); //存储分配失败
S->top = S->base;
S->stacksize = STACK_INI_SIZE ;
return OK;
}
Status StackEmpty(SqStack S){
if(S.top==S.base) return OK;
else return ERROR;
}
Status Push(SqStack *S,ElemType e){
if ((*S).top - (*S).base >= (*S).stacksize){ //栈满,追加存储空间
(*S).base = (ElemType *)realloc((*S).base ,
(STACK_INI_SIZE+STACKINCREMENT)* sizeof (ElemType));
if(!S->base) exit(OVERFLOW); //存储分配失败
(*S).top=(*S).base+(*S).stacksize;
(*S).stacksize+=STACKINCREMENT;}
*S->top++ = e;
return OK;
}
Status Pop(SqStack *S,ElemType *e){
// 若栈不空,则删除S的栈顶元素,
// 用 e 返回其值,并返回OK;否则返回ERROR
if (S->top == S->base) return ERROR;//栈空
*e = *--S->top;
return OK;
}
Status GetTop(SqStack S,ElemType *e){
//若栈顶不空,则用e返回S的栈顶元素,并返回ok;
//否则,返回ERROR
if(S.top==S.base) return ERROR;
*e= *(S.top-1);
return OK;
}
int DisplayStack(SqStack S){
if(S.base==NULL){
printf("栈已销毁!\n");
}
int len=S.top-S.base;
if(len<=0){
printf("栈为空!\n");
}
int k;
for(k=0;k<=len;k++)
printf("%c - ",S.base[k]);
printf("%c\n",S.base[k]);
return OK;
}
Status Brackets_Test(char *str){//判别表达式中三种括号是否匹配
SqStack s;
char c,*p;
InitStack(&s);
for(p=str; *p; p++){
if(*p=='('||*p=='['||*p=='{') Push(&s,*p);
else if(*p==')'||*p==']'||*p=='}') {
if(StackEmpty(s)) { printf("it is error!\n");return ERROR; }
Pop(&s,&c);
if(*p==')'&&c!='(') {printf("it is error!\n"); return ERROR;}
if(*p==']'&&c!='[') {printf("it is error!\n"); return ERROR; }
if(*p=='}'&&c!='{') {printf("it is error!\n"); return ERROR; }//必须与当前栈顶括号匹配
}
}
if(!StackEmpty(s)) {printf("it is error!\n");return ERROR; }
printf("it is ok!\n");
return OK;
}
main (){
char ch[50];
printf("栈已销毁!\n");
gets(ch);
Brackets_Test(ch);
}