160 阅读5分钟

栈的定义

栈是限定仅在表尾进行插入和删除操作的线性表。
1、允许插入和删除的一端称为栈顶。
2、另一端称为栈底。
3、不包含任何数据元素的栈称为空栈。
4、栈又称为先进先出,简称LIFO结构。
5、栈是一种特殊的线性关系。
6、栈底是固定的,最先进栈的只能在栈底。
7、栈的插入操作,叫做进栈,也称为压栈、入栈。
8、栈的删除操作,叫做出栈、也有叫做弹栈。

图片.png

栈的抽象数据类型

ADT 栈(stack)
Data
    同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
    InitStack(*S):初始化操作,建立一个空栈S。
    DestroyStack(*S):若栈存在,则销毁它。
    ClearStack(*S):将栈清空。
    StackEmpty(S):若栈为空,返回true,否则返回false。
    GetTop(S,*e):若栈存在且非空,用e返回S的栈顶元素。
    Push(*S,e):若栈S存在,插入新元素e到栈S中并成为栈顶元素。
    Pop(*S,*e):删除栈S中栈顶元素,并用e返回其值。
    StackLength(S):返回栈S的元素个数。
EndADT        

栈的顺序存储结构及实现

栈的顺序存储结构

栈的结构定义

typedef int SELemType;//SELemType类型根据实际情况而定,这里假设为int
typedef struct
{
    SELemType data[MAXSIZE];
    int top;//用于栈顶指针
}SqStack

若现在有一个栈,StackSize是5,则栈普通情况、空栈和栈满的情况示意图如图所示。

图片.png

栈的顺序存储结构-进栈操作

对于栈的插入,即进栈操作

图片.png

插入元素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--; // 栈顶指针减一
    retrun OK;
}

两栈共享空间结构

typedef struct
{
    SELemType data[MAXSIZE];
    int top1; //栈1 栈顶指针
    int top2; //栈2 栈顶指针
}SqDoubleStack;

对于两栈共享空间的push方法,除了要插入元素值参数外,还需要有一个判断是栈1还是栈2的栈号参数stackNumber。插入元素的代码如下:

插入元素e为新的栈顶元素
Status Push (SqDoubleStack *S, SELemType e, int stackNumber)
{
    if (S->top1+1 == S->top2) // 栈已满,不能再push新元素了
    {
        retrun ERROR;
    }
    if (stackNumber == 1) // 栈1 有元素进栈
    {
        S->data[++S->top1] = e;//若栈1 则先top+1后给数组元素赋值
    }
    else if (stackNumber == 2) //栈2 有元素进栈
    {
        S->data[--S->top2] = e;//若栈2 则先top2-1后给数组元素赋值
    }
    retrun OK;
}

若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR

Status Pop(SqDoubleStack *S, SELemType *e, int stackNumber)
{
    if (stackNumber == 1)
    {
        if(S->top1 == -1)
        {
            return ERROR;//说明栈1 以及是空栈,溢出
        }
        *e = S->data[S->top1--];//将栈1 的栈顶元素出栈
    }
    else if (stackNumber == 2)
    {
        if(S->top2 == MAXSIZE)
        {
            return ERROR;//说明栈2 已经是空栈,溢出
        }
        *e = S->data[S->top2++];//将栈2的栈顶元素出栈
    }
    return OK;
}

栈的链式存储结构及实现

栈的链式存储结构

1、栈的链式存储结构,简称为链栈。
2、把栈顶放在单链表的头部,单链表中比较常用的头结点也就失去意义了,通常对于链栈来说,是不需要头结点的。 3、对于链栈来说,基本不存在栈满的情况,处分内存已经没有可以使用的空间。
4、对于空栈来说,链表原定义是头指针指向空,那么链表的空其实就是top=NULL的时候。

链式的结构代码如下

Typedef struct StackNode
{
    SELemType data;
    struct StackNode *next;
}StackNode,*LinkStackPtr;

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

栈的链式存储结构---进栈操作

对于链栈的进栈push操作,假设元素值为e的新结点是s,top为栈顶指针,如图

图片.png

插入元素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++;
    retrun OK;
}

栈的链式存储结构---出栈操作

至于链栈的出栈Pop操作,也是很简单的三句操作。假设变量p用来存储要删除的栈顶结点,将栈顶指针下移一位,最后释放p即可。

图片.png

若栈不空,则删除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;
}

栈的作用

栈的引入简化了程序设计的问题,划分了不同关注层次,使得思考范围缩小,更加聚焦于我们要解决的问题核心。反之,像数组等,因为要分散精力去考虑数组的下标增减等细节问题,反而掩盖了问题的本质。