JAVA代码一样能够经过合理运用数据结构和算法的特色实现SQL中的大部分操做,例如:JOIN ON ,WHERE ,UNION ,IN/NOT IN ,GROUPBY ,TOP ,LIMIT 等等java
大数据量的 去重、交并差.....等集合操做,均可以适当借助中间容器实现,而且合理运用不一样的数据结构的特色作中间容器,能够大大提升效率优化时间复杂度。尽量避免循环嵌套的遍历,形成倍数级别(n行 x m行)的时间复杂度。注意根据须要重写hashcode()和equals()。还要考虑中间容器构造的时间和空间消耗算法
JDK提供了一些原生方法:retainAll,addAll,removeAll,可是有些效率通常sql
数据结构的特色:Hash、Tree结构适合查找频繁的场景,Array结构适合随记、下标访问,Set能够去重等等,堆作TOP。数据库
List<List/Set/Map/Object>,Map<key,List/Set/Map/Object> 将相同特性的放在一个List中,实现一KEY多值、分组等。方便查找过滤分组。以及实现相似矩阵等更复杂数据结构数据结构
在合适的场景也能够加入多线程处理提升速度。多线程
例如:并发
如下只是我的意见,有其余更好思路但愿你们留言数据结构和算法
求两个List的交集/差集/查重: 其核心是查找,能够借助HashSet/Map将大List放入其中做为查询字典,另外一个List去HashSet中查找是否存在。此思路借助HASH表结构完成查找,避免循环嵌套的遍历,提升了对比效率。工具
求两个List的彻底差集:能够借助Map,将大List做为K放入其中,V记录出现次数。另外一个List去Map中查找,存在则更新V=2,不存在则做为K放入其中。最后只须要找出Map中V为1的K。测试
给List<User>按照年龄分组:遍历List<User> 保存到HashMap<age,List<User>>中。分组后的值为HashMap.values()=List<List<User>>。JDK8可直接使用Stream分组
用Java代码替换Sql语句:有时考虑到数据库压力和并发问题,只能执行简单的Sql语句返回基础表数据。这时须要在Java的Service层中处理这些原始数据List,代替SQL中的操做。
Distinct:去重。将List保存到Set中实现去重。
Sum:统计出现次数。能够借助HashMap<T,Integer> 结构,遍历List<T>去查找HashMap中更新Integer++。
In/Not in: 求交集差集,其核心是查找,能够借助HashSet/Map将大List放入其中做为查询字典,另外一个List去HashSet中查找是否存在。此思路借助HASH表结构完成查找,避免循环嵌套的遍历,提升了对比效率。
Where:至关于过滤集合。推荐Guava库提供的过滤方法。
Groupby:分组。JDK8可直接使用Stream分组,或经过Map<分组id,List>结构保存。
Join:关联(一对一,一对多),能够将做为查询字典的集合放入HashMap中,key做用Join On关联条件,查找并更信息相应属性值/引用。若是是多条件关联,能够考虑条件合并,或是map嵌套Map<on条件1,Map<on条件2,表Object>>
class 主表Object{ 子表Object obj; //一对一 List<子表Object> list; //一对多 }
一对多方案:
方案1:HashMap字典主表List。将List<主表Object>放入HashMap<on条件,主表Object>中。遍历List<子表Object>,经过on条件从HashMap中找到主表Object,并放入其List<子表Object>中。
经测试:主表4万,子表8万数据量,子表无索引。 使用java与原生sql执行join对比,记录从查询到完成时间差。java速度没有不慢于sql。
方案2:HashMap分组子表List。与方案1思路类似,只是改为Map分组子表,将List<子表Object>分组为Map<on条件,List<子表Object>>结构,遍历List<主表Object>去分组后的Map中找对应List。
方案3:过滤子表List。遍历List<主表Object>,按on条件使用Guava库方法过滤List<子表Object>,放入主表Object中。
方案4:同步下标遍历。假设工号为关联条件,ArrayList<主表Object>和List<子表Object> 都按照工号排序,用一个int index=0记录ArrayList<主表Object>当前下标。遍历List<子表Object>,把子表Object放入ArrayList<主表Object>.get(index)中。当判断 子表Object.工号<>ArrayList<主表Object>.get(index).工号 时下移主表下标 index++。这样只须要遍历List<子表Object>和ArrayList<主表Object>都只遍历一次。前提是主/子都按照相同条件顺序排序。
//方案4 伪代码 //一对多场景下,主表为小表 List<主表Object> list1; //按照id排序 List<子表Object> list2; //按照id排序 主表Object o1; 子表Object o2; int sub_index=0; Iterator iter1 = list1.iterator(); //外循环小表 while(iter1.hasNext()){ o1 = (主表Object) iter1.next(); while(sub_index<list2.size()){ o2=list2.get(sub_index); //取得子表当前下标位置元素 if (o2.getid().equals(o1.getid())){ //判断关联条件 o1.getSubList.add(o2); sub_index++; //更新子表当前下标 }else{ break; } } }
频繁须要查询的集合最好使用Hash、Tree结构保存
Top K 问题
其本质上是排序问题,经常使用思路:快速排序(求小 左递归,求大 右递归)、堆排序(适合大数据量) .。
堆排序虽然自己速度没有快排和归并这种分治排序快,可是当统计外部大数据量时,求TOP K只须要创建容量为K的堆,很是节省内存开销。
JAVA中PriorityQueue 优先级队列是小根堆结构,可是能够经过comparator自定义大小,转换成大根堆模式。
PriorityQueue(int initialCapacity,Comparator<? super E> comparator)
集合第三方JAR推荐
google.Guava , Apache Commons Collections 包含不少高效的集合操做API和新类型的数据结构。
推荐Guava,经测试平均执行效率高于JDKAPI(Lists,Sets,Maps,Collections2等工具类中提供了包括集合交并差过滤等多种高效操做)。并且除了集合,还有不少高效简单的工具类,涉及String,Object,I/O等等
https://blog.csdn.net/dgeek/article/details/76221746