关于排序:数组的有序笛卡尔积

Ordered cartesian product of arrays

在2个整数排序数组的高效排序笛卡尔积中,建议使用惰性算法生成两个整数排序数组的有序笛卡尔积。

我很想知道这个算法是否可以推广到更多的数组中。

例如,假设我们有5个排序的双精度数组

(0.7、0.2、0.1)

(0.6、0.3、0.1)

(0.5、0.25、0.25)

(0.4、0.35、0.25)

(0.35、0.35、0.3)

我对生成有序笛卡尔积感兴趣,不必计算所有可能的组合。

请欣赏任何关于可能的懒惰笛卡尔积算法如何扩展到2以外的维度的想法。


这个问题似乎是统一成本搜索的枚举实例(参见https://en.wikipedia.org/wiki/dijkstra%27s_算法)。状态空间由指向已排序数组的当前索引集定义。后继函数是每个数组的可能索引增量的枚举。对于5个数组的给定示例,初始状态为(0、0、0、0、0)。

没有目标状态检查功能,因为我们需要经历所有可能的过程。如果对所有的输入数组进行排序,则保证对结果进行排序。

假设我们有m个长度为n的数组,那么这个方法的复杂性是o((n^m).log(n(m-1))。

下面是Python中的示例实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from heapq import heappush, heappop

def cost(s, lists):
    prod = 1
    for ith, x in zip(s, lists):
        prod *= x[ith]
    return prod

def successor(s, lists):
    successors = []
    for k, (i, x) in enumerate(zip(s, lists)):
        if i < len(x) - 1:
            t = list(s)
            t[k] += 1
            successors.append(tuple(t))
    return successors

def sorted_product(initial_state, lists):    
    fringe = []
    explored = set()
    heappush(fringe, (-cost(initial_state, lists), initial_state))
    while fringe:
        best = heappop(fringe)[1]
        yield best
        for s in successor(best, lists):
            if s not in explored:
                heappush(fringe, (-cost(s, lists), s))
                explored.add(s)

if __name__ == '__main__':
    lists = ((0.7, 0.2, 0.1),
             (0.6, 0.3, 0.1),
             (0.5, 0.25, 0.25),
             (0.4, 0.35, 0.25),
             (0.35, 0.35, 0.3))
    init_state = tuple([0]*len(lists))
    for s in sorted_product(init_state, lists):
        s_output = [x[i] for i, x in zip(s, lists)]
        v = cost(s, lists)
        print '%s %s \t%s' % (s, s_output, cost(s, lists))


所以,如果你有a(a1,…,a)和b(b1,…,bn)。

A

A1*…*An

我假设每个值都是正数,因为如果我们允许负数,那么:

(-50,-100,1)>(1,2,3)

as-50*(-100)*1=5000>6=1*2*3

即使没有负值,问题仍然相当复杂。您需要一个包含数据结构的解决方案,其深度为k。如果(a1,…,ak)<(b1,…,bk),那么我们可以假设在其他维度上(a1,…,ak,…)的组合。a)可能小于(b1,…,bk,…,bn)的组合。因此,如果这不是真的,情况就超过了概率,所以这些都是规则的例外。数据结构应包含:

  • K
  • A和B的前k元素
  • 规则例外的描述

对于任何此类例外情况,可能存在大于(b1,…,bk)的(c1,…,ck)组合,但(c1,…,ck)的较大组合可能仍然具有使用进一步维度值的组合,其中(a1,…,ak)<(c1,…,ck)规则的例外可能仍然存在。

因此,如果您已经知道(a1,…,ak)<(b1,…,bk),那么首先您必须通过查找第一个l维来检查是否存在异常,在这里,选择a的最大可能值和b的最小可能值。如果存在这样的l,那么您应该找到异常的开始位置(哪个维,哪个索引)。这将描述异常情况。当你发现异常时,你知道(a1,…,ak,…,al)>(b1,…,bk,…,bl)的组合,所以这里的规则是a大于b,当b大于a时会出现异常。

为了反映这一点,数据结构如下:

1
2
3
4
5
6
class Rule {
    int k;
    int[] smallerCombinationIndexes;
    int[] biggerCombinationIndexes;
    List<Rule> exceptions;
}

每当您发现一个规则的异常时,该异常将基于先前的知识生成。不用说,复杂性大大增加了,但问题是您对规则有异常,对异常有异常等等。当前的方法会告诉你,如果你取两个随机点,A和B,A是否小于B,它也会告诉你,如果你取(a1,…,ak)和(b1,…,bk)的组合,那么(a1,…,ak)和(b1,…,bk)的比较结果会改变的关键指标是什么。根据您的具体需求,这个想法可能已经足够,或者需要扩展。因此,您的问题的答案是:是的,您可以扩展lazy算法来处理进一步的维度,但是您需要处理规则的异常来实现这一点。