栈的顺序存储结构

4.1 栈的顺序存储结构

4.1.1 栈的简介

栈是一种只允许在一端进行插入或者删除的线性表,形象一点,我们大家都知道手枪弹夹吧,类似下图这种:

在这里插入图片描述

这里面子弹都是一发发装进去的,就像栈的插入,只从一端,当射击时,后面装的子弹先射击出去,就像栈的出栈。栈这个词听起来可能挺玄乎的,但是他其实就好比手枪弹夹这种结构,是一种"后进先出"(Last In First Out,LIFO)的操作方式。




4.1.2 栈的顺序结构定义

一个栈我们需要存数据还要有一个能指示栈顶的指针,我们就用data[]数组存放数据,top用于指向栈顶元素。代码如下:

/*定义栈类型*/
typedef struct{
    SElemType data[MAXSIZE];
    int top;        //栈顶指针
}SqStack;

同时,栈空的时候我们使top=-1,栈满时top=MAXSIZE-1

以下是栈的示意图:
在这里插入图片描述

现在我们有栈这个结构了,我们该想想有哪些操作了,例如删除,插入,清除之类的,下面是会涉及到操作函数的表格:

操作函数操作结果
InitStack(SqStack *S)初始化栈
ClearStack(SqStack *S)清空栈
StackEmpty(SqStack S)判断栈是否为空
GetTop(SqStack S,SElemType *e)获取栈顶元素,用e返回
Push(SqStack *S,SElemType e)进栈
Pop(SqStack *S,SElemType *e)出栈,并将数据存入e
StackLength(SqStack S)返回栈长度
StackTraverse(SqStack S)遍历并且打印栈

4.1.3 入栈和出栈


入栈

入栈就像将子弹一颗颗装入弹夹中,图解如下:

在这里插入图片描述

  • 首先要判断栈是否满,即S->top=MAXSIZE-1为栈满,不可入栈
  • 然后先将栈顶指针top移动一位到空位置,即S->top++
  • 最后利用栈顶指针来为空位置赋值S->data[S->top]=e

代码实现:

/*进栈,将新元素e放入栈顶*/
Status Push(SqStack *S,SElemType e){
    if(S->top==MAXSIZE-1)       //栈满
        return ERROR;
    
    S->top++;                //将栈顶移到空的位置
    S->data[S->top] = e;    //插入元素e到栈顶
}


出栈

出栈就像子弹发射出去,后进的先出,图解如下:
在这里插入图片描述

  • 首先判断栈是否为空,即S->top=-1时栈空,不可出栈。
  • 再将要删除的栈顶元素数据赋值给指针e
  • 最后将栈顶指针向栈底移动一位。

代码实现:

/*出栈,将出去的元素存入e*/
Status Pop(SqStack *S,SElemType *e){
    //判断栈是否为空
    if(S->top == -1)
        return ERROR;
    *e = S->data[S->top];   //将栈顶元素存入e
    S->top--;               //栈顶指针top减1
    return OK;
}




4.1.3 获得栈顶元素

根据栈的结构,我们可以很轻易得知,获得栈顶元素,只要根据栈顶指针去获得就可以了,下面给出代码:

/*若栈存在且非空,用e返回栈顶元素*/
Status GetTop(SqStack S,SElemType *e){
    if(S.top == -1){
        return ERROR;
    }else{
        *e = S.data[S.top];
    }
    return OK;
}

千万要注意首先判断栈是否非空。




4.1.4 初始化栈和清空栈


初始化栈

初始化栈,实现这个功能非常容易,只要让栈顶指针指向-1即可,S->top=-1,表示建立了一个空栈。

代码实现:

/*初始化栈*/
Status InitStack(SqStack *S){
    S->top = -1;
    return OK;
}


清空栈

清空栈在栈的顺序结构中和初始化栈一样。

代码实现:

/*清空栈*/
Status ClearStack(SqStack *S){
    S->top = -1;
    return OK;
}




4.1.5 其他剩余操作

剩余的操作都很好理解,附上代码~

获取栈长度

/*返回栈长度*/
int StackLength(SqStack S){
    return S.top+1;		//栈顶+1就是栈长度
}


判断栈是否为空

/*判断栈是否为空*/
Status StackEmpty(SqStack S){
    if(S.top==-1)
        return True;
    else
        return False;
}


遍历并打印栈

/*打印栈*/
Status visit(SElemType c){
    printf("%d ",c);
    return OK;
}

Status StackTraverse(SqStack S){
    int i = 0;
    while(i<=S.top){
        visit(S.data[i]);
        i++;
    }
}




