java集合小练习

集合小练习

练习一

需求:班级里有N个学生,学生属性:姓名,年龄,性别。

实现随机点名器。

本题的重要知识点在于快速向一个列表中添加批量的元素。然后在于如何实现随机访问列表中的元素,第一种实现方式可以是利用Random类生成一个随机索引,通过该索引得到元素;第二种方式是使用Collections工具类提供的shuffle方法,每次将列表中的元素顺序打乱,然后访问第一个元素(或者任意一个)即可。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class RandomAccess {
    public static void main(String[] args) {
        /*班级里有N个学生,学生属性:姓名,年龄,性别。
        实现随机点名器。*/

        // 1.定义列表
        List<String> students = new ArrayList<>();
        // 2.添加元素
        Collections.addAll(students, "aaa", "bbb", "ccc", "ddd", "eee",
                "fff", "ggg", "hhh", "iii", "jjj", "kkk");
        // 3-1.通过Random对象随机访问
        Random r = new Random();
        int index = r.nextInt(students.size());
        System.out.println(students.get(index));

        // 3-2.通过Collections工具类访问
        Collections.shuffle(students);
        System.out.println(students.get(0));
    }
}

练习二

班级里有N个学生

要求:

70%的概率随机到男生30%的概率随机到女生

本题的难点在于如何实现抽取的性别按概率分布。Random.nextInt(int bound)方法返回[0,bound)中的一个数(前包后闭),说白了就是随机选取0-99这100个数中的一个,这100个数字中的任意一个被抽中的概率都是相同的。因此可以使用Random.nextInt(100)<30来表示30%的概率,余下就是70%的概率。

