java用集合类求数组交并集_Java实现数组去重和两数组交并集

前言

Java平台

数组去重

基本的数组去重法

HashMap实现数组去重

两数组交集

基本的两数组求交法

HashMap版的两数组求交法

两数组并集

基本的两数组求并法

HashMap版的两数组求并法

Matlab平台

Matlab处理数组去重

Matlab求两数组交集

Matlab求两数组并集

后记

前言

前几天,有人问我两数组的交并集如何实现,我当时回复是使用HashMap进行操作。转念一想,这是个数学问题,那就必须得看看Matlab源码是如何实现,发现都是通过数组去重实现,因此我索性就将这三者混在一起,写篇博客。

Java平台

在Java平台处理数组问题,大多数都是遍历数组,然后逐数据处理。对于陌生问题,我们处理的方式都是先解决问题,再优化解决问题的方式,因此,大多数算法都会有简单(能处理问题,但是效率比较低)的算法和优化版本的算法。下面我也是先给出我自己的基本处理方法,再通过思考进而实现它的优化算法。

数组去重

基本的数组去重法

对于数组去重,其实我们可以像冒泡排序一般,逐个比较,非重复我就装在另一个unique数组中,如果这个数据有重复,我就查看unique数组是否已经包含你,包含了,就忽略,不包含,就将该数据也装进unique数组中。Talk is cheap. 代码如下:

public static int[] unique(int[] array){

int len = -1;

if(array == null || (len = array.length) < 2){

return len == -1 ? null : Arrays.copyOf(array, len);

}

int[] uniqueArray = new int[len];

int uniqueCount = 0;

outer:

for(int value : array){

for(int i = 0; i < uniqueCount; i++){

if(uniqueArray[i] == value){

continue outer;

}

}

uniqueArray[uniqueCount++] = value;

}

uniqueArray = Arrays.copyOf(uniqueArray, uniqueCount);

Arrays.sort(uniqueArray); // These unique values in array are in disorder.

return uniqueArray;

}

HashMap实现数组去重

观察数组去重后的最终结果,发现所有数据都互不相同(这句话是废话,不然怎么叫去重呢,哈哈哈!),如果我们能保证我们最终结果的各数据都互不相同,且涵盖原先数组的所有值,这问题就解决了。涵盖数组所有值,通过遍历,倒是好解决,如何使最终结果的各数据都互不相同,此时我们要想到什么数据结构能保证数据的唯一性,脑袋里面瞬间反应就是二叉树和哈希表,进而想想Java集合库有没有这两种数据结构的实现,没有就自己造轮子,查了查,倒是有很多,比如二叉树就有TreeMap和TreeSet,哈希表的就有HashMap、HashSet和HashTable,至于并发包里面的就先不考虑了,暂时我们还没涉及并发处理的情况。所有我们只要从这上面随便选一种就可以了。看标题就知道,我选择哈希表中的HashMap来实现数组的唯一化。代码如下:

public static int[] unique(int[] array){

int len = -1;

if(array == null || (len = array.length) < 2){

return len == -1 ? null : Arrays.copyOf(array, len);

}

HashMap uniqueMap = new HashMap<>(); // No certain, no initial

for(int value : array){

uniqueMap.put(value, null); // Equivalent to HashSet

}

int uniqueNums = uniqueMap.size();

int[] uniqueArray = new int[uniqueNums];

for(Integer key : uniqueMap.keySet()){

uniqueArray[--uniqueNums] = key;

}

Arrays.sort(uniqueArray); // For sequenced array

return uniqueArray;

}

两数组交集

基本的两数组求交法

对于两数组求交集,其实处理原理和冒泡排序法差不多,一个数组逐个比较另一个数组的所有值,找到相同的了,就看unique数组是否包含该值,包含,就忽略,不包含,就直接添加。代码如下:

