Создание уникальных значений

Я хочу создать программу C для генерации чисел от 0 до 999999, имея в виду, что сгенерированное число не должно содержать повторяющихся цифр. Например, "123" является приемлемым значением, но не "121", так как '1' повторяется. Я получил другие программные коды, которые проверяют, повторяются ли целые числа:

Проверьте, есть ли у целого числа повторяющиеся цифры. Никаких строковых методов или массивов

Какой самый быстрый способ проверить наличие повторяющихся цифр в числе?

Однако на самом деле это не решает мою проблему, и это очень неэффективные решения, если мне нужно выполнить проверку для 1 000 000 различных значений. Более того, предоставленное решение предназначено для int, а не для char[] и char *, которые я использую в своей программе. Ниже мой код до сих пор. Как видите, у меня нет проблем с обработкой значений до "012", однако возможностей для значений с 3 цифрами и выше слишком много, чтобы их перечислять, и они слишком неэффективны для кодирования. Был бы признателен за помощь.

int i, j;
char genNext[7] = "0";
printf("%s\n", genNext);

// loop through to return next pass in sequence
while (1) {
    for (i = 0; i < sizeof(genNext) / sizeof(char); i++) {
        if (genNext[i] == '9') {
            char * thisPass = strndup(genNext, sizeof(genNext));
            int countDigit = (int) strlen(thisPass);
            switch (countDigit) {
                case 1:
                genNext = "01";
                break;
                case 2:
                if (strcmp(genNext, "98")) {
                    if (i == 0) {
                        genNext[1] += 1;
                    } else {
                        genNext[0] += 1;
                        genNext[1] == '0';
                    }
                } else {
                    genNext = "012";
                }
                break;
                case 3:
                if (strcmp(genNext, "987")) {
                    // code to handle all cases
                } else {
                    genNext = "0123";
                }
                break;
                case 4:
                case 5:
                case 6:
                    // insert code here
            }
            break;
        } else if (genNext[i] == '\0') {
            break;
        } else if (genNext[i+1] == '\0') {
            genNext[i] += 1;
            for (j = 0; j < i; j++) {
                if (genNext[i] == genNext[j]) {
                    genNext[i] += 1;
                }
            }
        } else {
            continue;
        }
    }
    printf("%s\n", genNext);
    if (strcmp(genNext, "987654") == 0) {
        break;
    }
}

Основная проблема, с которой я сталкиваюсь, это случаи, когда '9' является частью тестируемого значения. Например, следующее значение в последовательности после "897" равно "901", а после "067895" следует "067912" на основе правил неповторяемости, а также последовательного возврата результата.

Желаемый результат будет следующим:

0
1
2
3
...
8
9
01
02
03
...
09
10
12
13
...
97
98
012
013
014
...
098
102
103
...
985
986
987
0123
0124
...
etc etc.

Любая помощь приветствуется, и если какая-либо часть моего вопроса была неясна, не стесняйтесь пояснять. Спасибо!

РЕДАКТИРОВАТЬ: Как мне сгенерировать все перестановки список чисел? не решает мой вопрос, так как приращение от "120398" до "120435" является следующим «законным» значением в последовательности.

РЕДАКТИРОВАТЬ 2: обновленный вопрос, чтобы включить желаемый результат


person clamismagic    schedule 08.12.2016    source источник
comment
Есть несколько возможностей. Один из них — инициализировать таблицу из 10 цифр значением 0; сканируйте цифры, увеличивайте счетчик для каждой встреченной цифры, затем проверяйте, больше ли какой-либо из счетчиков цифр больше 1. Другой способ — использовать strchr() итеративно, проверяя, появляется ли первая цифра в хвосте, и если нет, появляется ли вторая цифра в хвосте и так далее. Вероятно, есть и другие. Кроме того, вам следует подумать о сохранении числового «следующего значения», отформатировать его и проверить на наличие дубликатов. Это проще, чем делать приращения в строке, особенно если у вас есть переносы.   -  person Jonathan Leffler    schedule 08.12.2016
comment
genNext = "01"; не может скомпилироваться.   -  person BLUEPIXY    schedule 08.12.2016
comment
Это классическая комбинаторная задача порождения перестановок.   -  person Jean-Baptiste Yunès    schedule 08.12.2016
comment
Возможный дубликат Как мне сгенерировать все перестановки список чисел?   -  person n. 1.8e9-where's-my-share m.    schedule 08.12.2016