可以先按性别定义两个列表,使用Random对象按30-70的概率选择访问女生-男生列表,再使用Collections.shuffle方法洗牌,选择0号索引的元素,即已经实现按指定概率抽取。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class RandomAccessWithOdds {
    public static void main(String[] args) {
        String name = "";
        // ===使用方法1======================================
        // 开始时间
        long bt1 = System.currentTimeMillis();
        int boyCount = 0;
        int girlCount = 0;
        for (int i = 0; i < 100000; i++) {
            name = boyOrGirl1();
            if (name.startsWith("b"))
                boyCount++;
            else if (name.startsWith("g"))
                girlCount++;
        }
        System.out.println("boy被抽中:" + boyCount);
        System.out.println("girl被抽中:" + girlCount);
        System.out.println("耗时(ms)" + (System.currentTimeMillis() - bt1));

        // ===使用方法2==================================
        // 开始时间
        long bt2 = System.currentTimeMillis();
        int boyCount2 = 0;
        int girlCount2 = 0;
        for (int i = 0; i < 100000; i++) {
            name = boyOrGirl1();
            if (name.startsWith("b"))
                boyCount2++;
            else if (name.startsWith("g"))
                girlCount2++;
        }
        System.out.println("boy被抽中:" + boyCount2);
        System.out.println("girl被抽中:" + girlCount2);
        System.out.println("耗时(ms)" + (System.currentTimeMillis() - bt2));

        // ===使用方法3===================================
        // 创建列表
        List<String> boys = new ArrayList<>();
        List<String> girls = new ArrayList<>();
        // 向列表中添加元素
        Collections.addAll(boys, "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "b10");
        Collections.addAll(girls, "g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8", "g9", "g10");
        // 开始时间
        long bt3 = System.currentTimeMillis();
        int boyCount3 = 0;
        int girlCount3 = 0;
        for (int i = 0; i < 100000; i++) {
            name = boyOrGirl3(boys, girls);
            if (name.startsWith("b"))
                boyCount3++;
            else if (name.startsWith("g"))
                girlCount3++;
        }
        System.out.println("boy被抽中:" + boyCount3);
        System.out.println("girl被抽中:" + girlCount3);
        System.out.println("耗时(ms)" + (System.currentTimeMillis() - bt3));
    }

    /**
     * 使用Collections.Shuffle打乱列表实现随机抽取
     * @return 名字
     */
    public static String boyOrGirl1(){
        // 创建列表
        List<String> boys = new ArrayList<>();
        List<String> girls = new ArrayList<>();
        // 向列表中添加元素
        Collections.addAll(boys, "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "b10");
        Collections.addAll(girls, "g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8", "g9", "g10");
        // 创建一个Random对象,
        // 用于概率抽取boysgirls
        Random boyOrGirlRand = new Random();
        // Random.nextInt(int bound)在参数指定内的[0-100)概率相等
        // 因此<30的所有整数的概率就是30%
        // 此外就是70%的概率,从而实现30%/70%的概率分布
        if (boyOrGirlRand.nextInt(100) < 30){
            // 洗牌
            Collections.shuffle(girls);
            // 抽取男孩第一个
            //System.out.println(girls.get(0));
            return girls.get(0);
        }else {
            // 洗牌
            Collections.shuffle(boys);
            // 抽取女孩第一个
            //System.out.println(girls.get(0));
            return boys.get(0);
        }
    }

    /**
     * 使用Random生成随机索引访问元素,从而实现随机选取
     * 此方法相比使用Collections.shuffle效率大幅提高
     * @return 名字
     */
    public static String boyOrGirl2(){
        // 创建列表
        List<String> boys = new ArrayList<>();
        List<String> girls = new ArrayList<>();
        // 向列表中添加元素
        Collections.addAll(boys, "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "b10");
        Collections.addAll(girls, "g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8", "g9", "g10");
        // 创建一个Random对象,
        // 用于概率抽取boysgirls
        Random boyOrGirlRand = new Random();
        // Random.nextInt(int bound)在参数指定内的[0-100)概率相等
        // 因此<30的所有整数的概率就是30%
        // 此外就是70%的概率,从而实现30%/70%的概率分布
        if (boyOrGirlRand.nextInt(100) < 30){
            return girls.get(new Random().nextInt(girls.size()));
        }else {
            return boys.get(new Random().nextInt(girls.size()));
        }
    }

    /**
     * 本方法不创建姓名列表
     * 使用已创建的姓名列表,性能又可以提升很多
     * @param boys 男生姓名列表
     * @param girls 女生姓名列表
     * @return 名字
     */
    public static String boyOrGirl3(List<String> boys, List<String> girls){
        // 创建一个Random对象,
        // 用于概率抽取boysgirls
        Random boyOrGirlRand = new Random();
        // Random.nextInt(int bound)在参数指定内的[0-100)概率相等
        // 因此<30的所有整数的概率就是30%
        // 此外就是70%的概率,从而实现30%/70%的概率分布
        if (boyOrGirlRand.nextInt(100) < 30){
            return girls.get(new Random().nextInt(girls.size()));
        }else {
            return boys.get(new Random().nextInt(girls.size()));
        }
    }
}

本程序三次运行的结果:

第一次:

boy被抽中:69891

girl被抽中:30109

耗时(ms):45

boy被抽中:70021

girl被抽中:29979

耗时(ms):18

boy被抽中:69868

girl被抽中:30132

耗时(ms):10

第二次:

boy被抽中:70085

girl被抽中:29915

耗时(ms):44

boy被抽中:70027

girl被抽中:29973

耗时(ms):19

boy被抽中:69933

girl被抽中:30067

耗时(ms):10

第三次:

boy被抽中:70222

girl被抽中:29778

耗时(ms):43

boy被抽中:69919

girl被抽中:30081

耗时(ms):18

boy被抽中:70020

girl被抽中:29980

耗时(ms):10

练习三

自动点名器3

班级里有N个学生,要求:被点到的学生不会再被点到。但是如果班级中所有的学生都点完了,需要重新开启第二轮点名。

代码如下:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class RandomAccessRepeatly {
    public static void main(String[] args) {
        // 创建一个列表
        List<String> list = new ArrayList<>();
        // 用于存放被删除的元素,用于开启第二轮
        List<String> list2 = new ArrayList<>();

        // 添加元素
        Collections.addAll(list, "唐玄装", "朱棣", "曹操", "刘备",
                "孙权", "张飞", "李世明", "诸葛亮", "刘秀", "董卓");


        // 获取列表大小
        int size = list.size();
        // 创建随机数生成对象
        Random r = new Random();
        // 外循环:指定抽取的轮数
        for (int j = 1; j <= 10; j++) {
            System.out.println("=======" + j + "=========");
            // 内循环:随机抽取列表中的元素
            for (int i = 0; i < size; i++) {
                // 设置随机对象的种子
                r.setSeed(System.nanoTime());
                // size为界生成一个随机索引
                int index = r.nextInt(list.size());
                // 使用remove()方法,移除选中的元素;
                // 该方法返回被删除的元素,使用name接受
                String name = list.remove(index);
                // list2中添加被删除的元素
                list2.add(name);
                // 输出name
                System.out.println(name);
            }
            // 添加list2
            list.addAll(list2);
            // 清空list2
            list2.clear();
        }
    }
}

练习四

TxT文件中事先准备好80个学生姓名,每个学生的名字独占一行。

要求1:每次被点到的学生,再次被点到的概率在原先的基础上降低一半。举例:80个学生,点名5次,每次都点到小A,概率变化情况如下:

第一次每人概率:1.25%。

第二次小A概率:0.625%。

其他学生概率:1.2579%

第三次小A概率:0.3125%。

其他学生概率:1.261867%

第四次小A概率:0.15625%。

其他学生概率:1.2638449%

第五次小A概率:0.078125%。

其他学生概率:1.26483386%

要求2:作弊要求,第三次点名一定是张三。

提示:本题需要用到集合,IO,权重随机算法,有基础的同学可以试试,0基础的同学等IO学完之后再做。

练习五

定义一个Map集合,键用表示省份名称province,值表示市city,但是市会有多个。添加完毕后,遍历结果格式如下:

江苏省=南京市,扬州市,苏州市,无锡市,常州市

湖北省=武汉市,孝感市,十堰市,宜昌市,鄂州市

河北省=石家庄市,唐山市,邢台市,保定市,张家口市

代码如下:

import java.util.*;

public class ProvinceNCities {
    public static void main(String[] args) {
        //Map<String, List<String>> pnc1 = new HashMap<>();
        // 定义Map对象
        HashMap<String, ArrayList<String>> pnc = new HashMap<>();

        // 添加省份 江苏
        ArrayList<String> js = new ArrayList<>();
        js.add("南京市");
        js.add("扬州市");
        js.add("苏州市");
        js.add("无锡市");
        js.add("常州市");

        // 添加省份 湖北
        ArrayList<String> hb = new ArrayList<>();
        hb.add("武汉市");
        hb.add("孝感市");
        hb.add("十堰市");
        hb.add("宜昌市");
        hb.add("鄂州市");

        // 添加省份 河北
        ArrayList<String> heb = new ArrayList<>();
        heb.add("石家庄市");
        heb.add("唐山市");
        heb.add("邢台市");
        heb.add("保定市");
        heb.add("张家口市");

        // 将数据放入HashMap
        pnc.put("江苏省", js);
        pnc.put("湖北省", hb);
        pnc.put("河北省", heb);
        //System.out.println(pnc);

        // 通过EntrySet访问
        Set<Map.Entry<String, ArrayList<String>>> entries = pnc.entrySet();

        for (Map.Entry<String, ArrayList<String>> entry : entries) {
            //System.out.println(entry.getKey());
            // sj用户字符串拼接
            StringJoiner sj = new StringJoiner(",", entry.getKey() + " = ", "");
            // 遍历得到的城市名
            for (String s : entry.getValue()) {
                sj.add(s);
            }
            // 输出得到的最终字符串
            System.out.println(sj);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐骁虎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值