多线程练习

做以下练习的基本步骤:

  1. 定义共享变量(若要创建多个对象使用静态);
  2. 写循环(while)
    1. 有时候不写while,比如说抢红包每条线程只能抢一次,就不用while循环
  3. 同步代码块
  4. 判断(已经到末尾)
  5. 再判断(没有到末尾)

重点1:要知道共享变量是定义在javaBean内,还是定义在main方法中(创建对象时传递过来)
重点2:要清楚while循环的结束条件是什么,


1.

image.png
SelTickets类:

public class SellTickets extends Thread{

    private static int tickets=1;


    @Override
    public void run() {
        //1循环
        while(true){
            //2同步代码块确保线程安全
            synchronized (SellTickets.class){
                //3判断
                if (tickets==1000){
                    break;
                }else {
                    //让当前线程睡30毫秒
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }

                    System.out.println(Thread.currentThread().getName()+":正在卖第"+tickets+"张票");
                    tickets++;
                }
            }
        }
    }
}

main:

public class Test {
    public static void main(String[] args) {
        //创建两个线程
        SellTickets s1=new SellTickets();
        SellTickets s2=new SellTickets();
        //设名字
        s1.setName("窗口一");
        s2.setName("窗口二");
        //开始
        s1.start();
        s2.start();

    }
}

2.

image.png

public class MyRun implements Runnable{
    //第二种方式实现多线程,测试类中MyRunable只创建一次,所以不需要加static
    private  int gift=100;


    @Override
    public void run() {
        //1.循环
        while(true){
            //2.同步代码块确保线程安全
            synchronized (MyRun.class){
                //让当线程小睡一会
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                //3.判断
                if (gift<10){
                    break;
                }else {
                    gift--;
                    System.out.println(Thread.currentThread().getName()+"正在送,还剩:"+gift+"份");
                }
            }
        }
    }
}

main

public class Test {
    public static void main(String[] args) {

        //线程任务
        MyRun m=new MyRun();
        //创建线程
        Thread t1=new Thread(m);
        Thread t2=new Thread(m);
        //设置名字
        t1.setName("小王");
        t2.setName("小李");
        //开始
        t1.start();
        t2.start();
    }
}

image.png

3

image.png
使用第三种方法

public class MyRunable implements Runnable {
//第二种方式实现多线程,测试类中MyRunable只创建一次,所以不需要加static
    private int number = 1;

    @Override
    public void run() {
        //循环
        while (true) {

            //同步代码块确保线程安全
            synchronized (MyCall.class) {
                //判断
                if (number <= 100) {
                    if (number % 2 == 1) {
                        System.out.println(Thread.currentThread().getName() + "打印数字" + number);
                    }
                    number++;
                } else {
                    break;
                }
            }
        }
    }
}

main

public class Test {
    public static void main(String[] args) {

        MyRunable mc=new MyRunable();

        //创建线程传入mc参数
        Thread t1=new Thread(mc);
        Thread t2=new Thread(mc);

        t1.setName("线程一");
        t2.setName("线程二");

        t1.start();
        t2.start();
    }
}

4.

.image.png
改进前:

public class Grab extends Thread {
    //使用第一种方法,可能创建多个线程使用静态修饰
    private static double money = 100;
    //红包个数
    static int count = 3;
    //最小的中奖金额
    static final double MIN = 0.01;

    @Override
    public void run() {
         //循环舍弃:抢红包一人只能抢一次
        //同步代码块保证线程安全
        synchronized (Grab.class) {
            if (count == 0) {
                //如果没红包了就说明没抢到
                System.out.println(getName() + "没抢到红包");
            } else {
                //还有红包
                //定义一个变量表示中奖的金额
                double prize = 0;
                if (count == 1) {
                    //表示是最后一个红包,抽取剩下的钱即可
                    prize = money;
                } else {
                    //第一个和第二个红包
                    Random r = new Random();
                    //要知道第一个红包最多抽到99.98元 (因为100要分成3个包)
                    //100-(count-1)*min,在这个范围内抽
                    //若第一个红包最多抽到99.98元,则第二个红包最多抽到0.01元 (因为100要分成3个包)
                    //100-99.98-(count-1)*min,在这个范围内抽
                    prize = r.nextDouble(money - (count - 1) * MIN);
                    //又因为抽红包有可能抽到比0.01还小的数,所以强制改为0.01
                    if (prize < MIN) {
                        prize = MIN;
                    }
                }
                System.out.println(getName() + "抢到了" + prize);
                //更改红包数
                count--;
                //更改money
                money -= prize;
            }
        }
    }
}

main

public class Test {
    public static void main(String[] args) {

        //创建5个线程
        Grab g1=new Grab();
        Grab g2=new Grab();
        Grab g3=new Grab();
        Grab g4=new Grab();
        Grab g5=new Grab();

        //给线程设置名字
        g1.setName("小A");
        g2.setName("小B");
        g3.setName("小C");
        g4.setName("小D");
        g5.setName("小E");

        //启动线程
        g1.start();
        g2.start();
        g3.start();
        g4.start();
        g5.start();
    }
}

image.png
发现有问题:小数位并没有保留两位,不贴近现实

改进后:

public class Grab2 extends Thread {
    //使用第一种方法,可能创建多个线程使用静态修饰
    private static BigDecimal money = BigDecimal.valueOf(100);
    //红包个数
    static int count = 3;
    //最小的中奖金额
    static final BigDecimal MIN = BigDecimal.valueOf(0.01);

    @Override
    public void run() {
        //循环舍弃:抢红包一人只能抢一次
        //同步代码块确保线程安全
        synchronized (Grab2.class) {
            if (count == 0) {
                //如果没红包了就说明没抢到
                System.out.println(getName() + "没抢到红包");
            } else {
                //还有红包
                //定义一个变量表示中奖的金额
                BigDecimal prize;
                if (count == 1) {
                    //表示是最后一个红包,抽取剩下的钱即可
                    prize = money;
                } else {
                    //第一个和第二个红包
                    Random r = new Random();
                    //要知道第一个红包最多抽到99.98元 (因为100要分成3个包)
                    //100-(count-1)*min,在这个范围内抽
                    //若第一个红包最多抽到99.98元,则第二个红包最多抽到0.01元 (因为100要分成3个包)
                    //100-99.98-(count-1)*min,在这个范围内抽
                    double bounds = money.subtract(BigDecimal.valueOf(count - 1).multiply(MIN)).doubleValue();
                    prize = BigDecimal.valueOf(r.nextDouble(bounds));
                    //又因为抽红包有可能抽到比0.01还小的数,所以
                }
                //四舍五入
                prize = prize.setScale(2, RoundingMode.HALF_UP);
                System.out.println(getName() + "抢到了" + prize);
                //更改红包数
                count--;
                //更改money
                money=money.subtract(prize);
            }
        }
    }
}

main

public class Test {
    public static void main(String[] args) {


        Grab2 g1=new Grab2();
        Grab2 g2=new Grab2();
        Grab2 g3=new Grab2();
        Grab2 g4=new Grab2();
        Grab2 g5=new Grab2();

        //给线程设置名字
        g1.setName("小A");
        g2.setName("小B");
        g3.setName("小C");
        g4.setName("小D");
        g5.setName("小E");

        //启动线程
        g1.start();
        g2.start();
        g3.start();
        g4.start();
        g5.start();


    }
}

image.png

5.

image.png
这里的难点是这个奖池应该定义在哪, javabean的成员位置还是?

在Java中,如果你在main方法中创建了两个JavaBean对象,并且在构造这两个对象时都传递了同一个List集合的引用,那么这两个JavaBean对象将操作同一个集合。这意味着对任何一个对象通过该集合进行的增删改查操作,都会影响到另一个对象通过该集合看到的数据。
具体见:**基本数据类型和引用数据类型的特性

