简体   繁体   English

从数字列表中生成所有唯一对,n选择2

[英]generating all unique pairs from a list of numbers, n choose 2

i have a list of elements (let's say integers), and i need to make all possible 2-pair comparisons. 我有一个元素列表(比方说整数),我需要进行所有可能的2对比较。 my approach is O(n^2), and i am wondering if there is a faster way. 我的方法是O(n ^ 2),我想知道是否有更快的方法。 here is my implementation in java. 这是我在Java中的实现。

public class Pair {
 public int x, y;
 public Pair(int x, int y) {
  this.x = x;
  this.y = y;
 }
}

public List<Pair> getAllPairs(List<Integer> numbers) {
 List<Pair> pairs = new ArrayList<Pair>();
 int total = numbers.size();
 for(int i=0; i < total; i++) {
  int num1 = numbers.get(i).intValue();
  for(int j=i+1; j < total; j++) {
   int num2 = numbers.get(j).intValue();
   pairs.add(new Pair(num1,num2));
  }
 }
 return pairs;
}

please note that i don't allow self-pairing, so there should be ((n(n+1))/2) - n possible pairs. 请注意,我不允许自我配对,因此应该有((n(n + 1))/ 2)-n个可能的配对。 what i have currently works, but as n increases, it is taking me an unbearable long amount of time to get the pairs. 我目前有什么作品,但是随着n的增加,我花了很长时间忍受不了。 is there any way to turn the O(n^2) algorithm above to something sub-quadratic? 有什么办法可以将上面的O(n ^ 2)算法变成次二次方程式? any help is appreciated. 任何帮助表示赞赏。

by the way, i also tried the algorithm below, but when i benchmark, empirically, it performs worst than what i had above. 顺便说一句,我也尝试了下面的算法,但是当我进行基准测试时,它的性能比上面的还要差。 i had thought that by avoiding an inner loop this would speed things up. 我以为可以避免内部循环,从而可以加快速度。 shouldn't this algorithm below be faster? 下面的这种算法不应该更快吗? i would think that it's O(n)? 我认为这是O(n)? if not, please explain and let me know. 如果没有,请解释并让我知道。 thanks. 谢谢。

public List<Pair> getAllPairs(List<Integer> numbers) {
 int n = list.size();
 int i = 0;
 int j = i + 1;
 while(true) {
  int num1 = list.get(i);
  int num2 = list.get(j);
  pairs.add(new Pair(num1,num2));

  j++;

  if(j >= n) {
   i++;
   j = i + 1;
  }

  if(i >= n - 1) {
   break;
  }
 }
}

Well, you can't, right? 好吧,你不能,对吧?

The result is a list with n*(n-1)/2 elements, no matter what those elements are, just to populate this list (say with zeros) takes O(n^2) time, since n*(n-1)/2 = O(n^2) ... 结果是一个包含n*(n-1)/2元素的列表,无论这些元素是什么,仅填充此列表(用零表示)就需要O(n^2)时间,因为n*(n-1)/2 = O(n^2) ...

You cannot make it sub-quadric, because as you said - the output is itself quadric - and to create it, you need at least #elements_in_output ops. 您不能使其成为次二次方,因为正如您所说-输出本身就是二次方-并且要创建它,您至少需要#elements_in_output ops。

However, you could do some "cheating" create your list on the fly : 但是,您可以进行一些“作弊”操作以立即创建列表
You can create a class CombinationsGetter that implements Iterable<Pair> , and implement its Iterator<Pair> . 您可以创建实现Iterable<Pair> CombinationsGetter类,并实现其Iterator<Pair> This way, you will be able to iterate on the elements on the fly, without creating the list first, which might decrease latency for your application. 这样,您将能够动态访问元素,而无需先创建列表,这可以减少应用程序的延迟。

Note : It will still be quadric! 注意 :它将仍然是二次方! The time to generate the list on the fly will just be distributed between more operations. 即时生成列表的时间只会在更多操作之间分配。


EDIT: Another solution, which is faster then the naive approach - is multithreading . 编辑:另一个解决方案,它比幼稚的方法快-是多线程
Create a few threads, each will get his "slice" of the data - and generate relevant pairs, and create its own partial list. 创建几个线程,每个线程都将得到他的数据“切片”,并生成相关对,并创建自己的部分列表。
Later - you can use ArrayList.addAll() to convert those different lists into one. 以后-您可以使用ArrayList.addAll()将这些不同的列表转换为一个。
Note: though complexity is stiil O(n^2) , it is likely to be much faster - since the creation of pairs is done in parallel, and ArrayList.addAll() is implemented much more effieciently then the trivial insert one by one elements. 注意:尽管复杂度为O(n^2) ,但它可能会更快-因为成对创建是并行完成的,而ArrayList.addAll()的实现要比琐碎的一对一插入操作更有效。

EDIT2: Your second code is still O(n^2) , even though it is a "single loop" - the loop itself will repeat O(n^2) times. EDIT2:即使它是一个“单个循环”,您的第二个代码仍然是O(n^2) -循环本身将重复O(n^2)次。 Have a look at your variable i . 看看你的变量i It increases only when j==n , and it decreases j back to i+1 when it does it. 仅当j==n ,它增加;当这样做时,它将j减少回i+1 So, it will result in n + (n-1) + ... + 1 iterations, and this is sum of arithmetic progression , and gets us back to O(n^2) as expected. 因此,它将导致n + (n-1) + ... + 1次迭代,这是算术级数的总和 ,并使我们回到预期的O(n^2)

We cannot get better then O(n^2), because we are trying to create O(n^2) distinct Pair objects. 我们无法再达到O(n ^ 2),因为我们正在尝试创建O(n ^ 2)个不同的Pair对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM