IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Java数据结构和算法---栈 (前中后缀表达式)、递归 -> 正文阅读

[数据结构与算法]Java数据结构和算法---栈 (前中后缀表达式)、递归

栈(stack)的定义
? ? ? ? ①栈是一个先入后出的有序链表
? ? ? ? ②栈是限制线性表中元素的插入和删除只能在线性表的同一段进行的一种特殊线性表?
? ?允许插入和删除的一段 为变化的一端 称为 栈顶 另一端为固定的一端 称为栈底
? ? ? ? ③根据栈的定义可知 最先放入栈中元素在栈底 最后放入的元素在栈顶 而删除元素刚好相反
? ?最后放入的元素最先删除 最先放入的元素最后删除

?栈的应用场景? ? ? ??

?数组模拟栈
? ? ? ? ·定义一个top来表示栈顶 初始化为-1
? ? ? ? ·入栈的操作 当有数据加入到栈时 top++? ? ?stack[top]=data
? ? ? ? ·出栈的操作 int value = stack[top] top--??? return value
代码:

package zhan;

public class shuzumonizhan {
    public static void main(String[] args) {
        ArrayStack arrayStack = new ArrayStack(5);
        arrayStack.push(1);
        arrayStack.push(2);
        arrayStack.push(3);
        arrayStack.push(4);
        arrayStack.list();
        System.out.println();
        System.out.println(arrayStack.pop());
    }
}
class ArrayStack{
    private int maxSize;//栈的大小
    private int[] stack;//数组  数组模拟战 数据放在这里
    private int top = -1;

    //构造器
    public ArrayStack(int maxSize){
        this.maxSize = maxSize;
        stack = new int[this.maxSize];
    }

    //判断栈满
    public boolean isFull(){
        return top == maxSize-1;
    }
    //
    public boolean isEmpty(){
        return top==-1;
    }

    //入栈
    public void push(int value){
        if(isFull()){
            System.out.print("满啦!");
            return;
        }
        top++;
        stack[top] = value;
    }

    //出栈
    public int pop(){
        if(isEmpty()){
            throw new RuntimeException("空的!");
        }
        int value = stack[top];
        top--;
        return value;
    }
    //遍历栈  遍历时 需要从栈顶开始显示
    public void list(){
        if(isEmpty()){
            return;
        }
        for (int i = top; i >-1 ; i--) {
            System.out.println("stack["+i+"]:"+stack[i]);
        }
    }
}


?

栈实现综合计算器
? ? ? ? 思路:? ? ? ?

????????

?代码(暂时不考虑括号):

package zhan;

public class jisuanqi {
    public static void main(String[] args) {
        String expression = "70+2*6-4";
        //创建两个栈 一个数字 一个符号
        ArrayStackJsq numStackJsq = new ArrayStackJsq(10);
        ArrayStackJsq opeStackJsq = new ArrayStackJsq(10);

        int index = 0;//用于扫描
        int num1 = 0;
        int num2 = 0;
        int ope = 0;
        int res = 0;
        String temp = "";
        char ch = ' ';//将每次扫描得到的char保存到ch
        while(true){
            //一次得到exp中的每个字符
            ch = expression.substring(index,index+1).charAt(0);
            //判断ch
            if(opeStackJsq.isOper(ch)){
                if(!opeStackJsq.isEmpty()){
                    //判断优先级
                    if(opeStackJsq.youxianji(ch)<=opeStackJsq.youxianji(opeStackJsq.zhanding())){
                        num1 = numStackJsq.pop();
                        num2 = numStackJsq.pop();
                        ope = opeStackJsq.pop();
                        res = numStackJsq.cal(num1,num2,ope);
                        numStackJsq.push(res);
                        opeStackJsq.push(ch);
                    }else {
                        opeStackJsq.push(ch);
                    }
                }else {
                    opeStackJsq.push(ch);
                }
            }else {
                //numStackJsq.push(ch-48);
                //当处理多位数字时 处理数时 要向expression的index后再看一位 若是数 就再扫描 是符号再入栈
                temp+=ch;

                if(index==expression.length()-1){
                    numStackJsq.push(Integer.parseInt(temp));
                }else{
                    //判断下一个字符是不是数字
                    if(opeStackJsq.isOper(expression.substring(index+1,index+2).charAt(0))){
                        numStackJsq.push(Integer.parseInt(temp));
                        temp="";
                    }
                }


            }
            index++;
            if(index==expression.length()){
                break;
            }
        }
        while (true){
            //若符号栈为空则 计算结束
            if(opeStackJsq.isEmpty()){
                break;
            }
            num1 = numStackJsq.pop();
            num2 = numStackJsq.pop();
            ope = opeStackJsq.pop();
            res = numStackJsq.cal(num1,num2,ope);
            numStackJsq.push(res);
        }
        System.out.println(numStackJsq.pop());
    }
}
class ArrayStackJsq{
    private int maxSize;//栈的大小
    private int[] stack;//数组  数组模拟战 数据放在这里
    private int top = -1;