public class Prize implements Runnable {
        
    ArrayList<Integer> list;

    //构造,从创建对象时传递一个集合过来
    public Prize(ArrayList<Integer> list) {
        this.list = list;
    }


    @Override
    public void run() {
        //循环
        while (true) {
            //同步代码块,确保线程安全
            synchronized (Prize.class) {
                if (list.isEmpty()) {
                    break;
                }
                //随机获取集合元素----抽奖
                Collections.shuffle(list);
                Integer num = list.remove(0);
                System.out.println(Thread.currentThread().getName() + "又产生了一个" + num + "元的大奖");
            }
            
            //让当前线程睡一会,给别的线程机会
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }


        }
    }
}

main

public class Test {
    public static void main(String[] args) {
        //创建奖池
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);

        //传入参数
        Prize t = new Prize(list);
        //创建线程并传入t
        Thread t1=new Thread(t);
        Thread t2=new Thread(t);

        //设置名字
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");

        //启动线程
        t1.start();
        t2.start();
    }
}

image.png

6.

image.png

public class Prize implements Runnable {

    ArrayList<Integer> list;

    //构造,从main方法传递一个集合过来
    public Prize(ArrayList<Integer> list) {
        this.list = list;
    }

    //用两个变量记录 两个抽奖箱产生中奖次数
    int count1 = 0;
    int count2 = 0;
    //用两个集合存储奖项
    ArrayList<Integer> list1 = new ArrayList<>();
    ArrayList<Integer> list2 = new ArrayList<>();
    

    @Override
    public void run() {
        //循环
        while (true) {
            //同步代码块,确保线程安全
            synchronized (Prize.class) {
                
                if (list.isEmpty()) {
                    //当奖箱全部获取完了就开始打印
                     if ("抽奖箱1".equals(Thread.currentThread().getName())) {
                         //求最大值
                        Integer max = Collections.max(list1);
                        System.out.println("抽奖箱1" + list1+":"+count1+"个奖项,最大值是"+max);
                    } else {
                         //求最大值
                        Integer max = Collections.max(list2);
                        System.out.println("抽奖箱2" + list2+":"+count2+"个奖项,最大值是"+max);
                    }
                    break;
                    
                } else {
                    //list大小不是0,继续抽奖
                    //随机获取元素
                    Collections.shuffle(list);
                    Integer prize = list.remove(0);
                    
                    if ("抽奖箱1".equals(Thread.currentThread().getName())) {
                        //添加到list1
                        list1.add(prize);
                        //个数++
                        count1++;
                    } else {
                        //添加到list2
                        list2.add(prize);
                        //个数++
                        count2++;
                    }
                }
                
            }
            //让当前线程睡一会,给别的线程机会
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            
        }
    
    }
}

main

public class Test {
    public static void main(String[] args) {
        //创建奖池
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);

       
        Prize t = new Prize(list);
         //创建线程
        Thread t1=new Thread(t);
        Thread t2=new Thread(t);

        //设置名字
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");

        //启动线程
        t1.start();
        t2.start();

    }
}

image.png

这种方法的弊端:当有非常多的抽奖箱时(线程),不可能一个个创建集合来存储中奖项
改进:在run方法内定义一个box集合,创建多个线程时会调用run方法来创建线程对应的集合

public class Prize implements Runnable {

    ArrayList<Integer> list;

    //构造,从main方法传递一个集合过来
    public Prize(ArrayList<Integer> list) {
        this.list = list;
    }

    //用两个变量记录 两个抽奖箱产生中奖次数
    int count1 = 0;
    int count2 = 0;
    