public static int[] intersect(int[] aArray, int[] bArray){

if(aArray == null || bArray == null){

return null;

}

int aLen = 0, bLen = 0;

if((aLen = aArray.length) == 0 || (bLen = bArray.length) == 0){

return new int[0];

}

int intersectLen = (aLen > bLen) ? bLen : aLen;

int[] intersectArray = new int[intersectLen];

int iCount = 0;

for(int aValue : aArray){

boolean isContain = false;

for(int bValue : bArray){

if(aValue == bValue){

isContain = true;

break;

}

}

if(isContain){

boolean isExist = false;

for(int i = 0; i < iCount; i++){

if(intersectArray[i] == aValue){

isExist = true;

break;

}

}

if(!isExist){

intersectArray[iCount++] = aValue;

}

}

}

intersectArray = Arrays.copyOf(intersectArray, iCount);

Arrays.sort(intersectArray);

return intersectArray;

}

HashMap版的两数组求交法

求两个数组的交集,如果先对某个数组实现去重,再另外一个数组与之逐个比较,有相等的值,那该值就可以添加到交集中。也是利用带唯一性数据结构来解决该问题。这次依旧使用HashMap来实现该算法,代码如下:

public static int[] intersect(int[] aArray, int[] bArray){

if(aArray == null || bArray == null){

return null;

}

int aLen = 0, bLen = 0;

if((aLen = aArray.length) == 0 || (bLen = bArray.length) == 0){

return new int[0];

}

HashMap intersectMap = new HashMap<>();

for(int aValue : aArray){

intersectMap.put(aValue, true);

}

int intersectLen = (aLen > bLen) ? bLen : aLen;

int[] intersectArray = new int[intersectLen];

int iCount = 0;

for(int bValue : bArray){

Boolean isAdd = intersectMap.get(bValue);

if(isAdd != null && isAdd){ // Can only be added once.

intersectArray[iCount++] = bValue;

intersectMap.put(bValue, false);

}

}

intersectArray = Arrays.copyOf(intersectArray, iCount);

Arrays.sort(intersectArray);

return intersectArray;

}

两数组并集

基本的两数组求并法

求并集相当于对两个数组分别求unique,再剔除两unique数组的交集。代码如下:

public static int[] union(int[] aArray, int bArray){

int aLen = 0;

if(aArray == null || (aLen = aArray.length) == 0){

return unique(bArray);

}

int bLen = 0;

if(bArray == null || (bLen = bArray.length) == 0){

return unique(aArray);

}

int unionLen = aLen + bLen; // May throw OutOfMemoryError or NegativeArraySizeException

int[] unionArray = new int[unionLen];

int uCount = 0;

outer:

for(int aValue : aArray){

for(int i = 0; i < uCount; i++){

if(unionArray[i] == aValue){

continue outer;

}

}

unionArray[uCount++] = aValue;

}

outer:

for(int bValue : bArray){

for(int i = 0; i < uCount; i++){

if(unionArray[i] == bValue){

continue outer;

}

}

unionArray[uCount++] = bValue;

}

unionArray = Arrays.copyOf(unionArray, uCount);

Arrays.sort(unionArray);

return unionArray;

}

HashMap版的两数组求并法

对两数组求并也可以看做是对这两个数组所组成的大数组求unique。同样使用HashMap处理,代码如下:

public static int[] union(int[] aArray, int[] bArray){

if(aArray == null || aArray.length == 0){

return unique(bArray);

}

if(bArray == null || bArray.length == 0){

return unique(aArray);

}

HashMap unionMap = new HashMap<>();

for(int aValue : aArray){

unionMap.put(aValue, null);

}

for(int bValue : bArray){

unionMap.put(bValue, null);

}

int unionLen = unionMap.size();

int[] unionArray = new int[unionLen];

for(int key : unionMap.keySet()){

unionArray[--unionLen] = key;

}

Arrays.sort(unionArray);

return unionArray;

}

Matlab平台

Matlab内部的矩阵运算全部都是用针对特定CPU在汇编级别优化过的矩阵运算库实现的,所以该语言效率的主要体现在矩阵化操作,而Java唯一的优势就是循环(只是相对于Matlab来说)。Matlab的算法思想主要是围绕矩阵化操作来展开,并且对循环处理极为排斥(随着版本更新,循环问题好了点。),因此有些习惯类C型语言的人反而会写出超低效率的Matlab代码。接下来我们就来看看Matlab是如何处理上面的这些问题的,虽然我是用Java实现,但矩阵化思想依然保留其中。

Matlab处理数组去重