4.1.6 测试

测试代码:

int main(){
    int j;
    SqStack s;
    int e;
    if(InitStack(&s)==OK)
            for(j=1;j<=10;j++)
                    Push(&s,j);
    printf("栈中元素依次为:");
    StackTraverse(s);
    Pop(&s,&e);
    printf("弹出的栈顶元素 e=%d\n",e);
    printf("栈空否:%d(1:空 0:否)\n",StackEmpty(s));
    GetTop(s,&e);
    printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
    ClearStack(&s);
    printf("清空栈后,栈空否:%d(1:空 0:否)\n",StackEmpty(s));
    
    system("pause");
    return 0;
}

运行结果:

栈中元素依次为:1 2 3 4 5 6 7 8 9 10 弹出的栈顶元素 e=10
栈空否:0(1:空 0:否)
栈顶元素 e=9 栈的长度为9
清空栈后,栈空否:1(1:空 0:否)
请按任意键继续. . .




4.1.7 完整代码

下面附上完整代码:

#include<stdio.h>
#include<stdlib.h>

#define OK 1
#define ERROR 0

#define True 1
#define False 0
#define MAXSIZE 20

typedef int SElemType;
typedef int Status;

/*定义栈类型*/
typedef struct{
    SElemType data[MAXSIZE];
    int top;        //栈顶指针
}SqStack;

/*初始化栈*/
Status InitStack(SqStack *S){
    S->top = -1;
    return OK;
}

/*清空栈*/
Status ClearStack(SqStack *S){
    S->top = -1;
    return OK;
}

/*判断栈是否为空*/
Status StackEmpty(SqStack S){
    if(S.top==-1)
        return True;
    else
        return False;
}

/*若栈存在且非空,用e返回栈顶元素*/
Status GetTop(SqStack S,SElemType *e){
    if(S.top == -1){
        return ERROR;
    }else{
        *e = S.data[S.top];
    }
    return OK;
}

/*进栈,将新元素e放入栈顶*/
Status Push(SqStack *S,SElemType e){
    if(S->top==MAXSIZE-1)       //栈满
        return ERROR;
    
    S->top++;                //将栈顶移到空的位置
    S->data[S->top] = e;    //插入元素e到栈顶
}

/*出栈,将出去的元素存入e*/
Status Pop(SqStack *S,SElemType *e){
    //判断栈是否为空
    if(S->top == -1)
        return ERROR;
    *e = S->data[S->top];   //将栈顶元素存入e
    S->top--;               //栈顶指针top减1
    return OK;
}

/*返回栈长度*/
int StackLength(SqStack S){
    return S.top+1;
}

/*打印栈*/
Status visit(SElemType c){
    printf("%d ",c);
    return OK;
}

Status StackTraverse(SqStack S){
    int i = 0;
    while(i<=S.top){
        visit(S.data[i]);
        i++;
    }
}

int main(){
    int j;
    SqStack s;
    int e;
    if(InitStack(&s)==OK)
            for(j=1;j<=10;j++)
                    Push(&s,j);
    printf("栈中元素依次为:");
    StackTraverse(s);
    Pop(&s,&e);
    printf("弹出的栈顶元素 e=%d\n",e);
    printf("栈空否:%d(1:空 0:否)\n",StackEmpty(s));
    GetTop(s,&e);
    printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
    ClearStack(&s);
    printf("清空栈后,栈空否:%d(1:空 0:否)\n",StackEmpty(s));
    
    system("pause");
    return 0;
}

4.1.8 栈顺序结构的优缺点


优点:

  1. 实现简单,存储结构紧凑,空间利用率高;
  2. 访问元素快速,时间复杂度为O(1),无需遍历;
  3. 可以使用下标随机访问栈中的元素,方便实现一些操作,如查找指定元素、修改栈中的元素等;
  4. 操作系统通常会为每个线程分配一个栈,用于保存线程的状态和局部变量。在栈顺序结构中,可以通过指定栈的大小来限制函数调用的嵌套深度,防止栈溢出。

缺点:

  1. 栈顺序结构的大小是固定的,一旦初始化后就无法动态调整大小,可能会浪费内存或导致栈溢出;
  2. 在入栈和出栈操作时,需要移动元素,时间复杂度为O(n),当栈中元素较多时,效率会降低;
  3. 栈的容量可能会受到操作系统的限制,当栈的大小超过操作系统限制时,会导致栈溢出;
  4. 如果栈中的元素是复杂类型,需要进行深拷贝,可能会消耗较多的时间和内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

压力小子呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值