有效的按类别排序算法

时间:2013-01-11 13:04:38

标签: algorithm sorting

假设我们有一个长度为N的对象数组(所有对象都有相同的字段集)。

我们有一个长度为N的数组,它们代表某个对象的字段(例如代表ID的数字数组)。

现在我们要按字段对对象数组进行排序,该字段在第二个数组中表示,顺序与第二个数组相同。

例如,这里有2个数组(如说明中所示)和预期结果:

A = [ {id: 1, color: "red"}, {id: 2, color: "green"}, {id: 3, color: "blue"} ]
B = [ "green", "blue", "red"]

sortByColorByExample(A, B) == 
    [ {id: 2, color: "green"}, {id: 3, color: "blue"}, {id: 1, color: "red"} ]

如何有效实施'按示例排序'功能?我无法想出比O(N^2)更好的东西。

5 个答案:

答案 0 :(得分:3)

这假设您有B中的元素与A

中元素的双头投射

M的元素构建地图(比如说B)到他们的位置(O(N)

对于AO(N))的每个元素,访问地图以查找将其放置在已排序数组中的位置(O(log(N))并有效实现地图)

总复杂度:O(NlogN)时间和O(N)空间

答案 1 :(得分:2)

假设我们正在对项目的颜色进行排序。然后创建一个字典 d ,将每种颜色映射到A中具有该颜色的项目列表。然后迭代列表B中的颜色,并为每个颜色 c 输出(并删除)列表 d [ c ]中的值。这在O( n )时间运行,其中O( n )是字典的额外空间。

请注意,如果根据B中的示例无法对A进行排序,您必须决定该怎么做:您是否引发错误?选择最大化匹配数量的顺序?或者是什么?

无论如何,这是Python的快速实现:

from collections import defaultdict

def sorted_by_example(A, B, key):
    """Return a list consisting of the elements from the sequence A in the
    order given by the sequence B. The function key takes an element
    of A and returns the value that is used to match elements from B.
    If A cannot be sorted by example, raise IndexError.

    """
    d = defaultdict(list)
    for a in A:
        d[key(a)].append(a)
    return [d[b].pop() for b in B]

>>> A = [{'id': 1, 'color': 'red'}, {'id': 2, 'color': 'green'}, {'id': 3, 'color': 'blue'}]
>>> B = ['green', 'blue', 'red']
>>> from operator import itemgetter
>>> sorted_by_example(A, B, itemgetter('color'))
[{'color': 'green', 'id': 2}, {'color': 'blue', 'id': 3}, {'color': 'red', 'id': 1}]

请注意,此方法处理序列B中存在多个相同值的情况,例如:

>>> A = 'proper copper coffee pot'.split()
>>> B = 'ccpp'
>>> ' '.join(sorted_by_example(A, B, itemgetter(0)))
'coffee copper pot proper'

B中有多个相同的值时,我们会以相反的顺序获取A中的相应元素,但这只是实现的假象:使用collections.deque如果首选,我们可以安排以原始顺序获取popleft的相应元素,而不是列表(而pop而不是A)。

答案 2 :(得分:0)

创建一个数组数组,将其称为大小为B.length的C. 循环A.如果颜色为“绿色”则将其放在C [0]中。如果它的颜色为“蓝色”,则将其放在C [1]中,如果它的颜色为红色则将其放在C [2]中。 当你完成后,通过C,并将其展平为原始结构。

答案 3 :(得分:0)

合并排序不会更好吗?创建B.length数组,一个用于B中的每个元素,然后通过A,并将它们放在适当的较小数组中,然后在完成所有操作时将数组合并在一起。它应该在O(2n)附近

答案 4 :(得分:0)

  • 遍历第一个数组并创建HashMap个此类字段而不是List个对象。 O(n) [假设这些关键字段存在重复值]

例如。 key = green将包含字段值为Green

的所有对象
  • 现在遍历第二个数组,从HashMap获取对象列表并将其存储在另一个数组中。 O(k) ..(其中k - 字段的不同值)

总运行时间为O(n),但就地图和辅助阵列而言需要一些额外的内存

最后,您将根据您的要求对数组进行排序。