美文网首页
数据结构与算法-栈

数据结构与算法-栈

作者: 打南边来了个辣妈 | 来源:发表于2020-04-11 11:40 被阅读0次

问题引入

当在浏览器页面打开页面 a-b-c 之后,点击浏览器的后退按钮,就可以查看之前浏览过的页面 b 和 a。当你后退到页面 a,点击前进按钮,就可以重新查看页面 b 和 c。但是,如果你后退到页面 b 后,点击了新的页面 d,那就无法再通过前进、后退功能查看页面 c 了。

当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出、先进后出的特性,我们就应该首选“栈”这种数据结构。
以上的场景就可以用\color{#FF0000}{栈}这种数据结构来实现。

代码实现

栈主要包含两个操作,入栈和出栈,也就是在栈顶插入一个数据和从栈顶删除一个数据。
栈既可以用数组来实现,也可以用链表来实现。用数组实现的栈,我们叫作顺序栈,用链表实现的栈,我们叫作链式栈

进栈与出栈

1. 顺序栈

typedef int Status;
typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */

/* 顺序栈结构 */
typedef struct
{
    SElemType data[MAXSIZE];
    int top; /* 用于栈顶指针 */
}SqStack;
/*  构造一个空栈S */
Status InitStack(SqStack *S)
{
    /* S.data=(SElemType *)malloc(MAXSIZE*sizeof(SElemType)); */
    S->top=-1;
    return OK;
}
/* 插入元素e为新的栈顶元素 */
Status Push(SqStack *S,SElemType e)
{
    if(S->top == MAXSIZE -1) /* 栈满 */
    {
        return ERROR;
    }
    S->top++;                /* 栈顶指针增加一 */
    S->data[S->top]=e;  /* 将新插入元素赋值给栈顶空间 */
    return OK;
}

/* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
Status Pop(SqStack *S,SElemType *e)
{
    if(S->top==-1)
        return ERROR;
    *e=S->data[S->top];    /* 将要删除的栈顶元素赋值给e */
    S->top--;                /* 栈顶指针减一 */
    return OK;
}

2. 链式栈

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;
typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */

/* 链栈结构 */
typedef struct StackNode
{
   SElemType data;
   struct StackNode *next;
}StackNode,*LinkStackPtr;

typedef struct
{
   LinkStackPtr top;
   int count;
}LinkStack;

/*  构造一个空栈S */
Status InitStack(LinkStack *S)
{
   S->top = (LinkStackPtr)malloc(sizeof(StackNode));
   if(!S->top)
       return ERROR;
   S->top=NULL;
   S->count=0;
   return OK;
}

/* 插入元素e为新的栈顶元素 */
Status Push(LinkStack *S,SElemType e)
{
   LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode));
   s->data=e;
   s->next=S->top;    /* 把当前的栈顶元素赋值给新结点的直接后继,见图中① */
   S->top=s;         /* 将新的结点s赋值给栈顶指针,见图中② */
   S->count++;
   return OK;
}

/* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
Status Pop(LinkStack *S,SElemType *e)
{
   LinkStackPtr p;
   if(StackEmpty(*S))
       return ERROR;
   *e=S->top->data;
   p=S->top;                    /* 将栈顶结点赋值给p,见图中③ */
   S->top=S->top->next;    /* 使得栈顶指针下移一位,指向后一结点,见图中④ */
   free(p);                    /* 释放结点p */
   S->count--;
   return OK;
}

空间复杂度:
不管是顺序栈还是链式栈,我们存储数据只需要一个大小为 n 的数组就够了。在入栈和出栈过程中,只需要一两个临时变量存储空间,所以空间复杂度[1]是 O(1)。
时间复杂度:
时间复杂度也同样,不管是顺序栈还是链式栈,入栈、出栈只涉及栈顶个别数据的操作,所以时间复杂度都是 O(1)。

[1]:这里存储数据需要一个大小为 n 的数组,并不是说空间复杂度就是 O(n)。因为,这 n 个空间是必须的,无法省掉。所以我们说空间复杂度的时候,是指除了原本的数据存储空间外,算法运行还需要额外的存储空间

应用场景

  • 函数调用栈
  • 表达式求知
  • 括号匹配

源码

本文完整源码地址

参考文献

相关文章

网友评论

      本文标题:数据结构与算法-栈

      本文链接:https://www.haomeiwen.com/subject/hdtymhtx.html