    @Override
    public void run() {
        //在run方法内创建一个集合,创建多少个线程就会创建多少个相应的集合
        ArrayList<Integer>box=new ArrayList<>();
        //循环
        while (true) {
            //同步代码块,确保线程安全
            synchronized (Prize.class) {
                if (list.isEmpty()) {
                    //当奖箱全部获取完了就开始打印
                    if ("抽奖箱1".equals(Thread.currentThread().getName())) {
                        int max = Collections.max(box);
                        System.out.println("抽奖箱1" + box + ":" + count1 + "个奖项,最大值是" + max);
                    } else {
                        int max = Collections.max(box);
                        System.out.println("抽奖箱2" + box + ":" + count2 + "个奖项,最大值是" + max);
                    }
                    break;

                } else {
                        //继续抽奖(打乱获取第一个)
                    Collections.shuffle(list);
                    Integer prize = list.remove(0);

                    if ("抽奖箱1".equals(Thread.currentThread().getName())) {
                        //放入box
                        box.add(prize);
                        //奖项数
                        count1++;
                    } else {
                        //放入box
                        box.add(prize);
                        //奖项数
                        count2++;
                    }

                }
            }
            //让当前线程睡一会,给别的线程机会
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

image.png

为什么可以这样改进?
内存图:
image.png

7.

需求:最后一句
image.png
思路:
首先代码一定是写在while循环之后的,因为抽奖已经结束
首先要知道抽奖箱1和2的奖项的最大值,我们可以使用第三种方式创建多线程,因为call方法有返回值

public class Prize implements Callable<Integer> {
    //定义一个变量
    ArrayList<Integer> list;

    //构造,从main方法传递一个集合过来
    public Prize(ArrayList<Integer> list) {
        this.list = list;
    }

    //用两个变量记录 两个抽奖箱产生中奖次数
    int count1 = 0;
    int count2 = 0;


    @Override
    public Integer call() throws Exception {
        在run方法内创建一个集合,创建多少个线程就会创建多少个相应的集合
        //线程1 //线程2
        ArrayList<Integer> box = new ArrayList<>();
        //循环
        while (true) {
            //同步代码块,确保线程安全
            synchronized (Prize.class) {
                if (list.isEmpty()) {
                    //当奖箱全部获取完了就开始打印
                    if ("抽奖箱1".equals(Thread.currentThread().getName())) {
                        int max = Collections.max(box);
                        System.out.println("抽奖箱1" + box + ":" + count1 + "个奖项,最大值是" + max);
                    } else {
                        int max = Collections.max(box);
                        System.out.println("抽奖箱2" + box + ":" + count2 + "个奖项,最大值是" + max);
                    }
                    break;

                } else {
                    //继续抽奖
                    Collections.shuffle(list);
                    Integer prize = list.remove(0);

                    if ("抽奖箱1".equals(Thread.currentThread().getName())) {
                        box.add(prize);
                        count1++;
                    } else {
                        box.add(prize);
                        count2++;
                    }
                }
            }
            //让当前线程睡一会,给别的线程机会
            Thread.sleep(10);
        }
        ----while循环外
        //抽奖结束,循环结束,返回box中的最大奖项
        //要知道线程一或二的box中的奖项有可能没有,要特别考虑
        if (box.isEmpty()){
            return null;
        }else {
            return Collections.max(box);
        }
        
    }
}

main、

public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建奖池
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);

        //创建多线程要运行的参数对象
        Prize t = new Prize(list);


        //*这里创建俩个FutureTask对象,因为你不知道的是javabean返回的最大值是线程1还是2的,所以创建两个分别管理线程  
        //线程一的任务管理器,接收返回值
        FutureTask<Integer> ft1=new FutureTask<>(t);
        //线程二的任务管理器,接受返回值
        FutureTask<Integer> ft2=new FutureTask<>(t);

        
        //创建线程1、2
        Thread t1=new Thread(ft1);
        Thread t2=new Thread(ft2);

        //设置名字
        t1.setName("抽奖箱1");
        t2.setName("抽奖箱2");

        //启动线程
        t1.start();
        t2.start();

        //调用get方法获取返回值
        //线程1的最大值
        Integer i1 = ft1.get();
        //线程2的最大值
        Integer i2 = ft2.get();
        //打印
        System.out.println(i1+" "+i2);

        if (i1>i2){
            System.out.println("在此次抽奖过程中,抽奖箱1产生了最大奖项,该奖项金额为800");
        }else {
            System.out.println("在此次抽奖过程中,抽奖箱2产生了最大奖项,该奖项金额为800");
        }


    }
}

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/388768.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenSource - 一站式自动化运维及自动化部署平台