Ответы (3)


Ниже приведены три варианта алгоритма. Адаптируйте вариант 3 в соответствии с вашими требованиями.

Вариант 1

Это один из способов сделать это. Он реализует второстепенный вариант инициализировать таблицу из 10 цифр до 0; сканируйте цифры, увеличивайте счетчик для каждой встречающейся цифры, а затем проверяйте, превышает ли какой-либо из счетчиков цифр 1 алгоритм, который я предложил в комментарии. Тестовая функция возвращается, как только обнаруживается повторяющаяся цифра.

#include <stdio.h>
#include <stdbool.h>

enum { MAX_ITERATION = 1000000 };

static bool duplicate_digits_1(int value)
{
    char buffer[12];
    snprintf(buffer, sizeof(buffer), "%d", value);
    char digits[10] = { 0 };
    char *ptr = buffer;
    char c;
    while ((c = *ptr++) != '\0')
    {
        if (++digits[c - '0'] > 1)
            return true;
    }
    return false;
}

int main(void)
{
    int count = 0;
    for (int i = 0; i < MAX_ITERATION; i++)
    {
        if (!duplicate_digits_1(i))
        {
            count += printf(" %d", i);
            if (count > 72)
            {
                putchar('\n');
                count = 0;
            }
        }
    }
    putchar('\n');
    return 0;
}

При запуске он выдает 168 571 значение от 0 до 1 000 000, начиная с:

 0 1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29
 30 31 32 34 35 36 37 38 39 40 41 42 43 45 46 47 48 49 50 51 52 53 54 56 57
 58 59 60 61 62 63 64 65 67 68 69 70 71 72 73 74 75 76 78 79 80 81 82 83 84
 85 86 87 89 90 91 92 93 94 95 96 97 98 102 103 104 105 106 107 108 109 120
 123 124 125 126 127 128 129 130 132 134 135 136 137 138 139 140 142 143 145
 146 147 148 149 150 152 153 154 156 157 158 159 160 162 163 164 165 167 168
 169 170 172 173 174 175 176 178 179 180 182 183 184 185 186 187 189 190 192
 193 194 195 196 197 198 201 203 204 205 206 207 208 209 210 213 214 215 216
 217 218 219 230 231 234 235 236 237 238 239 240 241 243 245 246 247 248 249
 250 251 253 254 256 257 258 259 260 261 263 264 265 267 268 269 270 271 273
…
 987340 987341 987342 987345 987346 987350 987351 987352 987354 987356 987360
 987361 987362 987364 987365 987401 987402 987403 987405 987406 987410 987412
 987413 987415 987416 987420 987421 987423 987425 987426 987430 987431 987432
 987435 987436 987450 987451 987452 987453 987456 987460 987461 987462 987463
 987465 987501 987502 987503 987504 987506 987510 987512 987513 987514 987516
 987520 987521 987523 987524 987526 987530 987531 987532 987534 987536 987540
 987541 987542 987543 987546 987560 987561 987562 987563 987564 987601 987602
 987603 987604 987605 987610 987612 987613 987614 987615 987620 987621 987623
 987624 987625 987630 987631 987632 987634 987635 987640 987641 987642 987643
 987645 987650 987651 987652 987653 987654

Прежде чем решить, что это «неэффективно», измерьте это. Вы действительно тренируетесь достаточно часто, чтобы производительность стала настоящей проблемой?

Вариант 2

Создание альтернативной версии, которую я предложил в комментариях: использовать strchr() итеративно, проверяя, появляется ли первая цифра в хвосте, и если нет, появляется ли вторая цифра в хвосте, и так далее очень легко реализовать, учитывая рамки первого ответа:

static bool duplicate_digits_2(int value)
{
    char buffer[12];
    snprintf(buffer, sizeof(buffer), "%d", value);
    char *ptr = buffer;
    char c;
    while ((c = *ptr++) != '\0')
    {
        if (strchr(ptr, c) != NULL)
            return true;
    }
    return false;
}

