大话数据结构系列之栈的实际应用(十)

斐波那契函数推导( Java、C )

图解定义

C 语言实现

#include "stdio.h"

int Fbi(int i)  /* 斐波那契的递归函数 */
{
    if( i < 2 )
        return i == 0 ? 0 : 1;  
    return Fbi(i - 1) + Fbi(i - 2);  /* 这里Fbi就是函数自己,等于在调用自己 */
}  

int main()
{
    int i;
    int a[40];  
    printf("迭代显示斐波那契数列:\n");
    a[0]=0;
    a[1]=1;
    printf("%d ",a[0]);  
    printf("%d ",a[1]);  
    for(i = 2;i < 40;i++)  
    { 
        a[i] = a[i-1] + a[i-2];  
        printf("%d ",a[i]);  
    } 
    printf("\n");
    
    printf("递归显示斐波那契数列:\n");
    for(i = 0;i < 40;i++)  
        printf("%d ", Fbi(i));  
    return 0;
}

Java 实现

package com.example.stack;

public class FibonacciTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("使用迭代法实现:");
        circulation();
        System.out.println("使用递归法实现:================================================");
        for(int i = 0;i < 40; i++){
            System.out.println("i="+i+",结果为:"+fbi(i));
        }
    }
    
    public static void circulation() {
        int i;
        int a[] = new int[40];
        a[0] = 0;
        a[1] = 1;
        for(i = 2; i < 40; i++){
            a[i] = a[i-1] + a[i-2];
            System.out.println("i="+i+",结果为:"+a[i]);
        }
    }
    
    public static int fbi(int i){
        if(i < 2)
            return i ==0 ? 0 : 1;
        return fbi(i - 1) + fbi(i - 2);
    }
}

使用栈来实现四则运算( Java、C )

后缀到输出
1、从左到右遍历表达式的每个数字和符号,遇到是数字就进栈
2、遇到符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果

中缀转后缀
优先级:乘除优先加减
1、从左到右遍历每个数字和符号,若是数字就输出
2、若是符号,则判断其余栈顶符号的优先级,是右括号或优先级低于栈顶符号,则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止

参考:–https://blog.csdn.net/weixin_44187963/article/details/90140882
Java 语言

package com.example.stack;
import java.util.Stack;
/*利用栈,进行四则运算的类
    后缀到输出:
    **规则**:  
    1、从左到右遍历表达式的每个数字和符号,遇到是数字就进栈
    2、遇到符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果
    实例:9 3 1 - 3 * + 10 2 / +    =>      20
    
    中缀转后缀:
    **规则**:
    优先级:乘除优先加减
    1、从左到右遍历每个数字和符号,若是数字就输出
    2、若是符号,则判断其余栈顶符号的优先级,是右括号或优先级低于栈顶符号,则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止
    实例: 9+(3-1)*3+10/2   =>     9 3 1 - 3 * + 10 2 / + 
 */
public class Operate {
    
    /*
     * 验证数字串
     */
    public static void main(String args[]) {
        Operate operate = new Operate();
        //运算时加上
      /*  int t = operate.caculate("9+2*(3-1)+5*4/5"); 
        System.out.println(t);*/
        int t2 = operate.caculate("9+(3-1)*3+10/2");
        System.out.println(t2);
    }
    
    // 操作符栈
    private Stack<Character> priStack = new Stack<Character>();
    
    // 操作数栈
    private Stack<Integer> numStack = new Stack<Integer>();

    /**
     * @param str 需要进行技术的表达式
     * @return 计算结果
     */
    public int caculate(String str) {
        // 1.判断string当中有没有非法字符
        String temp;
        // 2.循环开始解析字符串,当字符串解析完,且符号栈为空时,则计算完成
        StringBuffer tempNum = new StringBuffer();
        StringBuffer string = new StringBuffer().append(str).append("#");

        while (string.length() != 0) {
            temp = string.substring(0, 1);
            string.delete(0, 1);
            // 判断temp,当temp为操作符时
            if (!isNum(temp)) {
                // 1.此时的tempNum内即为需要操作的数,取出数,压栈,并且清空tempNum
                if (!"".equals(tempNum.toString())) {
                    // 当表达式的第一个符号为括号
                    int num = Integer.parseInt(tempNum.toString());
                    numStack.push(num);
                    tempNum.delete(0, tempNum.length());
                }
                while (!compare(temp.charAt(0)) && (!priStack.empty())) {
                    // 第二个运算数
                    int a = (int) numStack.pop();
                    // 第一个运算数
                    int b = (int) numStack.pop();
                    char ope = priStack.pop();
                    int result = 0;
                    switch (ope) {
                        case '+':
                            result = b + a;
                            numStack.push(result);
                            break;
                        case '-':
                            result = b - a;
                            numStack.push(result);
                            break;
                        case '*':
                            result = b * a;
                            numStack.push(result);
                            break;
                        case '/':
                            result = b / a;
                            numStack.push(result);
                            break;
                    }

                }
                // 判断当前运算符与栈顶元素优先级, 如果高,或者低于平,计算完后,将当前操作符号,放入操作符栈
                    priStack.push(new Character(temp.charAt(0)));
                    // 当栈顶为'(',而当前元素为')'时,则是括号内以算完,去掉括号
                    if (temp.charAt(0) == ')') {
                        priStack.pop();
                        priStack.pop();
                    }
            } else
                // 当为非操作符时(数字)
                tempNum = tempNum.append(temp);
        }
        return numStack.pop();
    }