文章目录 orion-ops 是什么重构特性快速开始技术栈功能预览添砖加瓦License orion-ops 是什么 orion-ops 一站式自动化运维及自动化部署平台, 使用多环境的概念, 提供了机器管理、机器监控报警、Web终端、WebSftp、机器批量执行、机器批量上传、在线查看日志、定时调度任务、应…

《合成孔径雷达成像算法与实现》Figure6.17

% rho_r c/(2*Fr)而不是rho_r c/(2*Bw) % Hsrcf exp函数里忘记乘pi了 clc clear close all参数设置 距离向参数设置 R_eta_c 20e3; % 景中心斜距 Tr 2.5e-6; % 发射脉冲时宽 Kr 20e12; % 距离向调频率 alpha_os_r 1.2; …

B端系统从0到1:有几步,其中需求分析要做啥?

一款B系统从无到有都经历了啥&#xff0c;而其中的需求分析又要做什么&#xff1f;贝格前端工场给老铁们做一下分析&#xff0c;文章写作不易&#xff0c;如果咱们有界面设计和前端开发需求&#xff0c;别忘了私信我呦&#xff0c;开始了。 一、B端系统从0到1都有哪些要走的步骤…

绝地求生:“觉醒之旅”通行证曝光,西游主题通行证及成长型武器即将上线

随着27赛季即将结束&#xff0c;有关28.1版本的皮肤及通行证内容也被爆料出来&#xff0c;本次通行证为工坊通行证&#xff0c;和去年四圣兽通行证为同一类型&#xff0c;将于2月7日更新至正式服 除了通行证获取工坊币还是可以开箱获取并兑换一些奖励 先看通行证 四个套装应该分…

如何给最小化安装的CentOS主机装个远程桌面?

正文共&#xff1a;888 字 18 图&#xff0c;预估阅读时间&#xff1a;1 分钟 前面我们领微软云Azure的免费主机时&#xff08;白嫖党618福利&#xff01;来Azure领200美刀&#xff01;外加云主机免费用一年&#xff01;&#xff09;&#xff0c;发现“有资格免费试用服务”的主…

【VScode配置HTML如何编译 基础 JavaScript 实例】

基础 JavaScript 实例 VScode用JavaScript输出文本用JavaScript改变HTML元素一个外部JavaScript VScode 打开扩展搜索 右键看到即可 用JavaScript输出文本 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> </head> <body…

《Python入门到精通》webbrowser模块详解,Python webbrowser标准库,Python浏览器控制工具

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 webbrowser模块详解 1、常用操作2、函数大全webbrowser.open() 打开浏览器webbro…

C++面向对象程序设计-北京大学-郭炜【课程笔记(二)】

C面向对象程序设计-北京大学-郭炜【课程笔记&#xff08;二&#xff09;】 1、结构化程序设计结构化程序设计的不足 2、面向对象的程序设计2.1、面向对象的程序设计2.2、从客观事物抽象出类2.3、对象的内存分配2.4、对象之间的运算2.5、使用类的成员变量和成员函数用法1&#x…

java数据结构与算法基础-----位运算-----持续补充

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 刷题过程中&#xff0c;用到什么关于位运算的知识点&#xff0c;就补充什…

【开源】SpringBoot框架开发独居老人物资配送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询社区4.2 新增物资4.3 查询物资4.4 查询物资配送4.5 新增物资配送 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的独居老人物资配送系统&#xff0c;包含了社区档案、…

