在工作中,经常性的会出现在两张表中查找相同id的数据,许多开发者会使用两层for循环嵌套,虽然实现功能没有问题,但是效率极低,一下是一个简单的优化过程,代码耗时凑从26856ms优化到了748ms。
功能场景
有两份list类型的数据,分别是uestlist(用户表)和accountlist(账户表),要根据用户的id从accountlist表中查找对应的账户信息,并进行后续的处理,示例如下:
存数据(伪代码):5w条user数据,3w条account数据
@data class user{ private long userid; private string name; } @data class account{ private long userid; private string content; } public class nestedloopoptimization{ public static list<user> getuserlist(){ list<user> users =new arraylist<>(); for(inti =1; i <=50000; i++) { user user =newuser(); user.setname(uuid.randomuuid().tostring()); user.setuserid((long) i); users.add(user); } return users; } public static list<usermemo> getaccounttestlist(){ list<account> accountlist =newarraylist<>(); for(inti =30000; i >=1; i--) { account account =new account(); account.setcontent(uuid.randomuuid().tostring()); account.setuserid((long) i); accountlist.add(account); } return accountlist; } // ... 后续代码
最直接的实现方式(未优化的代码):
public static void nestedloop(list<user> userslist, list<usermemo> accountlist) { for (user user : userslist) { long userid = user.getuserid(); for (account account : accountlist) { if (userid.equals(account.getuserid())) { string content = account.getcontent(); // system.out.println("模拟数据content 业务处理......" + content); // 避免打印影响测试结果 } } } }
耗时:约数万毫秒,效率很低,数据量小的话无关紧要,如果随着系统的迭代数据量骤增的时候,就会极其耗时。
第一步优化:添加break
每个userid在accountlist中只有一条对应的数据,所以找到匹配项之后就可以跳出内循环:
public static void nestedloop(list<user> userslist, list<usermemo> accountlist) { for (user user : userslist) { long userid = user.getuserid(); for (account account : accountlist) { if (userid.equals(account.getuserid())) { string content = account.getcontent(); // system.out.println("模拟数据content 业务处理......" + content); // 避免打印影响测试结果 break; } } } }
第一步优化结束之后任需要很多耗时,但是比起嵌套循环好很多。
第二步优化:使用map优化
public static void mapoptimizedloop(list<user> usertestlist, list<usermemo> accountlist) { map<long, string> contentmap = accountlist.stream().collect(collectors.tomap(usermemo::getuserid, usermemo::getcontent)); for (user user : usertestlist) { long userid = user.getuserid(); string content = contentmap.get(userid); if (stringutils.haslength(content)) { // system.out.println("模拟数据content 业务处理......" + content); // 避免打印影响测试结果 } } }
做以上优化之后,耗时显著减少,通常在数百毫秒级别。
原理:
两层 for 循环嵌套的时间复杂度为 o(n*m),其中 n 和 m 分别为两个列表的长度。使用 map 后,get 操作的时间复杂度接近 o(1),整体时间复杂度降为 o(n+m),避免了内循环的重复遍历。hashmap 的 get 方法内部使用了 getnode 方法来查找键值对。getnode 方法利用哈希表结构,快速定位到目标键值对。虽然在极端情况下(所有键的哈希值都相同),getnode 的时间复杂度会退化为 o(n),但在实际应用中,哈希冲突的概率很低,hashmap 的 get 操作效率通常很高。因此无需过于担心 o(n) 的最坏情况。
通过以上优化之后,可以显著的提高代码的执行效率,已经其健壮性,尤其是在处理大数据量的时候,使用map优化,可以带来巨大的性能提升,避免了不必要的计算,从而实现了代码的性能。
到此这篇关于java双重for循环的优化示例的文章就介绍到这了,更多相关java双重for循环内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论