数据结构第二周笔记(4)——线性结构(慕课浙大版本--XiaoYu)

226 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

2.2.3 堆栈的链式存储实现

栈的链式存储结构实际上就是一个单链表,叫做链栈。插入和删除操作只能再链栈的栈顶进行。
栈顶指针Top应该再链表的哪一头?若用单向链表实现一个堆栈,链表的头和尾都可以作为top?
只有链表的头才行。链表的尾空余插入,但是删除就有问题,找不到前面的结点了,因为这是单项链表找不到前面的结点
    
    typedef struct SNode*Stack;
    struct SNode{
        ElementType Data;
        struct SNode*Next;
    };

image-20220628045906099

Stack CreateStack()
{//构建一个堆栈的头结点,返回指针
    Stack S;
    S = (Stack)malloc(sizeof(struct SNode));
    s->Next = NULL;
    return S;
}
​
int IsEmpty(Stack S)
{
    //判断堆栈s是否为空,若为空函数返回整数1,否则返回0
    return (S->Next == NULL);
}

image-20220628050006254

void Push(ElementType item,Stack S)
{
    //将元素item压入堆栈S
    struct SNode *TmpCell;
    TmpCell = (struct SNode *)malloc(sizeof(struct SNode));
    TmpCell -> Element = item;
    TmpCell -> Next = S -> Next;
    S -> Next = TmpCell;
}

使用链表来进行Push操作的时候不用判别堆栈满不满的问题,因为链表通过不断申请结点空间往里面插

数组实现堆栈的话,数组大小是固定的,存在着满不满的问题

image-20220628050745839

ElementType Pop(Stack S)
{
    //删除并返回堆栈s的栈顶元素
    struct SNode *FirstCell;
    ElementType TopElem;
    if( IsEmpty (S) ){
        printf("堆栈空");return NULL;
    }else{
        FirstCell = S ->Next;
        TopElem = FirstCell -> Element;
        free(FirstCell);
        return TopElem;
    }
}

2.2.4 堆栈应用:表达式求值

回忆:应用堆栈实现后缀表达式求值的基本过程:

  1. 从左到右读入后缀表达式的各项(运算符或运算数);
1.运算数:入栈;
2.运算符:从堆栈中弹出适当数量的运算数,计算并结果入栈;
3.最后,堆栈顶上的元素就是表达式的结果值

中缀表达式求值

基本策略:将中缀表达式转化为后缀表达式,然后求值
如何将中缀表达式转化为后缀?
观察一个简单例子:2+9/3-5  ->  2 9 3 / + 5 -
1.运算数相对顺序不变
2.运算符号顺序发生改变
    1.需要存储"等待中"的运算符号
    2.要将当前运算符号与"等待中"的最后一个运算符号比较(如果前面的一个运算符号的优先级比我来得高,就说明可以拿来计算,如果优先度比我低,那么当前的运算符号还不能说就直接拿来运算,因为后面可能还有优先级比我高的,所以需要保留起来,这个时候我们就需要一种结构来实现我们运算符号的存储,那结构就是堆栈)
        输出:2 9 3
        记下:+ /
        碰到运算数 我们就把它输出
        碰到运算符号 我们等着
        
有括号怎么办?
【例】a*(b+c)/d = ?        a b c + * d /
当括号被丢进堆栈里面的时候,它的优先级降到最低,优先算括号里的内容
算数规则:当遇到同一个优先级的时候,它的顺序是从左到右
​
T(N) = O(N)

image-20220628210030460

请试试应用堆栈将中缀表达式2*(6/3+4)-5转换为后缀表达式。在这个转换过程中,堆栈元素最多时元素个数是多少?3个

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

image-20220628215153143

堆栈的其他应用:
函数的调用及递归实现
深度优先搜索(图)
回溯算法(老鼠走迷宫案例)等等