我需要帮助非递归地创建k组合算法

时间:2014-05-08 02:53:40

标签: c algorithm

我在网上浏览了非递归k组合算法,但是在理解所有重建索引方面遇到了麻烦;我在网上找到的代码评论不好或崩溃。

例如,如果我有该集合,{' a','',' c',' d',& #39; e'}我希望找到3种组合;即,

abc
abd
abe
acd
ace
ade
bcd
bce
bde
cde

如何实现算法来执行此操作?当我写下一般程序时,这很清楚。那是;我递增指针中的最后一个元素,直到它指向' e,将第二个元素递增到最后一个元素并将最后一个元素设置为倒数第二个元素+ 1,然后再次递增最后一个元素直到达到' E'再次,依此类推,如我打印组合的方式所示。我查看了Algorithm to return all combinations of k elements from n的灵感,但我的代码只打印了#abc'。这是它的副本:

#include <stdio.h>
#include <stdlib.h>

static void
comb(char *buf, int n, int m)
{
    // Initialize a pointer representing the combinations
    char *ptr = malloc(sizeof(char) * m);
    int i, j, k;
    for (i = 0; i < m; i++) ptr[i] = buf[i];

    while (1) {
        printf("%s\n", ptr);

        j = m - 1;
        i = 1;
        // flag used to denote that the end substring is at it's max and
        // the j-th indice must be incremented and all indices above it must
        // be reset.
        int iter_down = 0; 
        while((j >= 0) && !iter_down) {
            // 
            if (ptr[j] < (n - i) ) {
                iter_down = 1;
                ptr[j]++;
                for (k = j + 1; k < m; k++) {
                    ptr[k] = ptr[j] + (k - j);
                }
            }
            else {
                j--;
                i++;
            }
        }
        if (!iter_down) break;
    }
}

int
main(void)
{
    char *buf = "abcde";
    comb(buf, 5, 3);
    return 1;
}

2 个答案:

答案 0 :(得分:1)

您的代码的一个非常大的问题是混合索引和值。你有一个字符数组,但是你会尝试增加字符,好像它们是缓冲区中的索引一样。你真正需要的是一系列指数。可以丢弃字符数组,因为索引提供了您所需要的所有内容,或者您​​可以单独保留字符数组。

答案 1 :(得分:1)

我在这里找到了伪代码描述,http://www4.uwsp.edu/math/nwodarz/Math209Files/209-0809F-L10-Section06_03-AlgorithmsForGeneratingPermutationsAndCombinations-Notes.pdf 并通过

在C中实现
#include <stdlib.h>
#include <stdio.h>

// Prints an array of integers
static void
print_comb(int *val, int len) {
    int i;
    for (i = 0; i < len; i++) {
        printf("%d ", val[i]);
    }
    printf("\n");
}

// Calculates n choose k
static int
choose(int n, int k)
{
    double i, l = 1.0;
    double val = 1.0;
    for (i = 1.0; i <= k; i++) {
        l = ((double)n + 1 - i) / i;
        val *= l;
    }
    return (int) val;
}

static void
comb(int n, int r)
{
    int i, j, m, max_val;
    int s[r];
    // Initialize combinations
    for (i = 0; i < r; i++) {
        s[i] = i;
    }
    print_comb(s, r);

    // Iterate over the remaining space
    for (i = 1; i < choose(n, r); i++) {
        // use for indexing the rightmost element which is not at maximum value
        m = r - 1;
        // use as the maximum value at an index, specified by m
        max_val = n - 1; // use for 
        while(s[m] == max_val) {
            m--;
            max_val--;
        }
        // increment the index which is not at it's maximum value
        s[m]++;
        // iterate over the elements after m increasing their value recursively
        // ie if the m-th element is incremented, all elements afterwards are
        // incremented by one plus it's offset from m
        // For example, this is responsible for switching 0 3 4 to 1 2 3 in
        // comb(5, 3) since 3 and 4 in the first combination are at their maximum
        // value
        for (j = m; j < r - 1; j++) {
            s[j + 1] = s[j] + 1;
        }
        print_comb(s, r);
    }
}

int
main(void)
{
    comb(5, 3);

    return 1;
}