数据密集型应用系统设计

数据密集型应用系统设计 原文完整版PDF&#xff1a;https://pan.quark.cn/s/d5a34151fee9 这本书的作者是少有的从工业界干到学术界的牛人&#xff0c;知识面广得惊人&#xff0c;也善于举一反三&#xff0c;知识之间互相关联&#xff0c;比如有个地方把读路径比作programming …

医卫答案在哪搜?九个公众号和软件推荐清单! #笔记#笔记#微信

在这个信息爆炸的时代&#xff0c;合理利用学习工具可以帮助我们过滤和获取有用的知识。 1.粉鹿搜题 这是一个公众号 题库包括四六级答案、各学校往期课后答案、期末考试题等&#xff0c;使用比较简单。 下方附上一些测试的试题及答案 1、最有可能担任债券发行受托人的个人…

Tuxera NTFS 2024永久免费版Mac系统NTFS磁盘读写软件

Tuxera NTFS 2024是一款Mac系统NTFS磁盘读写软件&#xff0c;由Tuxera公司开发。该软件可以在Mac上打开、编辑、复制、移动或删除存储在Windows NTFS格式USB驱动器上的文件。对于需要在Mac和Windows之间频繁传输文件的用户来说&#xff0c;Tuxera NTFS 2024无疑是一个方便且高效…

关于内存相关的梳理

1 关键字 总结 &#xff08;lowmemory&#xff0c;anr in&#xff09; 2 知识储备 虚拟机原理 垃圾回收算法 又包含标记 和清除两种算法 标记&#xff1a;程序计数器-已过时&#xff0c;可达性分析 具体可见 http://help.eclipse.org/luna/index.jsp?topic%2Forg.ec…

摸索设计模式的魅力:从策略模式看软件设计的智慧-灵活应对变化的艺术

设计模式专栏&#xff1a;http://t.csdnimg.cn/U54zu 引言 策略模式是一种设计理念&#xff0c;它允许开发者定义一族算法&#xff0c;将每一个算法封装起来&#xff0c;并且让它们可以相互替换。这种模式让算法的变化独立于使用算法的客户端&#xff0c;即程序的其他部分。在软…

如何手机搜保育员答案?9个大学生必备的搜题 #微信#媒体#知识分享

可以说是搜题软件里面题库较为齐全的一个了&#xff0c;收录国内高校常见的计算机类、资格类、学历类、外语类、工程类、建筑类等多种类型的题目。它可以拍照解题、拍照答疑、智能解题&#xff0c;并支持每日一练、章节练习、错题重做等特色功能&#xff0c;在帮助大家解答疑惑…

【深度学习】Pytorch 系列教程(二):PyTorch数据结构:1、Tensor(张量): GPU加速(GPU Acceleration)

文章目录 一、前言二、实验环境三、PyTorch数据结构0、分类1、Tensor&#xff08;张量&#xff09;1. 维度&#xff08;Dimensions&#xff09;2. 数据类型&#xff08;Data Types&#xff09;3. GPU加速&#xff08;GPU Acceleration&#xff09;查看可用gpu张量移动经典语句d…

Ansible file文件模块 设置文件的属性,比如创建文件、创建链接文件、删除文件

目录 语法创建目录创建链接文件删除文件 每个值的属性 语法 创建目录 ansible slave -m file -a path/data/app statedirectory path/data/app # 定义创建路径 statedirectory # 如果目录不存在就创建目录这就是创建目录成功之后的回显 可以看到&#xff0c;已经打印出目录a…

Rust 数据结构与算法:1算法分析之乱序字符串检查

Rust 数据结构与算法 一、算法分析 算法是通用的旨在解决某种问题的指令列表。 算法分析是基于算法使用的资源量来进行比较的。之所以说一个算法比另一个算法好,原因就在于前者在使用资源方面更有效率,或者说前者使用了更少的资源。 ●算法使用的空间指的是内存消耗。算法…