算法思路:该算法利用了差分来剔除重复值。首先对数组进行排序,初始化长度为数组长度的boolean数组diff来保存数据的差分信息,如果差分等于0,说明该值重复,diff数组在此记作false,不等于零则记作true。最后遍历diff数组,将为true值下标的值添加到unique数组。再把第一个数添加其中(第一个数肯定与前面不重复),最后为了让结果好看,排序unique数组即可。

public static int[] unique(int[] array){

int len = -1;

if(array == null || (len = array.length) < 2){

return len == -1 ? null : Arrays.copyOf(array, len);

}

array = Arrays.copyOf(array, len); // Avoid polluting the original array.

Arrays.sort(array);

boolean[] diffs = new boolean[len];

diffs[0] = true;

int uCount = 1;

for(int i = 1; i < len; i++){

if(array[i] != array[i - 1]){

uCount++;

diffs[i] = true;

}

}

int[] uniqueArray = new int[uCount];

for(int i = 0, index = 0; i < len; i++){

if(diffs[i]){

uniqueArray[index++] = array[i];

}

}

return uniqueArray;

}

Matlab求两数组交集

算法思路:该算法依旧是利用了差分的性质,只不过这次比较隐蔽。它首先把两数组a和b都进行unique操作,得到两个unique数组,再将这两个数组拼接在一起,对其排序,得到数组c,如果a和b有交集2,那么数组c中一定有两个挨着的2,因此数组c中所有相邻且相等的数值(差分值等于0)都是数组a和b的交集。代码如下:

public static int[] intersect(int[] aArray, int bArray){

if(aArray == null || bArray == null){

return null;

}

if(aArray.length == 0 || bArray.length == 0){

return new int[0];

}

int[] uA = unique(aArray);

int[] uB = unique(bArray);

int uaLen = uA.length;

int ubLen = uB.length;

int uabLen = uaLen + ubLen;

int[] sortuAuB = new int[uabLen]; // // May throw OutOfMemoryError and NegativeArraySizeException.

System.arraycopy(uA, 0, sortuAuB, 0, uaLen);

System.arraycopy(uB, 0, sortuAuB, uaLen, ubLen);

Arrays.sort(sortuAuB);

int indInterABLen = uaLen > ubLen ? ubLen : uaLen;

int[] indInterAB = new int[indInterABLen];

int iCount = 0;

for(int i = 1; i < uabLen; i++){

if(sortuAuB[i] == sortuAuB[i - 1]){

indInterAB[iCount++] = sortuAuB[i++]; // The next absolutely unequal.

}

}

return Arrays.copyOf(indInterAB, iCount);

}

Matlab求两数组并集

算法思路:把两个数组拼接起来,所有工作全交由unique处理,哈哈哈!

public static int[] union(int[] aArray, int[] bArray){

int aLen = 0;

if(aArray == null || (aLen = aArray.length) == 0){

return unique(bArray);

}

int bLen = 0;

if(bArray == null || (bLen = bArray.length) == 0){

return unique(aArray);

}

int abLen = aLen + bLen;

int[] unionAB = new int[abLen]; // // May throw OutOfMemoryError and NegativeArraySizeException

System.arraycopy(aArray, 0, unionAB, 0, aLen);

System.arraycopy(bArray, 0, unionAB, aLen, bLen);

return unique(unionAB); // Call unique to do all the work.

}

后记

虽然看起来Java平台处理的代码思路和Matlab平台处理的大相径庭,但细想起来其实是处理数据方式造成的差异。Java拥有唯一性数据的数据结构,因此直接使用这种数据结构就能解决问题,而Matlab并无这些复杂的数据结构,只有矩阵操作,因此它想要获取数据的唯一性信息,就只能通过排序和差分来实现。综上来看,这三类问题都是通过数据的唯一性来解决。

这一篇博文没有任何引用,主要是因为我当时利用唯一性,很快就写完这些算法了,并且进行单元测试还没有问题,由于时间的关系就没有参考别人的博文。这三个基本法是我写博文时,临时加上去的,当时只是想写Java平台和Matlab平台代码思路的对比,并没考虑这么多,后来想了想还是加上去了。当时写的时候,脑袋里面全是用唯一性进行处理,最后强迫自己,只能用最基本矩阵操作来实现,才写出这三个基本法,哎,竟然被自己知道的东西所限制,头疼!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值