JAVA:如何优化两个For循环的嵌套查询,从24秒优化到0.3秒

如何优化两个For循环的嵌套查询?

我们先来看看业务场景,我做了一个小模拟:

首先有十万条学生的信息,以及三万条老师的信息。老师与学生都有两个 属性,一个是token 一个是 id。
现在业务如下 我需要将拥有相同id的老师的token赋值给学生
eg: 老师id=1 学生id=1  那么就把老师token给学生

我们先看一下学生和老师的类:

//这里用了lombok 没有的请自己生成get和set还有构造函数
@Data
@AllArgsConstructor
public class Student {
    private String token;
    private Integer id;
}
//老师的
@Data
@AllArgsConstructor
public class Teacher {
    private String token;
    private Integer id;
}

然后我们来赋值:

public static void main(String[] args) {
    long stime = System.currentTimeMillis();
    List<Student> students = new ArrayList<Student>();
    List<Teacher> teachers = new ArrayList<Teacher>();
    // 业务场景如下  首先有十万条学生的信息,以及三万条老师的信息。
    // 老师与学生都有两个 属性 一个是token 一个是 id
    // 现在模拟赋值 将i的值赋给id token的值由UUID生成
    for(int i = 0; i < 100000; i++){
        Student student = new Student(UUID.randomUUID().toString(),i);
        students.add(student);
    }
    for(int i = 0; i < 30000; i++){
        Teacher teacher = new Teacher(UUID.randomUUID().toString(),i);
        teachers.add(teacher);
    }
    //到此为止 执行时间为:278 毫秒
}

现在业务如下 我需要将拥有相同id的老师的token赋值给学生
eg:老师id=1 学生id=1 那么就把老师token给学生 

那么如何实现上述业务呢? 我们总共有三个方法 。先看方法一:

方法一:两个For循环,然后查找

for (Student student : students) {
    for (Teacher teacher : teachers) {
        if(teacher.getId().equals(student.getId())){
            student.setToken(teacher.getToken());
            //执行时长:24401 毫秒
        }
    }
}

 哦吼,执行时常将近25s,这能忍吗?这不能忍!!!!

方法二:返回Break(!此方法适用于 仅有一个相同的 例如不能有两个学生的id都与老师相同)

/**
 * 增加break
 * 此方法适用于 仅有一个相同的 例如不能有两个学生的id都与老师相同
 */
for (Student student : students) {
    for (Teacher teacher : teachers) {
        if(teacher.getId().equals(student.getId())){
            student.setToken(teacher.getToken());
            break;
            //执行时长:7580 毫秒.
        }
    }
}

emmmm,七秒钟,优化了将近三倍,但是还是接受不了,区区从十万条数据中查找三万条就花了七秒,那百万级别的还不得宕机啊,还是不能忍。

/**
 * 使用map
 * 可以把需要操作的list转化为map
 * 需要操作:我们需要把 老师的id作为键  把token作为值
 *          然后我们以学生id为查找的get(index)
 */
Map<Integer, String> teacherMap = teachers.stream().collect(Collectors.toMap(s -> s.getId(), s -> s.getToken()));
int count=0;
for (Student student : students) {
    if(teacherMap.get(student.getId())!=null && !teacherMap.get(student.getId()).equals("")) {
        count++;//30000
        System.out.println("执行的token:"+teacherMap.get(student.getId()));
        student.setToken(teacherMap.get(student.getId()));
        //执行时长:347 毫秒
    }
}

可以从执行结果看到,不到0.5秒就完成了,这就是非常能接受了,那想想为什么?

那我们从时间复杂度分析一下:第一种将近n^{2}的时间复杂度,把每一个元素都比一下,慢是自然的。
那Map的底层结构我们众所周知,从8开始他就是数组+链表的形式,map的取值效率在多数的情况下是能维持接近O(1) 的,所以用map那是嘎嘎快。

今天分析到此结束,学会一个小知识,希望以后能用得上
代码记得动手敲,喜欢就请点个赞!!

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值