При сравнении времени я получил следующие результаты (ng41 использует duplicate_digits_1(), а ng43 использует duplicate_digits_2().

$ time ng41 > /dev/null
real    0m0.175s
user    0m0.169s
sys     0m0.002s
$ time ng43 > /dev/null
real    0m0.201s
user    0m0.193s
sys     0m0.003s
$

Повторные тайминги обычно показывали похожие результаты, но иногда у меня ng43 работало быстрее, чем ng41 — тайминг только для одного набора из миллиона чисел не однозначен (поэтому YMMV — ваш пробег может отличаться!).

Вариант 3

Вы также можете использовать этот метод, который аналогичен «подсчету цифр», но без предварительного преобразования в строку (поэтому он должен быть быстрее).

#include <stdio.h>
#include <stdbool.h>
#include <string.h>

enum { MAX_ITERATION = 1000000 };

static bool duplicate_digits_3(int value)
{
    char digits[10] = { 0 };
    while (value > 0)
    {
        if (++digits[value % 10] > 1)
            return true;
        value /= 10;
    }
    return false;
}

int main(void)
{
    int count = 0;
    const char *pad = "";
    for (int i = 0; i < MAX_ITERATION; i++)
    {
        if (!duplicate_digits_3(i))
        {
            count += printf("%s%d", pad, i);
            pad = " ";
            if (count > 72)
            {
                putchar('\n');
                count = 0;
                pad = "";
            }
        }
    }
    putchar('\n');
    return 0;
}

Поскольку он избегает преобразования в строки, он намного быстрее. Самое медленное время, которое я получил из серии из 3 прогонов, было:

real    0m0.063s
user    0m0.060s
sys     0m0.001s

что примерно в три раза быстрее, чем любой из двух других.

Дополнительный тайминг

Я также изменил значение MAX_ITERATION на 10 000 000 и запустил синхронизацию. Конечно, есть еще много отклоненных выходов.

$ time ng41 >/dev/null

real    0m1.721s
user    0m1.707s
sys     0m0.006s
$ time ng43 >/dev/null

real    0m1.958s
user    0m1.942s
sys     0m0.008s
$ time ng47 >/dev/null

real    0m0.463s
user    0m0.454s
sys     0m0.004s
$ ng41 | wc
   69237  712891 5495951
$ ng43 | wc
   69237  712891 5495951
$ ng47 | wc
   69237  712891 5495951
$ cmp <(ng41) <(ng43)
$ cmp <(ng41) <(ng47)
$ cmp <(ng43) <(ng47)
$ 

Эти тайминги были более стабильными; вариант 1 (ng41) всегда был быстрее варианта 2 (ng43), но вариант 3 (ng47) превосходит оба со значительным отрывом.

JFTR: тестирование проводилось на macOS Sierra 10.12.1 с GCC 6.2.0 на старом 17-дюймовом MacBook Pro — начало 2011 года, процессор Intel Core i7 с тактовой частотой 2,3 ГГц и 16 ГБ ОЗУ DDR3 с частотой 1333 МГц — не то чтобы память была проблемой для этого кода. Номера программ представляют собой последовательные 2-значные простые числа, если вам интересно.


Ведущие нули тоже

Этот код генерирует нужную вам последовательность чисел (хотя он настроен только на работу до 100 000 — изменение на 1 000 000 тривиально). Это весело в мазохистском смысле.

#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

enum { MAX_ITERATIONS = 100000 };

/* lz = 1 or 0 - consider that the number has a leading zero or not */
static bool has_duplicate_digits(int value, int lz)
{
    assert(value >= 0 && value < MAX_ITERATIONS + 1);
    assert(lz == 0 || lz == 1);
    char digits[10] = { [0] = lz };
    while (value > 0)
    {
        if (++digits[value % 10] > 1)
            return true;
        value /= 10;
    }
    return false;
}

int main(void)
{
    int lz = 0;
    int p10 = 1;
    int log_p10 = 0;    /* log10(0) is -infinity - but 0 works better */
    int linelen = 0;
    const char *pad = "";

    /* The + 1 allows the cycle to reset for the leading zero pass */
    for (int i = 0; i < MAX_ITERATIONS + 1; i++)
    {
        if (i >= 10 * p10 && lz == 0)
        {
            /* Passed through range p10 .. (10*p10-1) once without leading zeros */
            /* Repeat, adding leading zeros this time */
            lz = 1;
            i = p10;
        }
        else if (i >= 10 * p10)
        {
            /* Passed through range p10 .. (10*p10-1) without and with leading zeros */
            /* Continue through next range, without leading zeros to start with */
            p10 *= 10;
            log_p10++;
            lz = 0;
        }

        if (!has_duplicate_digits(i, lz))
        {
            /* Adds a leading zero if lz == 1; otherwise, it doesn't */
            linelen += printf("%s%.*d", pad, log_p10 + lz + 1, i);
            pad = " ";
            if (linelen > 72)
            {
                putchar('\n');
                pad = "";
                linelen = 0;
            }
        }
    }
    putchar('\n');
    return 0;
}

Пример вывода (до 100 000):

0 1 2 3 4 5 6 7 8 9 01 02 03 04 05 06 07 08 09 10 12 13 14 15 16 17 18 19
20 21 23 24 25 26 27 28 29 30 31 32 34 35 36 37 38 39 40 41 42 43 45 46 47
48 49 50 51 52 53 54 56 57 58 59 60 61 62 63 64 65 67 68 69 70 71 72 73 74
75 76 78 79 80 81 82 83 84 85 86 87 89 90 91 92 93 94 95 96 97 98 012 013
014 015 016 017 018 019 021 023 024 025 026 027 028 029 031 032 034 035 036
037 038 039 041 042 043 045 046 047 048 049 051 052 053 054 056 057 058 059
061 062 063 064 065 067 068 069 071 072 073 074 075 076 078 079 081 082 083
084 085 086 087 089 091 092 093 094 095 096 097 098 102 103 104 105 106 107
108 109 120 123 124 125 126 127 128 129 130 132 134 135 136 137 138 139 140
…
901 902 903 904 905 906 907 908 910 912 913 914 915 916 917 918 920 921 923
924 925 926 927 928 930 931 932 934 935 936 937 938 940 941 942 943 945 946
947 948 950 951 952 953 954 956 957 958 960 961 962 963 964 965 967 968 970
971 972 973 974 975 976 978 980 981 982 983 984 985 986 987 0123 0124 0125
0126 0127 0128 0129 0132 0134 0135 0136 0137 0138 0139 0142 0143 0145 0146
0147 0148 0149 0152 0153 0154 0156 0157 0158 0159 0162 0163 0164 0165 0167
…
0917 0918 0921 0923 0924 0925 0926 0927 0928 0931 0932 0934 0935 0936 0937
0938 0941 0942 0943 0945 0946 0947 0948 0951 0952 0953 0954 0956 0957 0958
0961 0962 0963 0964 0965 0967 0968 0971 0972 0973 0974 0975 0976 0978 0981
0982 0983 0984 0985 0986 0987 1023 1024 1025 1026 1027 1028 1029 1032 1034
1035 1036 1037 1038 1039 1042 1043 1045 1046 1047 1048 1049 1052 1053 1054
1056 1057 1058 1059 1062 1063 1064 1065 1067 1068 1069 1072 1073 1074 1075
…
9820 9821 9823 9824 9825 9826 9827 9830 9831 9832 9834 9835 9836 9837 9840
9841 9842 9843 9845 9846 9847 9850 9851 9852 9853 9854 9856 9857 9860 9861
9862 9863 9864 9865 9867 9870 9871 9872 9873 9874 9875 9876 01234 01235 01236
01237 01238 01239 01243 01245 01246 01247 01248 01249 01253 01254 01256 01257
01258 01259 01263 01264 01265 01267 01268 01269 01273 01274 01275 01276 01278
01279 01283 01284 01285 01286 01287 01289 01293 01294 01295 01296 01297 01298
…
09827 09831 09832 09834 09835 09836 09837 09841 09842 09843 09845 09846 09847
09851 09852 09853 09854 09856 09857 09861 09862 09863 09864 09865 09867 09871
09872 09873 09874 09875 09876 10234 10235 10236 10237 10238 10239 10243 10245
10246 10247 10248 10249 10253 10254 10256 10257 10258 10259 10263 10264 10265
…
98705 98706 98710 98712 98713 98714 98715 98716 98720 98721 98723 98724 98725
98726 98730 98731 98732 98734 98735 98736 98740 98741 98742 98743 98745 98746
98750 98751 98752 98753 98754 98756 98760 98761 98762 98763 98764 98765 012345
012346 012347 012348 012349 012354 012356 012357 012358 012359 012364 012365
012367 012368 012369 012374 012375 012376 012378 012379 012384 012385 012386
…
098653 098654 098657 098671 098672 098673 098674 098675 098712 098713 098714
098715 098716 098721 098723 098724 098725 098726 098731 098732 098734 098735
098736 098741 098742 098743 098745 098746 098751 098752 098753 098754 098756
098761 098762 098763 098764 098765
person Jonathan Leffler    schedule 08.12.2016
comment
Прежде чем я поясню небольшую часть программы, я хотел бы поблагодарить вас за ваше время. Действительно ценю это. Почему для вариантов 1 и 2 для буфера установлено значение 12 вместо 8, поскольку максимально возможное количество выделенных байтов равно 8, т.е. {'1', '0', '0', '0', '0', '0', '0', '\0'}? - person clamismagic; 08.12.2016
comment
Также я заметил проблему с вашим решением. Строковые значения с 0 в качестве первого символа не учитываются в алгоритме, поскольку int используется для управления генерацией значений, а не char[] или char *. Интересно, есть ли решения этой проблемы? - person clamismagic; 08.12.2016
comment
Буфер установлен на 12, так что даже если -2 000 000 000 отформатировано, переполнения буфера не произойдет — предполагается 32-битный int. Это означало, что я мог изменить ограничение, например, без необходимости менять код где-либо еще. - person Jonathan Leffler; 08.12.2016
comment
Что касается проблемы с ведущими нулями, мне не ясно, как ведущие нули влияют на проблему/решение. Если вам нужны ведущие нули и шесть цифр, наименьшее число — 012345. Ваш вопрос не показывает желаемого результата, поэтому я его не рассматривал — на самом деле, я не уверен, как его следует рассматривать. У меня есть несколько вариантов пакета функций в коде. Поскольку вам нужен строковый вывод, Вариант 1 и Вариант 2 генерируют строку во время обработки, но арифметическая проверка в Варианте 3 выполняется быстрее и может быть адаптирована. У меня есть версии всех трех алгоритмов с функциональным интерфейсом; нужна очистка. - person Jonathan Leffler; 08.12.2016
comment
Я обновил вопрос, включив в него желаемый результат. Надеюсь, вы сможете его изучить! огромное спасибо :) - person clamismagic; 09.12.2016
comment
Ой! Кто сказал вам, что ведущие нули — это хорошая идея? Это требование значительно усложняет числовую обработку; отсканировав 0..9 без начального нуля, вы должны повторно отсканировать его с начальным нулем. Потом 10..99 без и потом 10..99 с; затем 100..999 без и затем с; и т. д. А в режиме «ведущий ноль» вам нужно предварительно отсчитать ноль. Самая большая проблема — это структура данных, необходимая для отслеживания «степени десяти», над которой вы работаете, и того, делали ли вы «начальные нули» в этом диапазоне или нет. неудобный. Очень прикольно! Ты действительно уверен, что хочешь этого? У меня ужасное искушение позволить тебе сделать это. - person Jonathan Leffler; 09.12.2016
comment
хорошо.. легко понять, ясно и лаконично. Спасибо еще раз! :) - person clamismagic; 10.12.2016

Использование цикла (от 0 до 999 999 включительно) и отбрасывание значений с повторяющимися цифрами кажется мне самой простой реализацией.

Функцию reject-if-duplicate-digits можно сделать довольно быстрой. Рассмотрим, например,

int has_duplicate_digits(unsigned int value)
{
    unsigned int  digit_mask = 0U;

    do {
        /* (value % 10U) is the value of the rightmost
           decimal digit of (value).
           1U << (value % 10U) refers to the value of
           the corresponding bit -- bit 0 to bit 9. */
        const unsigned int  mask = 1U << (value % 10U);

        /* If the bit is already set in digit_mask,
           we have a duplicate digit in value. */
        if (mask & digit_mask)
            return 1;

        /* Mark this digit as seen in the digit_mask. */
        digit_mask |= mask;

        /* Drop the rightmost digit off value.
           Note that this is integer division. */
        value /= 10U;

        /* If we have additional digits, repeat loop. */
    } while (value);

    /* No duplicate digits found. */
    return 0;
}
person Nominal Animal    schedule 08.12.2016

На самом деле это классическая комбинаторная задача. Ниже приведено доказательство реализации концепции с использованием алгоритма L в TAOCP 7.2.1.2 и алгоритма T в TAOCP 7.2.1.3. Могут быть какие-то ошибки. Подробности смотрите в алгоритмах.

