C 子序列计算器。我能提高效率吗?

C 子序列计算器。我能提高效率吗?,c,subsequence,C,Subsequence,子序列的概念在本文中得到了很好的解释: 但是我不明白这个问题的答案,因为我是个初学者 我想知道的是,我是否可以让我的C程序更高效,同时保持它的简单易懂,并且不使用函数 #include <stdio.h> #define NUM 123456 int main(void) { int i,num=NUM,x,y,mask,digits=0,max=1; while ( num != 0 ) { //calculate digits num /=

子序列的概念在本文中得到了很好的解释:

但是我不明白这个问题的答案,因为我是个初学者

我想知道的是,我是否可以让我的C程序更高效,同时保持它的简单易懂,并且不使用函数

#include <stdio.h>
#define NUM 123456

int main(void) {

    int i,num=NUM,x,y,mask,digits=0,max=1;

    while ( num != 0 ) {  //calculate digits
        num /= 10;
        digits++;
    }

    for ( i = 1; i <= digits; i++ ) {  //calculate max number of subsequences
        max *= 2;     
    }
    max=max-2;

    printf("Subsequences are:\n");
    for ( i = 1; i <= max ; i++ ) {
        mask = i;     //digit selector
        x = 1;        //multiplier
        num = NUM;
        y=0;          //subsequence value

        while ( num != 0 ) {
            if ( mask % 2 == 1 ) {
                y += num % 10 * x;
                x *= 10; 
            }
            num /= 10;
            mask /= 2;
        }
        printf("%d \n" , y);
    } 

    return 0;
}
#包括
#定义数字123456
内部主(空){
整数i,num=num,x,y,掩码,数字=0,最大=1;
而(num!=0){//计算数字
num/=10;
数字++;
}

对于(i=1;i某些子序列与某些数字出现多次的原因,其根源在于这些数字具有相同数字的重复


可以通过将每个子序列保存在数组中并检查该数组以查看特定子序列是否已在数组中来消除重复。如果已在数组中,请不要打印。否则,请将子序列添加到数组内容并打印。问题可分为两个任务:(1)查找数字数组的所有子序列,并(2)将整数打包并解包为数字

让我们考虑数组的子序列<代码> {a,b,c}/<代码>。你可以通过从左到右遍历数组来生成它们,并遵循两个路径:一个在当前序列中包含当前元素,另一个在不在其中。

这导致了我们可以表示为树的递归方法:

                  {}
               /      \
         {}               {a}
       /    \           /     \
    {}        {b}     {a}      {ab}
   /  \      /   \   /   \    /    \
  {}  {c}  {b} {bc} {a} {ac} {ab} {abc}
向左分支时,我们跳过当前元素,向右分支时,我们包含元素。元素本身就是树的深度:在第一级,我们处理元素
a
,在下一级
b
,在最后一级
c

最下面一行包含所有子序列。这包括您不需要的空序列和完整序列。但现在让我们将它们包括在内。(最下面一行中的数组通常称为a,这是一个很好的web搜索术语。)

我提到了递归,它需要递归函数,而函数是不存在的

因此,我们需要用另一种方法来解决这个问题。让我们将树转向一边。破折号表示元素被跳过。右侧的符号使用另一种符号:
0
表示元素被跳过,
1
表示元素被包括在内:

- - -        000
- - c        001
- b -        010
- b c        011
a - -        100
a - c        101
a b -        110
a b c        111
我希望右边的代码看起来很熟悉,因为这就是从
000
111
的二进制计数方式。这是枚举元素的好方法。现在我们需要一种方法来判断每个数字中设置了哪些位

当数字为奇数时,设置最右边的位。我们可以通过重复将数字除以2来了解其他位,二进制表示向右移位,丢弃最右边的位

现在,如何从原始数字中提取数字?该数字是一个十进制数字;以10为基数。我们可以使用与查找二进制数字中的位相同的方法,因为位0和1是二进制数字

从数字开始。最后一个数字是除以10后的余数的结果。然后将数字除以10,直到为零。此代码从右到左生成数字。查找位的代码也是如此,这意味着我们可以在一个循环中找到是否设置了位以及要打印的位,始终取右most位,如果已设置,则打印原始数字的最右边数字

空子序列和完整子序列是枚举中的第一项和最后一项。如果不需要,请跳过它们

如果数字有重复的数字,那么就剩下了重复的子序列的问题。除了用户3629249建议创建子序列并稍后检查是否已经打印外,我看不到一个简单的方法来解决这个问题

一种简单的方法是保留一个子序列数组。该数组有
max
条目。填充该数组后,对其排序,然后打印,但跳过与前一个条目相等的条目

下面是一个示例实现,它使用一个数字数组,这样原始数字就不必每次都进行分解。它使用排序功能
qsort
from
,这需要排序功能:

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

#define NUM 412131

typedef unsigned int uint;

int uintcmp(const void *pa, const void *pb)
{
    const uint *a = pa;
    const uint *b = pb;

    return (*a > *b) - (*a < *b);
}

int main(void)
{
    uint digit[20];             // array of digits
    size_t ndigit = 0;          // length of array
    uint num = NUM;
    uint max = 1;
    size_t i;

    while (num) {
        digit[ndigit++] = num % 10;
        num /= 10;
        max *= 2;
    }

    uint res[max];              // array of subsequences

    for (i = 0; i < max; i++) {
        uint mask = i;          // mask for bit detection
        uint j = ndigit;        // index into digit array
        uint s = 0;

        while (j--) {
            if (mask % 2) s = s*10 + digit[j];
            mask /= 2;
        }

        res[i] = s;
    }

    qsort(res, max, sizeof(*res), uintcmp);

    for (i = 1; i < max - 1; i++) {
        if (res[i] != res[i - 1]) printf("%u\n", res[i]);
    }

    return 0;
}
#包括
#包括
#定义数字412131
typedef无符号整数单元;
内部uintcmp(常数无效*pa,常数无效*pb)
{
常数*a=pa;
常数*b=pb;
返回(*a>*b)-(*a<*b);
}
内部主(空)
{
uint数字[20];//数字数组
size\u t ndigit=0;//数组的长度
uint num=num;
uint max=1;
尺寸i;
while(num){
数字[ndigit++]=num%10;
num/=10;
最大*=2;
}
uint res[max];//子序列数组
对于(i=0;i和不使用函数——函数有什么不好?使用得当,它们可以使代码更容易理解。<代码> max=MAX-2 >如果你认为“有效”,则添加分号删除编译器错误。哇,是的,很抱歉我做了一个更改并忘记了。请使用
unsigned
而不是
int
。允许简化,例如
int%2
有3个可能的结果,
unsigned%2
只有两个。YMMV-高度依赖于处理器。您使用的函数是:
printf()
这是一个库函数,您可以通过
#包含
使其工作!