    //读取栈顶的元素
    public int zhanding(){
        return stack[top];
    }

    //构造器
    public ArrayStackJsq(int maxSize){
        this.maxSize = maxSize;
        stack = new int[this.maxSize];
    }

    //判断栈满
    public boolean isFull(){
        return top == maxSize-1;
    }
    //
    public boolean isEmpty(){
        return top==-1;
    }

    //入栈
    public void push(int value){
        if(isFull()){
            System.out.print("满啦!");
            return;
        }
        top++;
        stack[top] = value;
    }

    //出栈
    public int pop(){
        if(isEmpty()){
            throw new RuntimeException("空的!");
        }
        int value = stack[top];
        top--;
        return value;
    }
    //遍历栈  遍历时 需要从栈顶开始显示
    public void list(){
        if(isEmpty()){
            return;
        }
        for (int i = top; i >-1 ; i--) {
            System.out.println("stack["+i+"]:"+stack[i]);
        }
    }

    //返回运算符的优先级 优先级使用数组表示
    //数字越大 优先值越高
    public int youxianji(int oper){
        if(oper=='*'||oper=='/'){
            return 1;
        }else if(oper=='+'||oper=='-'){
            return 0;
        }else{
            return -1;
        }
    }
    //判断是不是一个运算符
    public boolean isOper(char val){
        return val=='+'||val=='-'||val=='*'||val=='/';
    }
    //计算方法
    public int cal(int num1,int num2,int o){
        int res = 0 ;
        switch (o){
            case '+':
                res = num1+num2;
                break;
            case '-':
                res = num2-num1;
                break;
            case '*':
                res = num1*num2;
                break;
            case '/':
                res = num2/num1;
        }
        return res;
    }
}

前缀表达式(波兰表达式)
? ? ?
? 前缀表达式的运算符位于操作数之前
? ? ? ? eg: (3+4)*5-6的前缀表达式为-*3456
前缀表达式的计算机求值
? ? ? ? 从右到左扫描表达式 遇到数字时 将数字压入堆栈 遇到运算符时 弹出栈顶的两个数 用运算符对它们做相应的计算(栈顶元素 和 次栈顶元素) 并将结果入栈 重复上述过程直到表达式最左端 最后运算得出的值就是表达式的结果

????????
中缀表达式

?后缀表达式(逆波兰表达式)
? ? ? ?
后缀表达式与前缀表达式相似 只是运算符位于操作数之后

后缀表达式的计算机求值
? ?
? ? 从左至右 扫描表达式 遇到数字时 将数字压入堆栈 遇到运算符时 弹出栈顶的两个数 用运算符对它们做相应的计算(次顶元素和栈顶元素) 并将结果入栈 重复上述过程直到表达式最右端 最后运算得出的值即为表达式的结果? ? ? ??

?逆波兰计算器

?代码:

package zhan;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class nibolanbiaodashi {
    public static void main(String[] args) {
        //先定义一个逆波兰表达式
        //(3+4)*5-6 =>30 4 + 5 * 6 -
        String expre = "30 4 + 5 * 6 -";
        //先将expre放入ArrayList中
        //将ArrayList传递给一个方法 该方法配合栈 完成计算
        List<String> list = getListString(expre);
        System.out.println(list);
        System.out.println(cal(list));
    }
    //将一个逆波兰表达式 一次将数据和运算符放入到将ArrayList传递给一个方法
    public static List<String> getListString(String sss){
        //将sss分割
        String[] split = sss.split(" ");
        List<String> list = new ArrayList<>();
        for(String s : split){
            list.add(s);
        }
        return list;
    }
    //完成对逆波兰表达式的运算
    public static int cal(List<String> list){
        //创建一个栈即可
        Stack<String> strings = new Stack<>();
        for (String item:list) {
            //使用正则表达式取出数
            if(item.matches("\\d+")){
                strings.push(item);
            }else {
                int num2 = Integer.parseInt(strings.pop());
                int num1 = Integer.parseInt(strings.pop());
                int res = 0;
                if(item.equals("+")){
                    res=num1+num2;
                }else if(item.equals("-")){
                    res=num1-num2;
                }else if(item.equals("*")){
                    res = num1*num2;
                }else if(item.equals("/")){
                    res = num1/num2;
                }else {
                    throw new RuntimeException("ERROR!");
                }
                strings.push(res+"");
            }
        }
        return Integer.parseInt(strings.pop());
    }
}

?中缀表达式转换为后缀表达式
? ? ? ? 具体步骤:
? ? ? ?
①初始化两个栈:运算符栈s1和存储中间结果的栈s2
? ? ? ? ②从左至右扫描中缀表达式
? ? ? ? ③遇到操作数时 将其压入s2
? ? ? ? ④遇到运算符时 比较其与s1栈顶运算符的优先级
? ? ? ? ? ? ? ? *·若s1为空 ,或者栈顶运算符位左括号"(",则将此运算符入栈
? ? ? ? ? ? ? ? ·否则 若优先级比栈顶运算符的高 也将运算符压入s1
? ? ? ? ? ? ? ? ·否则 (比如运算及相同的+和-)将s1栈顶的运算符弹出并压入到s2中 再次转到(*)与s1中新的栈顶运算符比较
????????⑤遇到括号时:
????????? ? ? ? ·若是左括号"(" 则直接压入s1
????????????????·若是右括号")" 则依次弹出s1栈顶的运算符 并压入s2 直到遇到左括号为止 然后将这一
????????对括号丢弃
????????⑥重复步骤2-5 直到表达式的最右边
? ? ? ? ⑦将s1中剩余的运算符依次弹出并压入s2
????????⑧依次弹出s2中的元素并输出 结果的逆序即为中缀表达式对应的后缀表达式

?代码1:将表达式转为List

    //将中缀表达式转为相应的List
    public static List<String> toList(String str){
        List<String> ans = new ArrayList<>();
        int i = 0;
        String s;//多位数的拼接
        char c;//每遍历到一个字符 就放入到c
        do{
            //如果c是一个非数字 需要加入ans
            if((c=str.charAt(i))<48 || (c=str.charAt(i))>57) {
                ans.add(""+c);
                i++;
            }else {//若是一个数 需要考虑多位数
                s="";
                while(i<str.length()&&(c=str.charAt(i))>=48&&(c=str.charAt(i))<=57){
                    s+=c;
                    i++;
                }
                ans.add(s);
            }
        }while (i<str.length());
        return ans;
    }

