将N个列表中的项目组合成一个平衡分布的好算法?

时间:2008-12-05 19:26:13

标签: algorithm list

假设我有以下三个列表

A1
A2
A3

B1
B2

C1
C2
C3
C4
C5

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

C1
A1
C2
B1
C3
A2
C4
B2
A3
C5

我正在使用.NET 3.5 / C#,但我正在寻找更多关于如何处理特定代码的信息。

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

7 个答案:

答案 0 :(得分:17)

  1. 获取成员最多的列表副本。这将是目的地列表。

  2. 然后选择下一个最大数字的列表。

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

  4. 对于第二个列表中的每个项目,维护一个浮点计数器。添加上一步中计算的值,并在数学上将其四舍五入为最接近的整数(保持原始浮点计数器完好无损)。将其插入目的地列表中的此位置,并将计数器增加1以说明它。对第二个列表中的所有列表成员重复。

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

  6. 编辑:这也有O(n)的优点,这总是很好:)

答案 1 :(得分:2)

首先,这个答案更多的是一种思路而不是一种解决方案。

好的,所以你有一个包含3个项目(A1,A2,A3)的列表,你希望A1在目标列表的前1/3中的某个位置,在目标列表的第二个1/3中的A2和1/3中的A3。同样,你希望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

这似乎对您的示例列表非常有效,但我不知道它可以扩展到包含许多项目的许多列表。试一试,让我知道它是怎么回事。

答案 2 :(得分:2)

实施 Andrew Rollings的回答:

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 :(得分:1)

我正在考虑分而治之的方法。每次迭代,您将所有列表拆分为元素&gt; 1比一并递减。当你到达一个点,除了一个列表之外的所有列表都是一个元素你可以随机组合它们,弹出一个级别并随机组合从那个长度为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 

答案 4 :(得分:1)

  • 制作列表哈希表。
  • 对于每个列表,将第n个元素存储在键(/ n (+ (length list) 1))
  • 下的列表中
  • (可选)将哈希表中每个键下的列表随机播放,或者以某种方式对它们进行排序
  • 按排序键
  • 连接哈希中的列表

答案 5 :(得分:0)

您可以简单地将三个列表合并到一个列表中,然后排列UNSORT。未排序的列表应该不需要太多努力就可以达到“均匀分布”的要求。

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

答案 6 :(得分:-1)

快速建议,用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)

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