    /**
     * 判断传入的字符是不是0-9的数字
     *传入的字符串
     * @return
     */
    private boolean isNum(String temp) {
        return temp.matches("[0-9]");
    }

    /**
     * @param str 需要进行比较的字符
     * @return 比较结果 true代表比栈顶元素优先级高,false代表比栈顶元素优先级低
     */
    private boolean compare(char str) {
        if (priStack.empty()) {
            // 当为空时,显然 当前优先级最低,返回高
            return true;
        }
        char last = (char) priStack.lastElement();
        // 如果栈顶为'('显然,优先级最低,')'不可能为栈顶。
        if (last == '(') {
            return true;
        }
        switch (str) {
            case '#':
                return false;// 结束符
          case '(':
                // '('优先级最高,显然返回true
                return true;
            case ')':
                // ')'优先级最低,
                return false;
            case '*': {
                // '*/'优先级只比'+-'高
                if (last == '+' || last == '-')
                    return true;
                else
                    return false;
            }
            case '/': {
                if (last == '+' || last == '-')
                    return true;
                else
                    return false;
            }
            // '+-'为最低,一直返回false
            case '+':
                return false;
            case '-':
                return false;
        }
        return true;
    }
}

栈与递归的关系

递归
把一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称做递归函数。

特点:每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身而是返回值退出

以 fbi(5) 为例,图解递归展示:
在这里插入图片描述

关系
递归过程退回的顺序是它前行顺序的逆序
在退回过程中,可能要执行某些动作,包括恢复在前行过程中存储起来的某些数据
这种存储某些数据,并在后面又以存储的逆序恢复这些数据,以提供之后使用的需求,显然很符合栈这样的数据结构。
更详细解析:参见博主另一篇博客 <栈 与 递归 不得不说的“故事”>-- https://blog.csdn.net/weixin_39966065/article/details/104037329

栈与递归的实际功用
浏览器的撤回功能
不管什么浏览器都有一个“后退”键,你点击后可以按访问顺序的逆序加载浏览过的网页。即使你从第一个网页开始,连续点了几十个链接跳转,你点“后退”时,还是可以像历史倒退一样,回到之前浏览过的某个页面

“递归”与“迭代”的选择性讨论

迭代:使用的是循环结构
利用变量的原值推出新值称为迭代,或着说迭代是函数内某段代码实现循环;
例如:for,while循环

递归:使用的是选择结构
重复调用函数自身实现循环称为递归;
例如:if else 调用自己,并在合适时机退出

对比图解:

两者关系:所有的迭代可以转换为递归,但递归不一定可以转换成迭代。
图:
在这里插入图片描述

诗词即兴环节

摘自”坐者“—— 程杰

  人生,就像是一个很大的栈演变。出生时你赤条条地来到人世,慢慢地长大,渐渐地变老,最终还是得赤条条地离开世间。
 人生,又仿佛是一天一天小小的栈重现。童年父母每天抱你不断地进出家门,壮年你每天奔波于家与事业之间,老年你每天独自蹒跚于养老院的门里屋前。
 人生,更需要又进栈出栈精神的体现。在哪里跌倒,就应该在哪里爬起来。无论陷入何等困境,只要抬头能仰望蓝天,就有希望,不断进取,你就可以让出头之日重现。困难不会永远存在,强者才能勇往直前。
 人生,其实就是一个大大的队列演变。无知童年、快乐少年,稚傲青年,成熟中年,安逸万年。
 人生,又是一个又一个小小的队列重现。穿下秋冬轮回年年,早中晚夜循环天天。变化的是时间,不变的是你对未来执着的信念。
 人生,更需要又队列精神的体现。南极到别急,不过是南纬 90 度到北纬 90 度的队列,如果你中途犹豫,临时转向,也许你就只能和企鹅相伴永远。可事实上,无论哪个方向,只要你坚持到底,你都可以到达终点。
 人生,或许如队列,如栈,但它就是现在,这就是人生(楼主乱入:》)

发布了222 篇原创文章 · 获赞 54 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/weixin_39966065/article/details/104037514
今日推荐