【问题标题】:Good algorithm for combining items from N lists into one with balanced distribution?将 N 个列表中的项目组合成一个平衡分布的好算法?
【发布时间】:2008-12-05 19:26:12
【问题描述】:

假设我有以下三个列表

A1
A2
A3

B1
B2

C1
C2
C3
C4
C5

我想将它们组合成一个列表,每个列表中的项目尽可能均匀分布,如下所示:

C1
A1
C2
B1
C3
A2
C4
B2
A3
C5

我正在使用 .NET 3.5/C#,但我正在寻找更多如何处理它而不是特定代码。

编辑:我需要保持原始列表中元素的顺序。

【问题讨论】:

  • 在我看来,您不只是想将它们组合在一起,而是希望它们像拉链或汽车在高速公路上礼貌地合并一样均匀地合并在一起。我说的对吗?
  • 这个算法有众所周知的名字吗?

标签: algorithm list


【解决方案1】:
  1. 复制成员最多的列表。这将是目标列表。

  2. 然后取出成员数量第二多的列表。

  3. 将目标列表长度除以较小的长度,得到大于一的小数值。

  4. 对于第二个列表中的每个项目,维护一个浮点计数器。将上一步计算的值相加,并在数学上将其四舍五入到最接近的整数(保持原始浮点计数器不变)。将它插入到目标列表中的这个位置,并将计数器增加 1 来说明它。对第二个列表中的所有列表成员重复此操作。

  5. 对所有列表重复步骤 2-5。

编辑:这也具有 O(n) 的优势,这总是很好:)

【讨论】:

  • 对此的一种变体是在步骤 4 中使用 Bresenham 的线算法而不是浮点计数器。将 N 个对象均匀地插入现有的 M 个对象列表中相当于枚举光栅化线的点从 到 .
  • 嗯,归根结底是同一件事……溢出/舍入是 bresenhams 的核心。
  • @AndrewRollings 你能否详细解释一下,或者pseudocode 足以让我理解?我无法清楚地理解您的答案。
【解决方案2】:

实施 安德鲁·罗林斯的回答:

public List<String> equimix(List<List<String>> input) {

  // sort biggest list to smallest list
  Collections.sort(input, new Comparator<List<String>>() {
     public int compare(List<String> a1, List<String> a2) {
        return a2.size() - a1.size();
     }
  });

  List<String> output = input.get(0);

  for (int i = 1; i < input.size(); i++) {
     output = equimix(output, input.get(i));
  }

  return output;
}

public List<String> equimix(List<String> listA, List<String> listB) {

  if (listB.size() > listA.size()) {
     List<String> temp;
     temp = listB;
     listB = listA;
     listA = temp;
  }

  List<String> output = listA;

  double shiftCoeff = (double) listA.size() / listB.size();
  double floatCounter = shiftCoeff;

  for (String item : listB) {
     int insertionIndex = (int) Math.round(floatCounter);
     output.add(insertionIndex, item);
     floatCounter += (1+shiftCoeff);
  }

  return output;
}

【讨论】:

    【解决方案3】:

    首先,这个答案更像是一个思路,而不是一个复杂的解决方案。

    好的,所以您有一个包含 3 个项目(A1、A2、A3)的列表,您希望 A1 位于目标列表的前 1/3 中,A2 位于目标列表的后 1/3 中, 和 A3 在第三个 1/3。同样,您希望 B1 位于前 1/2 等...

    所以你将你的 10 个列表分配为一个数组,然后从包含最多项目的列表开始,在本例中为 C。计算 C1 应落在的位置 (1.5) 将 C1 放在最近的位置,(在本例中, 1 或 2),然后计算 C2 应该落在哪里 (3.5) 并继续该过程,直到不再有 Cs。

    然后使用具有第二多项目数的列表。在这种情况下,A。计算 A1 去哪里(1.66),所以先尝试 2。如果您已经将 C1 放在那里,请尝试 1。对 A2 (4.66) 和 A3 (7.66) 执行相同的操作。最后,我们做列表 B。B1 应该在 2.5,所以尝试 2 或 3。如果两者都被采用,请尝试 1 和 4,并继续径向向外移动,直到找到一个空点。对 B2 执行相同操作。

    如果你选择较小的数字,你最终会得到这样的结果:

    C1 A1 C2 A2 C3 B1 C4 A3 C5 B2

    或者如果你选择了上面的数字:

    A1 C1 B1 C2 A2 C3 A3 C4 B2 C5

    这似乎适用于您的示例列表,但我不知道它可以扩展到包含许多项目的许多列表中。试试看,让我知道结果如何。

    【讨论】:

      【解决方案4】:
      • 制作列表的哈希表。
      • 对于每个列表,将列表中的第 n 个元素存储在键 (/ n (+ (length list) 1))
      • (可选)打乱哈希表中每个键下的列表,或以某种方式对它们进行排序
      • 通过排序键连接散列中的列表

      【讨论】:

        【解决方案5】:

        我正在考虑一种分而治之的方法。每次迭代,您将所有元素 > 1 的列表分成两半并递归。当你到达一个点,除了一个之外的所有列表都属于一个元素,你可以随机组合它们,弹出一个级别并随机组合从长度为一的帧中删除的列表......等等。

        我的想法是这样的:

        - filter lists into three categories
            - lists of length 1
            - first half of the elements of lists with > 1 elements
            - second half of the elements of lists with > 1 elements
        - recurse on the first and second half of the lists if they have > 1 element
            - combine results of above computation in order
        - randomly combine the list of singletons into returned list 
        

        【讨论】:

        • 这会比威尔的回答更好吗?
        【解决方案6】:

        您可以简单地将三个列表组合成一个列表,然后对该列表进行 UNSORT。一个未排序的列表应该可以满足您“均匀分布”的要求,而不需要太多努力。

        这里是 unsort 的一个实现:http://www.vanheusden.com/unsort/

        【讨论】:

        • 听起来像是随机化了元素。虽然它可能在大多数情况下都有效,但有时你会得到一个相当不平衡的分布。
        • 是的,我在发布解决方案后注意到了这一点。
        【解决方案7】:

        一个快速的建议,用python-ish伪代码:

        merge = list()
        lists = list(list_a, list_b, list_c)
        lists.sort_by(length, descending)
        
        while lists is not empty:
            l = lists.remove_first()
            merge.append(l.remove_first())
            if l is not empty:
                next = lists.remove_first()
                lists.append(l)
                lists.sort_by(length, descending)
                lists.prepend(next)
        

        这应该比此处的其他建议更均匀地分配较短列表中的元素。

        【讨论】:

        • 此伪代码并非在所有情况下都有效。我实现了它并尝试使用大小为 2 和 6 的两个列表。尝试从空列表中删除元素时出现 IndexError。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-04
        • 2014-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-11
        • 1970-01-01
        相关资源
        最近更新 更多