zoukankan      html  css  js  c++  java
  • 数据结构之堆栈

    因为找工作的原因,发现自己的数据结构和算法太薄弱了,被虐的很惨,遂下定决心开始从头学习数据结构和算法,就在MOOC上找了一门浙江大学开设的数据结构课程,也特地开了博客来记录一下此次学习之旅,也在这里定下一个目标,希望能够坚持到底,奥利给!!

    什么是堆栈

    首先从一个非常经典的算术表达式求解问题开始堆栈的学习。

    5 + 6 / 2 - 3 * 4

    如何求解上面的表达式?

    1、表达式由两类对象构成:运算数和运算符号

    2、不同的运算符号有不同的优先级

    一般,我们见到的算术表达式称为中缀表达式,因为运算符号位于两个运算数之间,如 a + b * c - d / e。

    为了方便计算机计算,我们一般将中缀表达式转换为后缀表达式:如a b c * + d e / -.

    如何将中缀表达式转换为后缀表达式

    需要借助堆栈来实现,按照我们计算表达式的流程,我们从左往右扫描表达式,并用堆栈来记录运算符号,当我们遇到一个运算符号小于先前记录的运算符序列的最后一个时(同优先级符号的从左往右优先级递减),这就表明我们应该事先运算前面的子表达式,所以将堆栈里的运算符弹出,直到在堆栈里遇到的运算符小于当前的预算符号。带括号的表达式中,左括号在堆栈外时,优先级为最高,当在堆栈里时,优先级最低。所以在扫描表达式时遇到左括号直接入入栈,遇到右括号后,开始弹出堆栈里的运算符,直到遇到左括号后,左括号弹出,因为括号优先级最低,所以此时运算符堆栈应该会出清。

    转换规则:

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

    这样,我们就完成了从中缀表达式到后缀表达式的转换,接下来,我们可以对该后缀表达式进行求值运算。

    后缀表达式的求值策略:

    1、首先我们知道,后缀表达式已经将预算符号的优先级和预算数进行了一定的排列,所以我们可以重做往右扫描,逐个处理运算符和运算数。

    遇到预算数时:压入堆栈存储,达到记住未参与运算数的目的

    遇到预算符号时:将栈里的运算数取出和运算符做运算,然后将运算结果入栈存储

    直到扫描到表达式的最末端,结束搜索,做完运算后,栈应该是空的。

    贴上我自己的实现:

    /**  求后缀表达式  ***/
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define MAX_SIZE 1000
    typedef char ElementType;
    
    typedef struct t_stack
    {
        ElementType data[MAX_SIZE];
        int top;
    }Stack_t;
    typedef Stack_t * pStack;
    
    typedef struct t_dstack
    {
        ElementType StackBuf[MAX_SIZE];
        int top1;
        int top2;
    }DStack_t;
    
    pStack stack_New(void)
    {
        pStack NewStack = (pStack)malloc(sizeof(Stack_t));
        memset(NewStack->data, 0, sizeof(NewStack->data));
        NewStack->top = -1;
        return NewStack;
    }
    
    /* 堆栈存储运算发符号 */
    pStack stack = NULL;
    char tempResult[100] = {0};
    int charNum = 0;
    
    int stack_isEmpty(Stack_t *s)
    {
        if (s)
        {
            if (s->top == -1)
                return 1;
            else
                return 0;
        }
        else
            return 1;
        
    }
    
    ElementType pop(pStack s)
    {
        if (!stack_isEmpty(s))
        {
            return s->data[(s->top)--];
        }
    }
    
    void push(pStack s, ElementType x)
    {
        if (s && s->top != MAX_SIZE - 1)
        {
            s->data[++(s->top)] = x;
        }
    }
    
    ElementType stack_gettop(pStack s)
    {
        if (!stack_isEmpty(s))
        {
            return s->data[(s->top)];
        }
        else
        {
            return -1;
        }
        
    }
    
    
    int tokenLevel(char token)
    {
        int level = 0;
        if (token == '*' || token == '/')
        {
            level = 1;
        }
        else if (token == '(')
        {
            level = -1;
        }
        
        return level;
    }
    
    int tokenCmp(char checktoken)
    {
        int ret = 0;
        char toptoken = stack_gettop(stack);
        int checklevel = tokenLevel(checktoken);
        int stacklevel = tokenLevel(toptoken);
        if (checktoken == ')' && toptoken == '(')
        {
            pop(stack);
            return 0;
        }
        if (toptoken == -1)
        {
            /* 空栈直接压入操作符号 */
            push(stack, checktoken);
            return 0;
        }
        else if (checklevel <= stacklevel || checktoken == ')')
        {
            /* 弹出堆栈内的运算符 */
            tempResult[charNum++] = pop(stack);
            tokenCmp(checktoken);
        }
        else
        {
            push(stack, checktoken);
            return 0;
        }
        return ret;
    }
    
    int main(void)
    {
        char expressString [100] = {0};
        stack = stack_New();
        int ret = 0;
        while (scanf("%s", expressString) != EOF)
        {
            int i = 0;
            memset(tempResult, 0, sizeof(tempResult));
            charNum = 0;
            
            while (expressString[i] != '')
            {
                if ((expressString[i]) >= '0' && expressString[i] <= '9')
                {
                    tempResult[charNum] = expressString[i];
                    charNum++;
                }
                else if (expressString[i] == '(')
                {
                    push(stack, expressString[i]);
                }
                else
                {
                    if (stack_isEmpty(stack))
                    {
                        push(stack, expressString[i]);
                    }
                    else
                    {
                        tokenCmp(expressString[i]);
                    }
                }
                i++;
            }
            while (!stack_isEmpty(stack))
            {
                tempResult[charNum++] = pop(stack);
            }
            /* 利用堆栈计算值 */
            stack->top = -1;
            for (i = 0; i < charNum; i++)
            {
                if (tempResult[i] >= '0' && tempResult[i]<= '9')
                    push(stack, tempResult[i]-'0');
                else
                {
                    int a = pop(stack);
                    int b = pop(stack);
                    switch (tempResult[i])
                    {
                        case '+':
                            ret = a + b;
                            push(stack, ret);
                            break;
                        case '-':
                            ret = b - a;
                            push(stack,ret);
                            break;
                        case '*':
                            ret = a * b;
                            push(stack,ret);
                            break;
                        case '/':
                            if (b)
                                ret = b / a;
                            push(stack,ret);
                            break;
                        default:
                            break;
                    }
                }
                
            }
            printf("%d", ret);
            memset(expressString, 0, sizeof(expressString));
        }
    
    }

    栈的特性

    只在一端(栈顶,Top)做 插入、删除
     插入数据:入栈(Push)
     删除数据:出栈(Pop)
     后入先出:Last In First Out(LIFO)
     

    栈的其他应用

    1、函数调用和递归实现
    2、深度优先搜索
    3、回溯算法
    。。。

    堆栈的抽象数据类型描述

    类型名称: 堆栈(Stack)
    数据对象集:一个有0个或多个元素的有穷线性表。
    操作集:长度为MaxSize的堆栈S - Stack,堆栈元素item - ElementType
    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 ):删除并返回栈顶元素;

    基于数组的栈实现

  • 相关阅读:
    Linux编程之自定义消息队列
    MVC5学习系列--Razor视图(一)
    JS将秒转换为 天-时-分-秒
    自己封装了一个EF的上下文类.,分享一下,顺便求大神指点
    VS2015企业版,社区版,专业版详细对比
    [干货来袭]C#6.0新特性
    WebApp上滑加载数据...
    用SignalR 2.0开发客服系统[系列5:使用SignalR的中文简体语言包和其他技术点]
    用SignalR 2.0开发客服系统[系列4:负载均衡的情况下使用SignalR]
    用SignalR 2.0开发客服系统[系列3:实现点对点通讯]
  • 原文地址:https://www.cnblogs.com/qinghaowusu/p/12669409.html
Copyright © 2011-2022 走看看