栈和队列的基本应用

目录

1 栈的基本应用

1.1 括号匹配

1.2 表达式转换求值

1.2.1 表达式转换(中缀转后缀、前缀)

1.2.2 表达式求值(后缀、前缀的手算和机算)

1.3 栈在递归中的应用

2 队列的基本应用

2.1 树的层次遍历

2.2 图的广度优先遍历

2.3 队列在操作系统中的应用


1 栈的基本应用

1.1 括号匹配

问题:

假设表达式有三种括号:圆括号“()”,花括号“{}”,方括号“[]”。它们可互相嵌套,如{([])}或{([])()[]}均为正确格式。而{)),{[()]均为不正确格式。

输入由三种括号构成的字符串,如何检测字符串里括号格式的正确性?

力扣题目:有效的括号

算法思路:

  • 创建一个空栈,开始顺序扫描所有字符
  • 遇到左括号入栈
  • 遇到右括号则弹出已入栈的栈顶左括号(若栈为空没有左括号,直接退出报错)
  • 检查两括号是否匹配(若两括号类型不一样,直接退出报错)
  • 若所有字符都扫描完,检查栈里是否还剩余左括号(若栈里还有左括号剩余,则报错)

算法核心就是:遇到左括号就入栈,遇到右括号就弹出栈顶的左括号与右括号匹配

匹配失败有三种情况:

  • 右括号单身(右括号要匹配时,栈已经为空)
  • 左右括号不匹配
  • 左括号单身(右括号匹配完,栈不为空)

 实现代码:

bool isValid(char * s)
{
    int len=strlen(s);
    char stack[len];
    int top=-1;    //栈顶指针
    for(int i=0;i

1.2 表达式转换求值

栈和队列的基本应用_第1张图片

1.2.1 表达式转换(中缀转后缀、前缀)

中缀表达式:(我们正常手写的表达式)

左操作数  运算符  右操作数 」(运算符 是写在 两个操作数 中间的)

 如表达式:A + B * (C - D) E / F

后缀表达式:

左操作数   右操作数   运算符(运算符 是写在 两个操作数 后面的

1 手算

中缀表达式 转成 后缀表达式 :从左往右转换表达式,保证运算顺序唯一

上文 中缀表达式 转成 后缀表达式 步骤:

  1. C - D == C -
  2. * (C - D) == B * (CD-) == C D - * 
  3. A + B * (C - D) == A + (B  C D - *)==A B C D - * +
  4. E / F == E F /
  5. A + B * (C - D)E / F ==(A B C D - * +) - (E F /) == A B C D - * + E F / -

2 机算

  1. 建立一个用于保存暂时还不能确定运算顺序的运算符),一个数组(用于存放后缀表达式),从左到右处理各个元素,直到末尾(会遇到三种情况)
  2. 遇到操作数:直接存入后缀表达式的数组
  3. 遇到界限符:
    1. 遇到“(”直接入栈
    2. 遇到“)”则依次弹出栈内运算符 存入后缀表达式直到 弹出“(”为止。注意:“(”不加入后缀表达式
  4. 遇到运算符:
    1. 依次弹出栈内优先级高于或等于遇到运算符的所有运算符存入后缀表达式直到弹出“(” 或栈空则停止。(* / 优先级高于 + -
    2. 之后再把遇到的运算符入栈

前缀表达式:

「  运算符   左操作数   右操作数」(运算符 是写在 两个操作数 前面的

中缀表达式 转成 后缀表达式:从右往左转换表达式,保证运算顺序唯一

上文 中缀表达式 转成 前缀表达式 步骤:

  1. E / F == E F
  2. C - D == C
  3. * (C - D) == *  - C D
  4. B * (C - D)E / F  == -  * B - C D  / E F
  5. A + B * (C - D) - E / F == + A - * B - C D  / E F

1.2.2 表达式求值(后缀、前缀的手算和机算)

后缀表达式求值:

1 手算

  1. 左往右扫描下一个运算符,直到处理完所有元素
  2. 遇到运算符,让运算符前面最近的两个操作数执行对应运算
  3. 将运算结果作为下一个运算符的一个操作数,回到1

栈和队列的基本应用_第2张图片

 2 机算

实现后缀表达式的计算:

  1. 建立一个用于保存暂时还不能确定运算顺序操作数),左往描后缀表达式的下一个元素,直到处理完所有元素
  2. 若扫描到操作数则压入栈,并回到1;否则执行3
  3. 若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,回到1

注意:

  • 先出栈的 是“右操作数”,而计算始终是左操作数对右操作数的计算,注意运算顺序!
  • 若表达式合法, 则最后栈中只会 留下一个元素, 就是最终结果
  • 可动手画一画入栈出栈过程

力扣题目:逆波兰表达式求值

机算代码:

int evalRPN(char ** tokens, int tokensSize)
{
    int stack[tokensSize];
    int top=-1;int a,b,c=0;
    memset(stack,0,sizeof(stack));
    for(int i=0;i=1)
        {
            a=stack[top-1];
            b=stack[top];
        }
        if(strcmp(tokens[i],"+")==0)
            c=a+b;
        else if(strcmp(tokens[i],"-")==0)
            c=a-b;
        else if(strcmp(tokens[i],"*")==0)
            c=a*b;
        else if(strcmp(tokens[i],"/")==0)
            c=a/b;    
        else
        {
            stack[++top]=atoi(tokens[i]);
            continue;
        }
        top=top-2;
        stack[++top]=c;
    }
    return stack[top];     
}

前缀表达式求值:

1 手算

  1. 右往左扫描下一个运算符,直到处理完所有元素
  2. 遇到运算符,让运算符后面最近的两个操作数执行对应运算
  3. 将运算结果作为下次运算的一个操作数,回到1

 2 机算

实现前缀表达式的计算:

  1. 建立一个栈(用于保存暂时还不能确定运算顺序操作数,从右往左描前缀表达式的下一个元素,直到处理完所有元素
  2. 若扫描到操作数则压入栈,并回到1;否则执行3
  3. 若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,回到1

注意:

  • 先出栈的 是“左操作数”,而后缀表达式先出栈的“右操作数
  • 若表达式合法, 则最后栈中只会 留下一个元素, 就是最终结果

机算代码:

 中缀表达式求值:

中缀求值=中缀转后缀+后缀求值

  1. 建立两个栈,运算符栈中缀转后缀)和操作数栈后缀求值
  2. 若扫描到操作数压入操作数栈
  3. 若扫描到运算符或界限符,则按照“中缀转后缀”相同的逻辑压入运算符栈(当期间每弹出一个运算符时,就需要再弹出两个操作数栈的栈顶元素并执行相应运算, 运算结果再压回操作数栈

栈和队列的基本应用_第3张图片
 

1.3 栈在递归中的应用

函数调用的特点:最后被调用的函数最先执行结束(LIFO) 

栈和队列的基本应用_第4张图片

栈和队列的基本应用_第5张图片

 栈和队列的基本应用_第6张图片

 栈和队列的基本应用_第7张图片

栈和队列的基本应用_第8张图片

2 队列的基本应用

2.1 树的层次遍历

2.2 图的广度优先遍历

2.3 队列在操作系统中的应用

多个进程争抢着使用有限的系统资源时,FCFS(First Come First Service, 先来先服务)是一种常用策略。

你可能感兴趣的:(算法,数据结构)