代码2(中缀转逆波兰list):
?

    //将中缀表达式的list转为后缀表达式相应的list
    public static List<String> toNibolan(List<String>ans){
        //定义两个栈
        Stack<String>s1 = new Stack<>();//符号栈
//        Stack<String>s2 = new Stack<>();//中间栈  没有必要有这个 因为在
//        //整个转换过程中没有pop操作 且最后需要逆序输出 所以 使用一个list代替
        List<String> s2 = new ArrayList<String>(){};
        //遍历
        for(String item : ans){
            if(item.matches("\\d+")){
                s2.add(item);
            }else if(item.equals("(")){
                s1.push(item);
            }else if(item.equals(")")){
                while(!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                s1.pop();//将这一对括号消除
            }else {
                //当item优先级小于等于栈顶运算符优先级 将s1栈顶的运算符加入s2
                while (s1.size()!=0&&Operation.getValue(s1.peek())>=Operation.getValue(item)){
                    s2.add(s1.pop());
                }
                s1.push(item);
            }
        }

        while (s1.size()!=0){
            s2.add(s1.pop());
        }
        return s2;
    }

综合代码:

package zhan;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class zhongxuzhuannibolan {
    public static void main(String[] args) {
        //先把表达式转为中序的ArrayList 然后进行转换
        String expre = "1+((2+3)*4)-5";
        List<String> list = toList(expre);
        System.out.println(list);
        System.out.println();
        System.out.println(toNibolan(list));

    }


    //将中缀表达式的list转为后缀表达式相应的list
    public static List<String> toNibolan(List<String>ans){
        //定义两个栈
        Stack<String>s1 = new Stack<>();//符号栈
//        Stack<String>s2 = new Stack<>();//中间栈  没有必要有这个 因为在
//        //整个转换过程中没有pop操作 且最后需要逆序输出 所以 使用一个list代替
        List<String> s2 = new ArrayList<String>(){};
        //遍历
        for(String item : ans){
            if(item.matches("\\d+")){
                s2.add(item);
            }else if(item.equals("(")){
                s1.push(item);
            }else if(item.equals(")")){
                while(!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                s1.pop();//将这一对括号消除
            }else {
                //当item优先级小于等于栈顶运算符优先级 将s1栈顶的运算符加入s2
                while (s1.size()!=0&&Operation.getValue(s1.peek())>=Operation.getValue(item)){
                    s2.add(s1.pop());
                }
                s1.push(item);
            }
        }

        while (s1.size()!=0){
            s2.add(s1.pop());
        }
        return s2;
    }




    //将中缀表达式转为相应的List
    public static List<String> toList(String str){
        List<String> ans = new ArrayList<>();
        int i = 0;
        String s;//多位数的拼接
        char c;//每遍历到一个字符 就放入到c
        do{
            //如果c是一个非数字 需要加入ans
            if((c=str.charAt(i))<48 || (c=str.charAt(i))>57) {
                ans.add(""+c);
                i++;
            }else {//若是一个数 需要考虑多位数
                s="";
                while(i<str.length()&&(c=str.charAt(i))>=48&&(c=str.charAt(i))<=57){
                    s+=c;
                    i++;
                }
                ans.add(s);
            }
        }while (i<str.length());
        return ans;
    }


    //将一个逆波兰表达式 一次将数据和运算符放入到将ArrayList传递给一个方法
    public static List<String> getListString(String sss){
        //将sss分割
        String[] split = sss.split(" ");
        List<String> list = new ArrayList<>();
        for(String s : split){
            list.add(s);
        }
        return list;
    }
    //完成对逆波兰表达式的运算
    public static int cal(List<String> list){
        //创建一个栈即可
        Stack<String> strings = new Stack<>();
        for (String item:list) {
            //使用正则表达式取出数
            if(item.matches("\\d+")){
                strings.push(item);
            }else {
                int num2 = Integer.parseInt(strings.pop());
                int num1 = Integer.parseInt(strings.pop());
                int res = 0;
                if(item.equals("+")){
                    res=num1+num2;
                }else if(item.equals("-")){
                    res=num1-num2;
                }else if(item.equals("*")){
                    res = num1*num2;
                }else if(item.equals("/")){
                    res = num1/num2;
                }else {
                    throw new RuntimeException("ERROR!");
                }
                strings.push(res+"");
            }
        }
        return Integer.parseInt(strings.pop());
    }
}
//此类用来判断优先级
class Operation{
    public static final int ADD =1;
    public static final int SUB =1;
    public static final int MUL =2;
    public static final int DIV =2;
    public static int getValue(String ope){
        int res = 0;
        switch (ope){
            case "+":
                res = ADD;
                break;
            case "-":
                res = SUB;
                break;
            case "*":
                res = MUL;
                break;
            case "/":
                res = DIV;
                break;
        }
        return res;
    }
}

递归
? ? ?
? ①执行一个方法时 就创建一个新的受保护的独立空间(栈空间)
? ? ? ? ②方法的局部变量是独立的不会相互影响 比如n变量
? ? ? ? ③如果方法中使用的是引用类型的变量(比如数组) 就会共享该引用类型的数据
? ? ? ? ④递归必须向退出递归的条件必进 否则就是无限递归?
? ? ? ? ⑤当一个方法执行完毕 或者遇到return 就会返回 遵守谁调用 就将结果返回给谁
? ? 同时方法执行完毕或者返回时 该方法也就执行完毕

实际案例:
? ? ? ? 递归-迷宫问题 目前没学过算法 所以只能强行通过比较得出最短 索性放到后面再说了

public class migong {
    public static void main(String[] args) {
        //先创建一个二维数组 模拟迷宫
        int[][] map = new int[8][7];
        //用1表示墙壁
        //把上下置为1
        for (int i = 0; i < 7; i++) {
            map[0][i]=1;
            map[7][i]=1;
        }
        //把左右置为1
        for (int j = 0; j < 8; j++) {
            map[j][0]=1;
            map[j][6]=1;
        }
        map[3][1]=1;
        map[3][2]=1;
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(map[i][j]+"  ");
            }
            System.out.println();
        }
        System.out.println();
        System.out.println();
        setWay(map,1,1);
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(map[i][j]+"  ");
            }
            System.out.println();
        }
    //使用递归来给小球找路

    }

    /**
     *如果能到map[6][5] 则能找到
     * 当map[i][j]=0时 表示小球还没走过这个点 1表示墙  2表示走过 且是通路 3表示走过 但是死路
     * 在走迷宫时 需要确定一个方法 比如 按照下->右->上->左的顺序 若走不通 则回溯
     * @param map 地图
     * @param i (i,j)从哪个位置开始找
     * @param j
     * @return 若找到 返回true
     */
    public static boolean setWay(int [][]map,int i,int j){
        if(map[6][5]==2){
            return true;
        }else{
            if(map[i][j]==0){
                //按照下->右->上->左的顺序
                map[i][j]=2;//先假设能走通
                if(setWay(map,i+1,j)){
                    return true;
                }else if(setWay(map,i,j+1)){
                    return true;
                }else if(setWay(map,i-1,j)){
                    return true;
                }else if(setWay(map,i,j-1)){
                    return true;
                }else {
                    map[i][j]=3;
                    return false;
                }

            }else {//可能是123
                return false;
            }
        }
    }
}

