有没有快速的方法来生成由他们的产品订购的笛卡尔坐标对?

时间:2015-04-13 18:51:57

标签: algorithm language-agnostic

我想在它们的产品按降序排列的有界​​正方形内生成成对的笛卡尔坐标。例如,对于大小为3的正方形,坐标为:

(3,3), (3,2), (2,3), (2,2), (3,1), (1,3), (2,1), (1,2), (1,1)

有没有办法快速生成这个列表 - 即一个将整数映射到第n个坐标的常数时间函数?

3 个答案:

答案 0 :(得分:1)

也许你可以根据你想要的速度以及改变广场边界的速度来详细说明你的具体需求。

这个问题类似于在乘法表中生成不同的数字(其基数研究保罗鄂尔多斯和最快的已知算法,准确计算为O(n ^ 2))。

考虑生成列表部分的一种方法(假设您不会列出数十亿个坐标)是按降序快速散列部分i*j s并对其进行排序。为了使哈希准确,我们将其扩展到所选范围[n,k]以下,直到n * l低于k*k某些l。例如,对于从(10,10)到(7,7)的坐标范围,我们将哈希值扩展为(5,5),以便(10,5)大于(7,7),将包括在内。

JavaScript代码:

function f(n,k){
  var l = k, k2 = k*k;
  while (n*l > k2){
    l--;
  }
  console.log("low bound: " + l);
  var h = {}, h2 = [];
  for (var i=n; i>l; i--){
    for (var j=i; j>l; j--){
      var m = i*j;
       if (h[m]) h[m] = h[m].concat([i,j]);
       else {
         h[m] = [i,j];
         h2.push(m);
      }
    }
  }
  h2.sort(function(a,b){return b-a});
  var i=0;
  while(h2[i] >= k2){
    console.log(h[h2[i++]]);
  }
}

输出:

f(10,6)

low bound: 3

(10,10) 
(10,9) 
(9,9) 
(10,8)
...
(10,4), (8,5)
(9,4), (6,6)

更多输出:

f(1000000,999995)

low bound: 999990

(1000000,1000000) 
(1000000,999999) 
(999999,999999)
(1000000,999998) 
(999999,999998) 
(1000000,999997) 
(999998,999998) 
(999999,999997) 
(1000000,999996) 
(999998,999997)
(999999,999996) 
(1000000,999995) 
(999997,999997)
(999998,999996)
(999999,999995) 
(1000000,999994)
(999997,999996) 
(999998,999995) 
(999999,999994) 
(1000000,999993) 
(999996,999996)
(999997,999995) 
(999998,999994) 
(999999,999993) 
(1000000,999992) 
(999996,999995) 
(999997,999994) 
(999998,999993) 
(999999,999992) 
(1000000,999991) 
(999995,999995)

答案 1 :(得分:1)

我没有测试过这个想法。您可以通过从右下角到左上角取下对角线,快速生成大致正确顺序的所有坐标列表,就像countability of the rationals的参数一样。这将给你一个几乎排序的列表。

有一些排序方法可以利用它来为您提供更快的排序。有关讨论,请参阅Which sorting algorithm is best suited to re-sort an almost fully sorted list?。您可以随时尝试不同的排序算法,以查看哪种方法最适合您的数据。

答案 2 :(得分:1)

你的枚举应该从右上角到左下角自然地进行。

将边界维护为优先级队列。从右上角开始是边界中唯一的一个条目。

在每一步中,从PQ中弹出max元素并将其三个后代(West,South和South-West)插入到队列中,而不创建重复的(可能使用实际的数组数组来支持队列,但这意味着额外的空间......好吧,这些短(例如,垂直)数组不超过n,每个数组都不大于几个元素,并且它们永远不会向上/向上移动,只能向下移动

队列长度 O(n) - 想想"diagonals", even if curved, -

enter image description here

并且您生成 n 2 结果,因此总体复杂性取决于队列实现的效率。如果是对数,它将 O(n 2 log n)并且如果是线性的(使用哈希表,因为我们知道的范围是所涉及的值, O(n 2 ,总体而言;但是每个生成的对将 在线 , - O(1)... O(log n)

如果精度允许(对于您的范围,它看起来会如此),预先计算坐标的对数,并按log(x) + log(y)而不是x * y对这些对进行排序,交易 O(n 2 乘以 n 对数和 O(n 2 添加。

编辑:请参阅this了解另一个非常相似的算法的实际Haskell代码;它还包含额外的提示,如何将其加速另一个因子2(xy==yx),因此仅在正方形的三角形半部分上工作 - 这也将使所需空间减半。看起来没有必要将SW子项添加到优先级队列,只需SW即可!