Вот небольшое объяснение. Пусть t будет количеством цифр. Для t == 10 проблема состоит в том, чтобы сгенерировать все t! перестановки множества {0,1,2,...,9} в лексикографическом порядке (алгоритм L).

Для t > 0 и t ‹ 10 это разбивается на 1) Сгенерируйте все комбинации t цифр из 10 возможных цифр. 2). Для каждой комбинации сгенерируйте все t! перестановки.

Наконец, вы можете отсортировать все 10! + 10! / 2 + 10! / 3! + .. + 10 результатов. Сначала сортировка может показаться дорогой. Но во-первых, генерация комбинации идет уже в лексическом порядке. Во-вторых, перестановки генерируются также в лексическом порядке. Таким образом, последовательность на самом деле очень регулярна. QSort здесь не так уж и плох.

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

static inline int compare_str(const void *a, const void *b)
{
    return strcmp(a, b);
}

static inline int compare_char(const void *a, const void *b)
{
    char ca = *((char *) a);
    char cb = *((char *) b);

    if (ca < cb)
        return -1;
    if (ca > cb)
        return 1;
    return 0;
}


// Algorithm L in TAOCP 7.2.1.2
static inline char *algorithm_l(int n, const char *c, char *r)
{
    char a[n + 1];
    memcpy(a, c, n);
    a[n] = '\0';
    qsort(a, n, 1, compare_char);
    while (1) {
        // L1. [Visit]
        memcpy(r, a, n + 1);
        r += n + 1;

        // L2. [Find j]
        int j = n - 1;
        while (j > 0 && a[j - 1] >= a[j])
            --j;
        if (j == 0)
            break;

        // L3. [Increase a[j - 1]]
        int l = n;
        while (l >= 0 && a[j - 1] >= a[l - 1])
            --l;
        char tmp = a[j - 1];
        a[j - 1] = a[l - 1];
        a[l - 1] = tmp;

        // L4. [Reverse a[j]...a[n-1]]
        int k = j + 1;
        l = n;
        while (k < l) {
            char tmp = a[k - 1];
            a[k - 1] = a[l - 1];
            a[l - 1] = tmp;
            ++k;
            --l;
        }
    }

    return r;
}

