找到n个有序元素的中间k-组合的有效方法

时间:2013-04-01 01:59:32

标签: combinations median

假设我有一个排序数组 N ,由 n 元素组成。现在,给定 k ,我需要一种高效的方法来生成k组合,这种组合将是中间组合(如果所有 k - 组合都按字典顺序排序)。< / p>

示例:

N = {a,b,c,d,e} , k = 3

1:a,b,c
2:a,b,d
3:a,b,e
4:a,c,d
5:a,c,e
6:a,d,e
7:b,c,d
8:b,c,e
9:b,d,e
10:c,d,e

我需要算法来生成组合编号5.


组合数字系统上的维基百科页面解释了如何获得(以贪婪的方式)。但是,由于 n 非常大,我需要找到所有 k 小于 n 的中间组合,我还需要更多东西比那更有效率。

我希望由于感兴趣的组合始终位于中间,因此有一种直接的方法可以找到它。例如,上面列表中的第一个k组合总是由 N 中的第一个 k 元素给出,类似地,最后一个组合总是由最后一个 k 元素。有没有这种方法可以找到中间组合?

http://en.wikipedia.org/wiki/Combinatorial_number_system

1 个答案:

答案 0 :(得分:0)

如果您正在寻找从词典索引或独特组合的等级中获取K指数的方法,那么您的问题属于二项式系数。二项式系数处理在K组中选择唯一组合以及总共N个项目的问题。

我在C#中编写了一个类来处理使用二项式系数的常用函数。它执行以下任务:

  1. 以任意N选择K到文件的格式输出所有K索引。 K-index可以用更具描述性的字符串或字母代替。

  2. 将K索引转换为正确的词典索引或排序二项式系数表中条目的等级。这种技术比依赖迭代的旧发布技术快得多。它通过使用Pascal三角形中固有的数学属性来实现这一点,并且与迭代集合相比非常有效。

  3. 将已排序的二项系数表中的索引转换为相应的K索引。使用的技术也比旧的迭代解决方案快得多。

  4. 使用Mark Dominus方法计算二项式系数,这样就不太可能溢出并使用更大的数字。

  5. 该类是用.NET C#编写的,它提供了一种通过使用通用列表来管理与问题相关的对象(如果有)的方法。此类的构造函数采用名为InitTable的bool值,当为true时,将创建一个通用列表来保存要管理的对象。如果此值为false,则不会创建表。为了使用上述4种方法,不需要创建该表。提供访问者方法来访问该表。

  6. 有一个关联的测试类,它显示了如何使用该类及其方法。它已经在几个案例中进行了广泛的测试,并且没有已知的错误。

  7. 要阅读此课程并下载代码,请参阅Tablizing The Binomial Coeffieicent

    以下测试代码将计算任何N选择K组合的中位词典元素:

    void TestMedianMethod()
    {
       // This test driver tests out the GetMedianNChooseK method.
       GetMedianNChooseK(5, 3);  // 5 choose 3 case.
       GetMedianNChooseK(10, 3); // 10 choose 3 case.
       GetMedianNChooseK(10, 5); // 10 choose 5 case.
    }
    
      private void GetMedianNChooseK(int N, int K)
      {
         // This method calculates the median lexicographic index and the k-indexes for that index.
         String S;
         // Create the bin coeff object required to get all
         // the combos for this N choose K combination.
         BinCoeff<int> BC = new BinCoeff<int>(N, K, false);
         int NumCombos = BinCoeff<int>.GetBinCoeff(N, K);
         // Calculate the median value, which in this case is the number of combos for this N
         // choose K case divided by 2.
         int MedianValue = NumCombos / 2;
         // The Kindexes array holds the indexes for the specified lexicographic element.
         int[] KIndexes = new int[K];
         // Get the k-indexes for this combination.  
         BC.GetKIndexes(MedianValue, KIndexes);
         StringBuilder SB = new StringBuilder();
         for (int Loop = 0; Loop < K; Loop++)
         {
            SB.Append(KIndexes[Loop].ToString());
            if (Loop < K - 1)
               SB.Append(" ");
         }
         // Print out the information.
         S = N.ToString() + " choose " + K.ToString() + " case:\n";
         S += "   Number of combos = " + NumCombos.ToString() + "\n";
         S += "   Median Value = " + MedianValue.ToString() + "\n";
         S += "   KIndexes = " + SB.ToString() + "\n\n";
         Console.WriteLine(S);
      }
    

    <强>输出:

    5 choose 3 case:
       Number of combos = 10
       Median Value = 5
       KIndexes = 4 2 0
    
    
    10 choose 3 case:
       Number of combos = 120
       Median Value = 60
       KIndexes = 8 3 1
    
    
    10 choose 5 case:
       Number of combos = 252
       Median Value = 126
       KIndexes = 9 3 2 1 0
    

    您应该能够轻松地将此课程移植到您选择的语言上。您可能不必移植类的通用部分来实现您的目标。根据您使用的组合数量,您可能需要使用大于4字节整数的字大小。