? 递归八皇后问题
?

?

?思路分析:


public class bahuanghou {
    static int max = 8;//表示有几个皇后
    int []array = new int[max];//存最后的结果
    static int count=0;
    static int count2=0;
    public static void main(String[] args) {
        bahuanghou bahuanghou = new bahuanghou();
        bahuanghou.check(0);
        System.out.println(count);
        System.out.println(count2);
    }
    //可以将皇后摆放的位置输出
    private void print(){
        count++;
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]+" ");
        }
        System.out.println();
    }
    //查看我们放置第n个皇后后 去检测该皇后是否和前面已经摆放的皇后冲突
    private boolean judge(int n){
        count2++;
        for (int i = 0; i < n; i++) {
            //表示第n个皇后 是否和前面的n-1个皇后  是否在同一列      是否在同一直线
            if (array[i] == array[n]||Math.abs(n-i)==Math.abs(array[n]-array[i])) {
                return false;
            }
        }
        return true;
    }
    //编写一个方法 放置第n个皇后
    private void check(int n){
        if(n==max){
           print();
           return;
        }
        //依次放入 并判断是否冲突
        for (int i=0 ; i < max ;i++){
            //先把当前这个皇后n 放到该行的第一列
            array[n]=i;
            if(judge(n)){//不冲突
                //接着放第n+1个皇后
                check(n+1);
            }
        }
    }
}

?

?

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-30 18:50:35  更:2022-03-30 18:55:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 11:47:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码