// Algorithm T in TAOCP 7.2.1.2
static inline void algorithm_t(int t, char *r)
{
    assert(t > 0);
    assert(t < 10);

    // Algorithm T in TAOCP 7.2.1.3
    // T1. [Initialize]
    char c[12]; // the digits
    for (int i = 0; i < t; ++i)
        c[i] = '0' + i;
    c[t] = '9' + 1;
    c[t + 1] = '0';
    char j = t;
    char x = '0';

    while (1) {
        // T2. [Visit]
        r = algorithm_l(t, c, r);

        if (j > 0) {
            x = '0' + j;
        } else {
            // T3. [Easy case?]
            if (c[0] + 1 < c[1]) {
                ++c[0];
                continue;
            }
            j = 2;

            // T4. [Find j]
            while (1) {
                c[j - 2] = '0' + j - 2;
                x = c[j - 1] + 1;
                if (x != c[j])
                    break;
                ++j;
            }

            // T5. [Done?]
            if (j > t)
                break;
        }

        // T6. [Increase c[j - 1]]
        c[j - 1] = x;
        --j;
    }
}

static inline void generate(int t)
{
    assert(t >= 0 && t <= 10);

    if (t == 0)
        return;

    int n = 1;
    int k = 10;
    for (int i = 1; i <= t; ++i, --k)
        n *= k;
    char *r = (char *) malloc((t + 1) * n);
    if (t == 10) {
        algorithm_l(10, "0123456789", r);
    } else {
        algorithm_t(t, r);
    }
    qsort(r, n, t + 1, strcmpv);
    for (int i = 0; i < n; ++i, r += t + 1)
        printf("%s\n", r);
}

int main()
{
    for (int t = 1; t <= 10; ++t)
        generate(t);
}

Эффективность: это реализация не очень эффективна. Это прямой перевод из алгоритма для облегчения понимания. Однако это все же намного эффективнее, чем повторение 10 ^ 10 чисел. Для генерации всех чисел от 0 до 9876543210 требуется около 2,5 секунд. Это включает время записи их в файл, выходной файл размером 94 МБ, с одним числом в строке. Для ввода до 6 цифр требуется около 0,05 секунды.

Если вы хотите, чтобы эти числа шли в том порядке, который вы хотите в программе, может быть лучше сгенерировать числа, как указано выше, чтобы подготовить таблицу и использовать ее позже. Даже для таблицы от 0 до 9876543210 имеется менее десяти миллионов чисел, что не так уж и много для современных компьютеров. В вашем случае до шести цифр всего меньше миллиона номеров.

person Yan Zhou    schedule 09.12.2016