大家好,我是三叔,很高兴这期又和大家见面了,一个奋斗在互联网的打工人。
劳动最光荣,笔者祝大家五一假期快乐!
不废话,上代码:
当存在两个嵌套的 for 循环时,时间复杂度将取决于循环嵌套的层数和循环内部执行的操作。如果内部操作的时间复杂度是 O(1),则两个 for 循环的时间复杂度为 O(n^2),其中 n 是集合中元素的数量。以下是两个list的嵌套循环,它计算了两个集合的笛卡尔积:
public static void main(String[] args) {
// 主题类list
List<TopicVO> topicList = Arrays.asList(
new TopicVO(1, 10, "主题1"),
new TopicVO(2, 20, "主题2"),
new TopicVO(3, 30, "主题3")
);
// 事件类list
List<EventVO> eventList = Arrays.asList(
new EventVO(1, 10, "事件1"),
new EventVO(2, 20, "事件2"),
new EventVO(3, 30, "事件3")
);
// 比较赋值操作
topicList.stream().forEach(topicVO -> {
eventList.stream().forEach(eventVO -> {
if (topicVO.getId() == eventVO.getId() && topicVO.getName().equals(eventVO.getName())) {
// 如果满足上面的条件,就把topicVo的age字段赋值给eventVo的age字段
eventVO.setAge(topicVO.getAge());
}
});
});
}
笔者在开过过程中,由于业务逻辑的需要,需要对两个list进行遍历,取出符合判断条件的值,赋值到另一个对象,所以两个for循环就能解决问题。但是在随着测试数据的日积月累,数据量越来越大,这个接口的responseTime时间开始增加了,于是笔者在排查的过程中,就发现了这两个for循环“嫌疑”很大。
在 Java 集合中,单个 for 循环的时间复杂度通常是 O(n),而两个嵌套的 for 循环的时间复杂度可能是 O(n^2) 或更高,具体取决于循环嵌套的层数和内部操作的时间复杂度。
list转map,时间复杂度降低到O(n)
笔者处理逻辑需要和最外层的集合进行比较,所以这里把最外层的list使用Java8进行list转map(笔者这篇文章介绍了如何使用:Java8list转map)
上代码:
public static void main(String[] args) {
List<TopicVO> topicList = Arrays.asList(
new TopicVO(1, 10, "主题1"),
new TopicVO(2, 20, "主题2"),
new TopicVO(3, 30, "主题3")
);
List<EventVO> eventList = Arrays.asList(
new EventVO(1, 10, "事件1"),
new EventVO(2, 20, "事件2"),
new EventVO(3, 30, "事件3")
);
// 之前的判断逻辑是同时满足两个条件才进行赋值操作,因为笔者的id和name字段能保证全局绝对的唯一,所以这里笔者将拼接属性作为唯一key
// key: id + name
// value: age
Map<String, Integer> topicMap
= topicList.stream().collect(Collectors.toMap(vo -> vo.getId() + vo.getName(), TopicVO::getAge));
// 重点在这里
for (EventVO eventVO : eventList) {
// 拼接新的key,如果key在map中,获取到map对象取到值(因为map的value就是我们需要的值,所以直接get(key)就可以拿到value值)
String newKey = eventVO.getId() + eventVO.getName();
if (topicMap.containsKey(newKey)) {
eventVO.setAge(topicMap.get(newKey));
}
}
}
这样,两层for循环,笔者通过list转map,成功让这两层for循环的时间复杂度降低了一个量级,避免了笛卡尔积,并且代码也变得整洁起来。
思考:map效率一定比list高吗
对于 List 和 Map 的遍历,它们的效率取决于具体的使用场景。一般情况下,如果你只是需要简单地遍历所有元素,那么 List 的遍历会更加高效。这是因为 List 的内部数据结构是一个数组,所以它的遍历速度会比 Map 的遍历速度快一些。
但是,如果你需要在遍历的过程中进行查找、删除、更新等操作,那么 Map 的遍历会更加高效。这是因为 Map 内部使用了哈希表的数据结构,它可以通过 key 快速定位到对应的 value,而 List 的查找、删除、更新等操作都需要遍历整个列表,效率相对较低。
总之,对于 List 和 Map 的遍历,要根据具体的使用场景来选择。如果只是简单的遍历,选择 List 会更加高效;如果需要进行复杂的操作,选择 Map 会更加高效。