【数据结构】栈的操作

简介: 【数据结构】栈的操作


定义:栈是限定仅在表尾进行插入或删除操作的线性表。


由于栈只有一边开口存取数据,称开口的那一端为“栈顶”,封死的那一端为“栈底”(类似于盛水的木桶,从哪进去的最后还得从哪出来)。


栈操作数据元素的方法


栈操作数据元素只有两种动作

入栈:在栈顶插入一个元素的操作;

出栈:从栈顶删除一个元素的操作;


栈的“先进后出”原则(Last In First Out)


使用栈存储数据元素,对数据元素的“存”和“取”有严格的规定:数据按一定的顺序存储到栈中,当需要调取栈中某数据元素时,需要将在该数据元素之后进栈的先出栈,该数据元素才能从栈中提取出来。


eada04a96e450afd4e21f92355884ba6_f1374ee760988a25573859d7c78f31cf.png


如图 1 ,栈中存放了 4 个数据元素,进栈的顺序是 A 先进栈,然后 B 进,然后 C 进,最后 D 进栈;当需要调取 A 时,首先 D 出栈,然后 C 出栈,然后 B 出栈,最后 A 才能出栈被调用。


就好比只有一个门的车库(每次仅允许一辆车通过),每辆车好比一个数据元素,只有离门最近的车先开出来,里边的车才能出来;最里边的车是最先开进去的,注定要最后出来。


栈的表示和实现


既然栈也是线性表,那么它就同样有线性表的两种表示形式:顺序栈 和 链式栈(简称“链栈”)。


栈的顺序存储结构(顺序栈)


顺序栈:是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。

#define MAXSIZE 100    /*  栈的最大容量 */
typedef int ElemType;     /*元素类型*/
/* 顺序栈 */
typedef struct{ 
  SElemType data[MAXSIZE];
  int top; //栈顶指针 ,约定指向栈顶元素的下一个位置
} SqStack;


顺序栈的算法实现


初始化空栈


约定:非空栈的栈顶指针top始终指向栈顶元素的下一个位置.

void initSqStack(SqStack *s)
{
  s->top= 0;
}


### 判断栈空

bool isEmptyStack(SqStack s)
{
  if (s.top==0)             //栈顶指针应该指向栈顶元素的下一个位置,否则栈空。
  return true;
  else
  return false;
}


入栈


bool push(SqStack s,SElemType e) / s指向栈的指针变量,指针作为参数,可以将变化后的栈的值传递出来 /
{
  if (s->top >=MAXSIZE)
    return false;
  else
 {
  s->data[s->top]=e; //先插入,
  s->top ++; //栈顶指针后加1
  //相当于 s->data[s->top++]
    return true;
 }
}


出栈


bool pop(SqStack *s,SElemType *e) /* 指针作为参数,可将修改后的值传递出来 */
{
  if (s->top ==0)
        return false ;
  else
  {
       --s->top;            //栈顶指针先减1
     *e=s->data[s->top];  //再读取删除元素
       //*e=s->data[--s->top ];   //等价
      return  true;
  }
}


读栈顶


SElemType getTop(SqStack s)
{
  SElemType e;
  if (s.top ==0)
        return false ;
  else
  {
      e=s.data[s.top-1];
      return e;
  }
}


注意:上面的顺序栈是静态栈,空间一旦定下就难改而且一旦没有一段连续的内存,就会申请失败那么,就出现了动态顺序存储栈,代码附下:


点击查看代码

#include <stdio.h>
#include <stdlib.h>
#define TURE 1
#define FALSE 0
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
typedef int SelemType;
/*---动态分配栈--*/
typedef struct
{
    SelemType *base;
    SelemType *top;
    int StackSize;
} SeqStack;
/*---初始化---*/
int InitStack(SeqStack *s)
{
    s->base = (SeqStack *)malloc(STACK_INIT_SIZE*sizeof(SeqStack));
    if(!s->base)
        printf("创建失败");
    else
    {
        s->top = s->base;
        s->StackSize = STACK_INIT_SIZE;
    }
}
/*---判断栈是否为空---*/
int IsEmpty(SeqStack *s)
{
    if(s->top==s->base)
    {
        return TURE;
    }
    else
    {
        return FALSE;
    }
}
/*---入栈操作---*/
int push(SeqStack *s,SelemType x)
{
    if((s->base)-(s->base)==s->StackSize)
    {
        s->base = (SeqStack *)realloc(s->base,(s->StackSize+STACKINCREMENT)*sizeof(SeqStack));
        if(s->base==NULL)
        {
            return FALSE;
        }
        s->top  =s->base+s->StackSize;
        s->StackSize +=STACKINCREMENT;
    }
    else
    {
        *s->top = x;
        s->top++;
        return(TURE);
    }
}
/*---出栈操作---*/
int Pop(SeqStack *s,SelemType *x)
{
    if(s->top==s->base)
    {
        return FALSE;
    }
    else
    {
        s->top--;
        *x = *s->top;
        return (TURE);
    }
}


链式存储结构(链式栈)


链栈,用线性表的链式存储结构实现。

用链表表示栈时,用链表头结点的一端作为栈的栈顶端,这样做的好处是当数据元素压栈或者弹栈时,直接使用头指针就可以完成,不需要增设额外的指针。

756255da5412992dad81f04a7e636952_6fd6928510da6d106f0cdc51d5aca223.png

typedef Struct SNode{
    ElemType  data;
    Struct   SNode   * next;
 } SNode;


栈的应用举例


数制的转换(以8进制为例)


f682946f20ee4539a139bc07194f5c14_48d6901258d75b72b0b9ce1c4e72afd6.png

void conversion(int n)
{
   SqStack s;
   ElemType e;
   bool tmp;
   initSqStack(&s);
   while(n)
  {
     tmp=push(&s,n%8);   /* 求余数压栈 */
     n=n/8;
   }
   while(!isEmptyStack (s))
   {
       tmp=pop(&s,&e);
       printf("%3d",e);
   }
   printf("\n");
}


算术表达式求值


一个表达式由操作数、运算符界限符组成。


89786a3e9c601283a53ca6af6e442351_8ddcaa89645a534e62f2d86dcd044dd6.png

9a7bcfe6ffa9da92cded440e559ea435_7fa030cdb5b4f17c843ed689f3d79d6c.png

c120dfd3d2fb6572bd4b5f0c3016b28b_30e8279de5dc17e207943dc6a6232d33.png

伪代码:

OprandType EvaluateExpression( ){
    InitStack(OPTR); PUSH(OPTR,’#’);
    InitStack(OPND); c=getchar();
    While(c!=‘#’||GetTop(OPTR)!=‘#’){
        If(!In(c,op)) {PUSH(OPND,c);c=getchar();}    //In(c,op)       C是运算符吗?
        Else
           switch(Precede(GetTop(OPTR) ,  c )){
              case ‘<’   PUSH(OPTR,c);c=getchar();break;
              case ‘=’   POP(OPTR,x);c=getchar();break;
              case ‘>’   POP(OPTR,theta); 
                         POP(OPND,b); POP(OPND,a);              
                         PUSH(OPND,operate(a,theta,b));
                         break;
          }//switch
     }//while
}//EvaluateExpression


括号的匹配问题(具体在博客另一篇随笔)


引用《深入浅出数据结构与算法》————清华出版社



相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
191 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
32 1
|
25天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
46 5
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
1月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
51 4
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
48 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
48 0
|
2月前
初步认识栈和队列
初步认识栈和队列
65 10