数据结构与算法 | 3.线性结构——堆栈

博客内容为 浙江大学:陈越姥姥 的教学视频笔记

数据结构与算法

1.什么是堆栈

  • 堆栈:具有一定操作约束的线性表(只在一端做插入、删除)
    • 插入数据:入栈(Push)
    • 删除数据:出栈(Pop)
    • 先入后出:Last In First Out(LIFO)

2.堆栈的抽象数据类型描述

  • (1)堆栈的抽象数据类型描述

    类型名称:堆栈(Stack)
    
    数据对象集:一个有0个或多个元素的有穷线性表。
    
    操作集:长度为MaxSize的堆栈S,堆栈元素item
    1.Stack CreateStack(int MaxSize):生成堆栈,其最大长度为MaxSize;
    2.int IsFull(Stack S, int MaxSize):判断堆栈S是否已满;
    3.void Push(Stack S, ElementType item):将元素item压入堆栈;
    4.int IsEmpty(Stack S):判断堆栈S是否为空
    5.ElementType Pop(Stack S):删除并返回栈顶元素。
    
  • (2)Push和Pop可以交叉进行。

    • 问题:如果将三个字符ABC顺序压入堆栈,ABC的出栈所有可能。(可以产生CAB吗?)
      • A入A出 B入B出 C入C出 ABC
      • A入A出 B入C入 C出B出 ACB
      • A入B入 B出A出 C入C出 BAC
      • A入B入 B出C入 C出A出 BCA
      • A入B入 C入C出 B出A出 CBA
      • 不可能产生序列:CAB

3.栈的顺序存储实现

栈的顺序存储结构通常由一个一维数组和一个记录栈顶元素位置的变量组成。

  • 1)顺序栈的类型定义

    #define MaxSize <存储数据元素的最大个数>
    typrdef struct SNode *Stack
    struct SNode{
        ElementType Data[MaxSize];
        int Top;
    }
    
  • 2)入栈

    void Push(Stack PtrS, ElementType item){
        if(PtrS->Top == MaxSize - 1){
            printf("堆栈满");
            retuen;
        }else{
            PtrS->Data[++(PtrS->Top)] = item;
            return;
        }
    }
    
  • 3)出栈

    ElementType Pop(Stack PtrS){
        if(PtrS->Top == -1){
            printf("栈为空");
            return ERROR;
        }else{
            return (PtrS->Data[(PtrS->Top)--]);
        }
    }
    
  • 4)请用一个数组实现两个堆栈,要求最大地利用数组空间,使数组只要有空间入栈操作就可以成功。

    • 堆栈
    • 代码略

4.堆栈的链式存储实现

栈的链式存储结构实际上就是一个单链表,叫作链栈。插入和删除操作只能在链栈的栈顶进行。栈顶指针Top应该在链表的哪一头?
单向链表有头有尾,栈顶指针Top一定在链表的头上。(如果Top在链表的尾部,那么插入操作没问题,但出栈时,由于是单向,因此不知道前一个结点是多少,Top不能指向前一个结点。)

  • 1)链栈的类型定义

    typedef struct SNode *Stack;
    struct SNode{
        ElementType Data;
        struct SNode *Next;
    }
    
  • 2)创建堆栈

    Stack CreateStack(){
        Stack S;
        S = (Stack)malloc(sizeof(struct SNode));
        S->Next = NULL;
        return S;
    }
    
  • 3)判断堆栈是否为空

    int IsEmpty(Stack S){
        return (S->Next == NULL);
    }
    
  • 4)入栈

    void Push(ElementType item, Stack S){
        struct SNode *TmpCell;
        TmpCell = (struct SNode *)malloc(sizeof(struct SNode));
        TmpCell->Element = item;
        TmpCell->Next = S->Next;
        S->Next = TmpCell;
    }
    
  • 5)出栈

    ElementType Pop(Stack S){
        struct SNode *FirstCell;
        ElementType TopElem;
        if(IsEmpty(S)){
            printf("栈为空");
            return;
        }else{
            FirstCell = S->Next;
            S-Next = FirstCell;
            TopElem = FirstCell->Element;
            free(FirstCell);
            return TopElem;
        }
    }
    

5.堆栈应用:表达式求值

中缀表达式:运算符位于两个运算数之间。如:a + b * c - d / e
后缀表达式:运算符位于两个运算数之后。如:a b c * + d e / -
可以看出来的是,只是运算符的位置变了,运算数的相对位置是没有变化的。

(1)中缀表达式转换为后缀表达式

  • 从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理。
    • 运算数:直接输出
    • 左括号:压入堆栈
    • 右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)。
    • 运算符:
      • 优先级大于栈顶运算符时,则把它压栈;
      • 优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈。
    • 若各对象处理完毕,则把堆栈中存留的运算符一并输出。
  • 示例:
    • 后缀运算符

(2)后缀表达式求值

  • 遇到数字,存入堆栈。
  • 遇到运算符,从堆栈中取出两个数字进行运算,并把运算结果压入堆栈。
  • 直到遍历完成输出结果。
    • 后缀表达式求值

6.堆栈的其他应用

  • 函数调用及递归实现
  • 深度优先搜索
  • 回溯算法
  • ...

posted on 2020-09-05 20:00  wangxx06  阅读(323)  评论(0)    收藏  举报

导航