列出组合的更有效方式

Posted

技术标签:

【中文标题】列出组合的更有效方式【英文标题】:More efficient way of listing combinations 【发布时间】:2016-07-13 05:12:35 【问题描述】:

最近我回答了许多重复的问题之一,即“如何获取在此处插入数据类型的数组的所有可能组合。我的回答是:

#include <stdio.h>

int main()

    /* String for combos to be enumerated */
    char set[4] =  'a', 'b', 'c', 'd' ;
    /* Length of the array */
    int setLength = 4, a, b, c;

    /* This will print all combos that have 1 value. E.g. A, B, C, D */
    for (a = 0; a < setLength; a++) 
    
        printf("%c : ", set[a]);
    

    /* This will give the 1st value of the combo */
    for (a = 0; a < setLength; a++)
    
        /* This will give the 2nd value. Resulting in combos with a length of 2 */
        for (b = 0; b < setLength; b++)         
        
            printf("%c%c : ", set[a], set[b]);
        
    

    /* 1st value */
    for (a = 0; a < setLength; a++)
    
        /* 2nd value */
        for (b = 0; b < setLength; b++)
        
            /* 3rd value */
            for (c = 0; c < setLength; c++)
            
                printf("%c%c%c : ", set[a], set[b], set[c]);
            
        
    

    /* To continue with longer combos simply add more and more for loops */
    printf("\n");
    return 0;

但是,当我查看此问题的其他答案时,它们都涉及该语言的内置函数,例如C#。因此我的问题是:我回答的方式是正确的还是可靠的,如果不是,那么在没有内置函数的情况下,什么是更有效的方式。

【问题讨论】:

为什么不尝试几个不同的程序,看看哪个更快?顺便说一句,您的程序似乎只适用于 4 元素集。这不符合解决方案的条件。 不相关,但在 C 语言中,当您不需要函数时,您必须明确说明它需要 void 作为参数。 int main()int main(void) 意味着两个不同的东西。第一个接受不确定数量的参数,而后者不接受任何参数。此外,C 规范规定 main 函数应该看起来像 int main(void)int main(int argc, char *argv[])int main() 不是有效的 main 函数。 @Joachim Pileborg 谢谢,总是欢迎批评,因为我对 C 还是很陌生。 @n.m.会的,我也会尝试更正上面的代码,使其适用于任何数量的元素,谢谢你的输入。 ***.com/a/12225214/2469027 你不需要它@JoachimPileborg 【参考方案1】:

您可以使用带有回溯的简单算法 - 一种允许您使用之前的部分计算来获得更多值的技术。

代码如下:

void print_comb_rec(char* values, int n, int length, char* helper)

    int i;

    if (length == 0)
    
        printf("%s : ", helper);
        return;
    

    for (i = 0; i < n; i++)
    
        helper[length - 1] = values[i];
        print_comb_rec(values, n, length - 1, helper);
    


void print_comb(char* values, int n, int length)

    char* helper = malloc(sizeof(char) * (length + 1));
    int i;

    helper[length] = '\0';
    print_comb_rec(values, n, length, helper);

    free(helper);

用法:使用函数 print_comb。它需要置换值、数组 n 的长度和组合的长度。通过使用它,您可以获得给定长度的结果。

请注意,对于给定的 n,可能组合的数量呈指数增长(即O(n^length))。对于任何递归算法,使用它也有可能耗尽堆栈的内存。

【讨论】:

谢谢,帮了大忙。【参考方案2】:

我需要比评论更多的空间,所以把它放在这里:

关于此代码:

for (a = 0; a < setLength; a++)

    /* This will give the 2nd value. 
     * Resulting in combos with a length of 2 
     */
    for (b = 0; b < setLength; b++)
    
        printf("%c%c : ", set[a], set[b]);
    

将导致不正确的输出组合,例如:

aa
bb
cc
dd

哪些不是有效的组合

这段代码:

/* 1st value */
for (a = 0; a < setLength; a++)

    /* 2nd value */
    for (b = 0; b < setLength; b++)
    
        /* 3rd value */
        for (c = 0; c < setLength; c++)
        
            printf("%c%c%c : ", set[a], set[b], set[c]);
        
    

将产生如下输出组合:

aaa
aab
aac
aad
...

这不是有效的组合。

关于一个相关的主题。

大多数在线代码判断问题都有严格的时间限制。调用 `printf() 需要很多时间。

建议尽可能使用以下功能:

#include <stdio.h>


    void fastRead( size_t *a );
    void fastWrite( size_t a );

    inline void fastRead(size_t *a)
    
        int c=0;
        // note: 32 is space character
        while (c<33) c=getchar_unlocked();

        // initialize result value
        *a=0;

        // punctuation parens, etc are show stoppers
        while (c>47 && c<58)
        
            *a = (*a)*10 + (size_t)(c-48);
            c=getchar_unlocked();
        
        //printf( "%s, value: %lu\n", __func__, *a );
     // end function: fastRead


    inline void fastWrite(size_t a)
    
        char snum[20];
        //printf( "%s, %lu\n", __func__, a );

        int i=0;
        do
        
            // 48 is numeric character 0
            snum[i++] = (char)((a%10)+(size_t)48);
            a=a/10;
        while(a>0);

        i=i-1; // correction for overincrement from prior 'while' loop

        while(i>=0)
        
            putchar_unlocked(snum[i--]);
        
        putchar_unlocked('\n');
     // end function: fastWrite

【讨论】:

以上是关于列出组合的更有效方式的主要内容,如果未能解决你的问题,请参考以下文章

在 datagridview 和表单之间传递数据的更有效方式

使用数据集的更有效方式

更新子文档、NodeJS 和 Mongoose 的更有效方式

更新子文档、NodeJS 和 Mongoose 的更有效方式

加载图像以进行检测的更有效方式

哪个是订阅以太坊状态变化的更有效方式