美文网首页
第4章(1) 栈

第4章(1) 栈

作者: cb_guo | 来源:发表于2019-03-07 11:41 被阅读0次

    栈 是限定仅在表尾进行插入和删除操作的线性表

    1、栈 (stack)

    • 很多类似软件,比如 Word、Photoshop 等文档或图像编辑软件中,都有撤销操作,其实就是用栈这种方式来实现的
    • 我们把允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。
    • 栈又称为后进先出 (Last In First Out) 的线性表,简称 LIFO 结构
      栈的插入操作: 叫做进栈,也称压栈、入栈
      栈的删除操作: 叫做出栈,也有的叫做弹栈

    1.1、栈的抽象数据类型

    1.2、栈的顺序存储结构及实现

    • 栈的顺序存储结构用数组来实现,下标为 0 的一端作为栈底
    • 若存储栈的长度为StackSize,则栈顶位置 top 必须小于 StackSize
    • 当栈存在一个元素时,top 等于 0,因此通常把空栈的判定条件定为 top 等于 -1
    • 栈的结构定义
    typedef int Status; 
    typedef int SElemType;   /* SElemType类型根据实际情况而定,这里假设为int */
    
    /* 顺序栈结构 */
    typedef struct
    {
          SElemType data[MAXSIZE];
          int top;         /* 用于栈顶指针 */
    }SqStack;
    

    1.2.1、进栈操作

    /* 插入元素e为新的栈顶元素 */
    Status Push(SqStack *S,SElemType e)
    {
            if(S->top == MAXSIZE -1) /* 栈满 */
            {
                    return ERROR;
            }
            S->top++;               /* 栈顶指针增加一 */
            S->data[S->top]=e;      /* 将新插入元素赋值给栈顶空间 */
            return OK;
    }
    

    1.2.2、出栈操作

    /* 若栈不空,则删除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;
    }
    
    • 栈的顺序存储结构不涉及任何循环语句,因此时间复杂度均为O(1)

    1.3、栈的链式存储结构及实现

    • 栈只有栈顶来做插入和删除操作,栈顶放在链表的头部还是尾部呢? 头部
    • 对于链栈来说,基本不存在栈满的情况,除非内存已经没有可以使用的空间
    • 对于空栈来说,链表原定义是头指针指向空,那么链栈的空其实就是 top=NULL 的时候
    • 链栈的结构代码如下
    /* 链栈结构 */
    typedef struct StackNode
    {
            SElemType data;
            struct StackNode *next;
    }StackNode,*LinkStackPtr;
    
    
    typedef struct
    {
            LinkStackPtr top;
            int count;
    }LinkStack;
    

    1.3.1、进栈操作

    /* 插入元素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;
    }
    

    1.3.2、出栈操作

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

    1.3.3、小结

    • 链栈的进栈 push 和出栈 pop 操作都很简单,没有任何循环操作,时间复杂度均为 O(1)
    • 对比一下顺序栈和链栈,它们在时间复杂度上是一样的,均为 O(1)
    • 对于空间性能,顺序栈需要事先确定一个固定的长度,可能会存在内存空间浪费的问题,但它的优势是存取时定位很方便;而链栈则要求每个元素都有指针域,这同时也增加了一些内存开销,但对于栈的长度无限制
    • 如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是使用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些

    相关文章

      网友评论

          本文标题:第4章(1) 栈

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