#c
#c
Вопрос:
Я создаю программу на языке Си, которая предназначена для ввода чисел и хранения их в массиве, но у меня есть ограничение, что одно и то же число нельзя вводить дважды. Есть идеи, как это реализовать?
Вот мой код:
#includelt;stdlib.hgt; #include lt;stdio.hgt; int main(){ int n=0, num=0, i, j; int N[n]; printf("Write the amount of values that you will introducen"); do { scanf("%d",amp;n); if(nlt;0) printf("Invalid number, try againn"); } while (nlt;0); printf("Remember to use numbers between 0 and 50n"); for(i=0; ilt;n; i ) { do { scanf("%d",amp;num); //If a repeated value is entered, show a message and request the number again if(numlt;0 || numgt;50){ printf("Invalid number, try againn"); }else{ N[i]=num; printf("- - - - -n"); } } while (numlt;0 || numgt;50); getchar(); getchar(); return 0; } }
Комментарии:
1. Когда пользователь вводит номер, вам нужно будет выполнить поиск в массиве существующих номеров, чтобы узнать, используется ли это значение уже, и соответствующим образом обработать этот случай.
2. Ну, вы позволяете пользователю вводить значение и, если оно уже было в массиве, выводите сообщение и возвращаете запрос на ввод. Примечание: Массив длины 0 (ваш N[n], с n == 0) является нестандартным и в любом случае не позволяет присваивать значения каким-либо элементам, потому что их нет. Простой способ состоит в том, чтобы определить массив, достаточно большой, чтобы охватить все большинство случаев, и проверить максимальное количество входных данных.
3. Вместо поиска O(N^2) для каждого добавления следует отметить, что ваш диапазон ввода сильно ограничен значениями в диапазоне [0, 250]. Технически вы можете поддерживать четыре 64-разрядных целых числа и использовать побитовые операции для записи того, какое значение было добавлено.
4. Действительно… Магические числа нежелательны. Именованные константы лучше. Это также помогло бы с той частью вашей программы, которая уже отвлекается от логики, где она просит пользователя «использовать числа от 0 до 250» , но затем отклоняет все, что больше 50.
5. Если у вас небольшой (например, меньше миллиона) диапазон возможных чисел, которые может ввести пользователь, вы также можете просто создать массив bool или int, в котором вы храните флаг для каждого введенного числа… глупо, но просто.
Ответ №1:
Поскольку ваш диапазон значений очень мал, очень легко записать тот факт, что число находится в вашем списке, установив один бит.
Действительно, у вас есть 51 возможное значение в диапазоне [0, 50], поэтому вы можете представить их 64-разрядным целым числом. Стандартные целочисленные типы находятся там lt;stdint.hgt;
, где вы найдете uint64_t
.
uint64_t in_list = 0; int numbers[51]; int count = 0; for(int num; count lt;= 50 amp;amp; 1 == scanf("%d", amp;num); ) { if (num gt;= 0 amp;amp; num lt;= 50) { if (!(in_list amp; (1ULL lt;lt; num))) { numbers[count ] = num; in_list |= (1ULL lt;lt; num); } else { printf("Value %d is already added.n", num); } } }
Здесь все еще присутствует неприятное количество жестко закодированных значений, но их можно улучшить и даже расширить для более высоких диапазонов. Для простоты давайте предположим, что ноль всегда является минимумом. И поскольку нам понадобится массив для битов, нам даже не нужно использовать 64-разрядные значения. Просто персонажи прекрасны.
#include lt;stdint.hgt; #include lt;stdio.hgt; #define MAX_NUM 250 int main() { uint8_t in_list[(MAX_NUM / 8) 1] = { }; int numbers[MAX_NUM 1]; int count = 0; for(int num; count lt;= MAX_NUM amp;amp; 1 == scanf("%d", amp;num); ) { if (num gt;= 0 amp;amp; num lt;= MAX_NUM) { int char_select = num / 8; int bit_mask = 1 lt;lt; (num % 8); if (!(in_list[char_select] amp; bit_mask)) { numbers[count ] = num; in_list[char_select] |= bit_mask; } else { printf("Value %d is already added.n", num); } } else { printf("Enter a value between 0 and %d.n", MAX_NUM); } } }
Ответ №2:
Когда пользователь вводит новый номер, используйте for
цикл для просмотра всех номеров, уже содержащихся в массиве. Если вы обнаружите, что номер уже есть в массиве, то заставьте их ввести другой номер. Таким образом, ваш внутренний цикл будет выглядеть примерно так:
while (1) { scanf("%d",amp;num); // Validation #1: value if (num lt; 0 || num gt; 50) { printf("Numero no valido, ingrese de nuevo el valorn"); continue; } // Validation #2: uniqueness bool duplicate = false; for (int k = 0; k lt; i; k ) { if (N[k] == num) { printf("Number is a duplicate.n"); duplicate = true; break; } } if (duplicate) { continue; } N[i] = num; break; }
Обратите внимание, что мы используем continue
, чтобы вернуться к началу текущего цикла и выпрыгнуть break
из него. Нет простого способа break
или continue
цикла на один уровень выше текущего (если вы не разрешите использовать goto
), поэтому я должен использовать логический флаг с именем duplicate
.
Кстати, вам, возможно, потребуется включить stdbool.h
, чтобы использовать этот bool
тип.
Ответ №3:
Как только пользователь добавит значение, переместите его в массив. Затем пользователь снова вводит значение, просматривает массив, чтобы проверить, существует ли оно уже. Если он существует, то пользователь уже вводил это значение ранее. В этом случае не позволяйте пользователю вводить одно и то же значение. Если нет, то пусть они. ПРОСТО 🙂