Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何以最快的方式使两个排序数组相交?_Java_Arrays_Algorithm_Sorting_Merge - Fatal编程技术网

Java 如何以最快的方式使两个排序数组相交?

Java 如何以最快的方式使两个排序数组相交?,java,arrays,algorithm,sorting,merge,Java,Arrays,Algorithm,Sorting,Merge,我有两个巨大的排序数组(每个大约10万个项目)。我需要非常快地将它们相交。现在我用标准的方法来做: 如果a[i]b[j],那么j++ 其他:向交点添加[i],i++,j++ 但它需要太长时间(约350微秒)才能完成,这导致整体性能非常差。有没有办法做得更快 p.S.交叉点大小不大于1000个项目(平均),我只需要25到100个项目。并行运行2个100k数组需要大约200k个比较。您当前正在以350微秒=350k纳秒的速度完成它。因此,每次比较的时间不到2纳秒。如果您的CPU大约为4GHz,那

我有两个巨大的排序数组(每个大约10万个项目)。我需要非常快地将它们相交。现在我用标准的方法来做:

  • 如果a[i]
  • 如果a[i]>b[j],那么j++
  • 其他:向交点添加[i],i++,j++
但它需要太长时间(约350微秒)才能完成,这导致整体性能非常差。有没有办法做得更快


p.S.交叉点大小不大于1000个项目(平均),我只需要25到100个项目。

并行运行2个100k数组需要大约200k个比较。您当前正在以350微秒=350k纳秒的速度完成它。因此,每次比较的时间不到2纳秒。如果您的CPU大约为4GHz,那么这就是8个时钟周期

那很好。你可以尝试变得老练,检测运行情况等等,但可能管道暂停会比节省工作更伤你自己

只有两种方法可以加快速度。减少工作量,或增加工人

你已经表明减少工作是可行的,这就是为什么塔马斯·黑格达斯建议这样做。不要创建交集,而是创建一个
迭代器
,该迭代器将返回交集中的下一个内容。这将要求您重写使用上述迭代器的逻辑,但您将在当前计算的10%以下完成。这将快近10倍

至于添加工作线程,您需要在工作线程之间分配工作,并防止它们相互重叠。对于
k
较小(不大于您的CPU数量!),且工作量与数组大小成对数关系的情况,您可以执行quickselect来查找
k-1
值,这些值将组合数组分解为
k
偶数块(oops调整,而不是执行quickselect…),以及每个数组中这些值的索引。这就产生了难度相等的
k
问题,每个问题可以指定为4个数字。旋转
k
线程,让每个线程都得到一大块答案。这将比您当前所做的大约快
k

在付出更多努力的情况下,这些方法可以结合起来。您要做的是让迭代器创建(比如)4个worker,并向每个worker分发块。当您调用
iter.next()
时,迭代器将为您提供它拥有的下一个值(如果有)。如果没有,它将等待正在生成下一个块的工人完成,抓取该块,如果一个工人准备好了,则将另一个块交给该工人,然后将该块中的第一个值交给他。你可以玩方块大小。您希望它足够大,以便CPU能够很好地确定它应该从RAM流到CPU缓存,并且不认为线程之间存在同步争用


我猜,考虑到规模和同步限制,混合方法与迭代器方法相比不会有多大的优势(如果有的话)。但是如果你真的很绝望,你可以试试。

我发布了一个问题/解决方案的简单实现:2个数组填充了随机整数。如果达到100个相交值的阈值,循环将中断

一个使用OP逻辑进行循环。另一个启动两个线程,每个线程处理数组的一半

线程开销似乎是个问题。或者它可能需要微调

这是一个20次的样本。最坏情况:没有强制运行到阵列末端的交叉点。时间以微秒为单位

Workers: 2806
Workers: 4197
Workers: 4235
Workers: 818
Workers: 729
Workers: 3376
Workers: 740
Workers: 688
Workers: 2245
Workers: 732
Workers: 330
Workers: 945
Workers: 605
Workers: 630
Workers: 630
Workers: 334
Workers: 643
Workers: 309
Workers: 290
Workers: 761
done
Sorted: 1525
Sorted: 405
Sorted: 550
Sorted: 880
Sorted: 265
Sorted: 267
Sorted: 252
Sorted: 310
Sorted: 253
Sorted: 272
Sorted: 285
Sorted: 270
Sorted: 270
Sorted: 315
Sorted: 267
Sorted: 269
Sorted: 265
Sorted: 258
Sorted: 269
Sorted: 289
done

