-1

The idea of subsequences is explained very well in this post:Generate subsequences

But i didnt understand the answers on that question because im a beginner.

What i wanted to know is if i could make my C program any more efficient while still keeping it simple and understandable and without using functions?

#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;
}

Note that when we define NUM as a number such as 5111 or 100 some of the subsequences appear twice. Is there any simple way to fix that? Thanks!

Community
  • 1
  • 1
riegour
  • 25
  • 5
  • 3
    _and without using functions_ -- What's so bad about functions? Used properly, they can make the code easier to understand. – M Oehm Nov 11 '15 at 18:13
  • 1
    `max=max-2` adding a semicolon removes a compiler error if that's what you consider "efficient." – cadaniluk Nov 11 '15 at 18:14
  • wow yeah, sorry about that i made a change and forgot. – riegour Nov 11 '15 at 18:15
  • @cad no way! Without that semicolon the code runs in 0 seconds! – Fantastic Mr Fox Nov 11 '15 at 18:15
  • Im only saying not to use functions because i havent really looked into them yet and dont understand them, thanks though! – riegour Nov 11 '15 at 18:16
  • The task might be easier if you treated the number as string, i.e. as char array with the digits as characters instead of recnstructing the number every time. – M Oehm Nov 11 '15 at 18:16
  • thats true, but the exercise im working on wants it to be #define'd as a number – riegour Nov 11 '15 at 18:18
  • 2
    Use `unsigned` rather than `int`. Allows simplifications like `int%2` has 3 possible results and `unsigned%2` has only two. YMMV - highly dependent on processor. – chux - Reinstate Monica Nov 11 '15 at 18:33
  • thats a good idea, thanks! Edit: Helped quite a bit! – riegour Nov 11 '15 at 18:37
  • Is your question that you need an explanation of your code? (I ask, because you said that you didn't understand the answers to the question you linked to.) – M Oehm Nov 11 '15 at 18:43
  • Well i understood the top answer but i didnt understand the code on any of the others. – riegour Nov 11 '15 at 18:49
  • 1
    You ***are*** using a function: `printf()` which is a library function and you `#include ` to make it work! – Weather Vane Nov 11 '15 at 20:18
  • for readability and ease of documentation, only one variable declaration per statement, only one statement per line. – user3629249 Nov 12 '15 at 00:05

2 Answers2

0

The root of the reason that certain subsequences appear more than once with some numbers is because those numbers have repetitions of the same digit.

That repetition could be eliminated by saving each subsequence in an array and checking that array to see if the specific subsequence is already in the array. If already in the array, do not print. Otherwise, add subsequence to array contents and print

user3629249
  • 16,402
  • 1
  • 16
  • 17
0

The problem can be divided into two tasks: (1) find all subsequences of an array of digits and (2) pack and unpack integers into digits.

Let's consider the subsequences of the array {a, b, c}. You can generate them by walking through the array from left to right and follow two paths: One where you include the current element in a subsequence and one where you don't.

That leads to a recursive approach tat we can represent as a tree:

                  {}
               /      \
         {}               {a}
       /    \           /     \
    {}        {b}     {a}      {ab}
   /  \      /   \   /   \    /    \
  {}  {c}  {b} {bc} {a} {ac} {ab} {abc}

When we branch left, we skip the current element and when we go right, we include the element. The elements themselves are the depth of the tree: On the first level we treat element a, on the next band on the last c.

The bottom row has all subsequences. This includes the empty sequence and the full sequence, which you don't want. But let's include them for now. (The arrays in the bottom row are usually called a power set, which is a nice web-searchable term.)

I mentioned recursion, which entails recursive functions, and functions are out.

So we need to tackle the problem another way. Let's turn the tree on its side. A dash denotes that the element was skipped. The notation on the right uses another notation: 0 means the element was skipped, 1 means the element was included:

- - -        000
- - c        001
- b -        010
- b c        011
a - -        100
a - c        101
a b -        110
a b c        111

I hope the codes on the right look familiar, because that's how you count from 000 to 111 in binary. That's a nice way to enumerate our elements. Now we need a way to tell which bits are set in each number.

The rightmost bit is set when the number is odd. We can find out about the other bits by repeatedly dividing the number by two, which in binary is a shift to the right, discarding the rightmost bit.

Now how to extract the digits from the original number? That number is a decimal number; it's in base 10. We can use the same approach as for finding the bits in the binary number, because the bits 0 and 1 are the binary digits.

Start with the number. The last digit is the result of taking the remainder after a division by 10. Then divide the number by ten until it is zero. This code yields the digits from right to left. So does the code for finding the bits, which means we can find whether a bit is set and which digit to print in a single loop, always taking the rightmost bit and if it is set, print the rightmost digit of the original number.

The empty and the full subsequences are the first and last items in the enumeration. If you don't want them, skip them.

That leaves the problem of the duplicated subsequences if the digit has repeated digits. I don' see an easy way to solve this except user3629249's suggestion to create the subsequence anyway and later check whether is has already been printed.

An easy way to do this is to keep an array of the subsequences. That array has max entries. After you have filled that array, sort it and then print it, but skip entries that are equal to the previous entry.

Here's an example implementation that uses an array of digits so that the original number doesn't have to be decomposed each time. It uses the sorting function qsort from <stdlib.h>, which requires a sorting function:

#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;
}
M Oehm
  • 28,726
  • 3
  • 31
  • 42