package so;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public final class CrazyClass {

    static class Feeder implements Runnable{
        final int b, e;
        int[] k1001;
        int[] k1002;

        final Set<Integer> setThis;

        Feeder(int[] ia, int[] ia1, int be, int en, Set<Integer> s){
            k1001 = ia;
            k1002= ia1;
            b = be;
            e = en;
            setThis = s;
        }

        public void run() {
            int i2 = b;
            for(int i1 = b; i1 < e; i1++){
                if (k1001[i1] == k1002[i2]){
                    synchronized(setThis){
                        setThis.add(k1001[i1]);
                        if (setThis.size() == 25){
                            System.out.println("bye!!!");
                            break;
                        }
                    }
                }
                else if (k1001[i1] < k1002[i2])
                    i1++;
                else if (k1001[i1] > k1002[i2])
                    i2++;
            }

        }
    }

    static void sorted(){
        int i1 = 0, i2 = 0;
        Set<Integer> result = new HashSet<Integer>();
        Random r = new Random();
        int[] k1001 = new int[100000];
        int[] k1002 = new int[100000];

        for(int i = 0; i< k1001.length; i++){
            k1001[i] = r.nextInt();
            k1002[i] = r.nextInt();
        }

        Arrays.sort(k1001);
        Arrays.sort(k1002);

        long l = System.nanoTime();

        for(; i1 < k1001.length; i1++){
            if (k1001[i1] == k1002[i2]){
                result.add(k1001[i1]);
                if (result.size() == 100){
                    System.out.println("bye!!!");
                    break;
                }
            }
            else if (k1001[i1] < k1002[i2])
                i1++;
            else if (k1001[i1] > k1002[i2])
                i2++;
        }
        l = System.nanoTime() - l;
        System.out.println("Sorted: " + TimeUnit.MICROSECONDS.convert(l, TimeUnit.NANOSECONDS));
    }

    static void workers(){
        Thread t1, t2;
        Set<Integer> setThis = new HashSet<Integer>();
        Random r = new Random();
        int[] k1001 = new int[100000];
        int[] k1002 = new int[100000];

        for(int i = 0; i< k1001.length; i++){
            k1001[i] = r.nextInt();
            k1002[i] = r.nextInt();
        }

        t1 = new Thread(new Feeder(k1001, k1002, 0, 49999, setThis));
        t2 = new Thread(new Feeder(k1001, k1002, 50000, 99999, setThis));
        try{
            long l = System.nanoTime();
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println("Workers: " + TimeUnit.MICROSECONDS.convert(System.nanoTime() - l, TimeUnit.NANOSECONDS));

        }catch(Exception x){

        }
    }

    static public void main(String[] args){
        int run = 20;
        for(int i = 0; i < run; i++)
            workers();
        System.out.println("done");
        for(int i = 0; i < run; i++)
            sorted();
        System.out.println("done");

    }
}
工人:2806
工人:4197
工人:4235
工人:818
工人:729
工人:3376
工人:740
工人:688
工人:2245
工人:732
工人:330
工人:945
工人:605
工人:630
工人:630
工人:334
工人:643
工人:309
工人:290
工人:761
完成
排序:1525
排序:405
排序:550
分类:880
排序:265
分类:267
分类:252
排序:310
排序:253
分类:272
排序:285
排序:270
排序:270
分类:315
分类:267
分类:269
排序:265
排序:258
分类:269
排序:289
完成
如此包装;
导入java.util.array;
导入java.util.HashSet;
导入java.util.Random;
导入java.util.Set;
导入java.util.concurrent.TimeUnit;
公共期末班疯狂课堂{
静态类馈送器实现可运行{
最终int b,e;
int[]k1001;
int[]k1002;
最终设置此设置;
馈线(int[]ia,int[]ia1,int be,int en,集合s){
k1001=ia;
k1002=ia1;
b=be;
e=en;
设此=s;
}
公开募捐{
int i2=b;
for(inti1=b;i1k1002[i2])
i2++;
}
}
}
静态空排序(){
inti1=0,i2=0;
Set result=new HashSet();
随机r=新随机();
int[]k1001=新int[100000];
int[]k1002=新int[100000];
对于(int i=0;ipackage com.example.so.algorithms;

import java.util.Arrays;
import java.util.Random;

/**
 * <p> http://stackoverflow.com/questions/42538902/how-to-intersect-two-sorted-arrays-the-fastest-possible-way#comment72213844_42538902 </p>
 * <p> Given two sorted sub-lists of 100k each determine the first 10 intersecting (common) entries within 350 millis </p>
 * @author Ravindra
 * @since 03March2017
 *
 */
public class TestMergeIntersection {

    /**
     * <pre>
Time (millis):9
Result :[442958664, 932132404, 988442487, 1356502780, 1614742980, 1923995812, 1985016181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    </pre>
     * @param args
     */
    public static void main(String[] args) {
        handleTest();
    }

    private static void handleTest() {
        int size = 1024*128;
        int intersectionCount = 100;
        int[] arrayOne = generateSortedSublist(size);
        int[] arrayTwo = generateSortedSublist(size);
        int[] result = new int[intersectionCount];
        int count = 0;
        int i=0;
        int j=0;
        long start = System.currentTimeMillis();
        while(count < 100 && i < size && j < size ) {
            if( arrayOne[i] < arrayTwo[j]) {
                i++;
            } else if(  arrayOne[i] > arrayTwo[j] ) {
                j++;
            } else {
                result[count] =arrayOne[i]; 
                i++;
                j++;
                count++;
            }
        }
        long end = System.currentTimeMillis();

        System.out.println("Time (millis):"+(end-start));
        System.out.println("Result :"+Arrays.toString(result));
    }

    private static int[] generateSortedSublist(int size) {

        Random random = new Random();
        int[] result = new int[size];

        for(int i=0;i<result.length;i++) {
            result[i] = random.nextInt(Integer.MAX_VALUE);
        }

        Arrays.sort(result);

        return result;
    }

}