Я пытался написать программу на C, которая по массиву с плавающей запятой определяет, сколько существует каждого числа, а затем печатает каждое число и соответствующую ему частоту. Это упражнение из моего колледжа (курс информатики). В общей сложности я, должно быть, потратил около 3 часов, пытаясь обдумать решение, и просто не могу думать. Хотя я уверен, что это мелочь.
Я не мог разработать ничего, что, по моему мнению, сработало бы. Если я пойду в VS и попытаюсь что-то запрограммировать, чтобы решить эту проблему, мой разум застынет в тот момент, когда мне нужно будет подумать, как представить механизм, который заставляет компьютер «знать», если число в данной позиции и его частота уже учтены. for before в массиве частот (int).
(Для всеобщего понимания, я изменил текст выше после публикации, потому что забыл слово «массив» и неправильно перевел на английский. На португальском (мой родной язык) это «ветор», поэтому я предположил, что это «вектор», это еще одно существующее английское слово. Однако оно, похоже, не используется так часто, как «массив», для обозначения этого в дискуссиях по английскому программированию.)
#include <stdio.h>
#define VEC_LEN 8
int main(void)
{
int vFreq[VEC_LEN] = { 0, 0, 0, 0, 0, 0, 0 ,0 };
float vNums[VEC_LEN] = { 1.5, -4.8, 2.9, 6.1, 4.2, 1.5, 2.9, 6.1 };
for (int i = 0; i < VEC_LEN; i++)
{
float n = vNums[i];
for (int j = 0; j < VEC_LEN; j++)
{
if (n == vNums[j])
vFreq[i]++;
// then my brain freezes
}
}
return 0;
}
Возможно, вы хотите добавить третий массив, например float vCountedNums[VEC_LEN];, и когда вы впервые увеличиваете vFreq[i] до 1, также установите vCountedNums[i] = n;. Таким образом, у вас будет возможность «запомнить», что счетчик, присутствующий в vFreq[i], соответствует значению с плавающей запятой, указанному в vCountedNums[i].
Вы уверены, что все числа конечны (ни бесконечности, ни NaN) и что вам не придется иметь дело с 0.0 и -0.0?
@NateEldredge да
Разрешено ли вам изменять массив?
@Gerhardh Да, я думаю, никаких ограничений на этот счет нет. Просто нужно напечатать каждое число и его частоты в каждой строке вывода.





Я не буду давать полное решение на языке C. Поскольку вы проходите «курс информатики», я думаю, вам лучше решить эту задачу самостоятельно. Но вот описание алгоритма, который вы можете реализовать.
Начните с сортировки массива vNums. Для этого вы будете использовать qsort.
После сортировки ваш массив будет выглядеть так:
{ -4.8, 1.5, 1.5, 2.9, 2.9, 4.2, 6.1, 6.1 }
Затем вы перебираете отсортированный массив и подсчитываете последовательные равные элементы. Когда два последовательных элемента равны, увеличьте счетчик и перейдите к следующему элементу. Если два последовательных элемента различаются, вы печатаете первый вместе со значением счетчика, а затем перезапускаете подсчет. В псевдокоде что-то вроде:
count = 1
current_value = sorted_array[0]
index = 1
while index < number_of_element_in_sorted_array
{
if (current_value == sorted_array[index])
{
count = count + 1
}
else
{
print current_value and count
count = 1
current_value = sorted_array[index]
}
index = index + 1
}
print current_value and count
@rafamussap причина сортировки - ускорить работу программы. Учтите следующее: при сортировке одинаковые числа также являются соседними в массиве, поэтому вы можете сканировать отсортированный массив только один раз. Вы начинаете отсчет со следующего числа, пока оно не станет отличаться от предыдущего числа, затем записываете счет и возобновляете счет с этого числа. Если массив не отсортирован, придется заново сканировать весь массив и отслеживать, какие числа вы уже учли. Попробуйте с {1.4, -9.1, 2.0, 1.4, 5.6, 1.4, -9.1}. К тому времени, как вы увидите второй 1.4, вы должны знать, что вы уже это учли.
@rafamussap. Если можно, общее предложение. Когда вы попытаетесь решить подобные упражнения, забудьте о компьютере. Возьмите ручку и бумагу и нарисуйте набросок, изображающий ситуацию (в данном случае список чисел). Когда вы станете более опытным, вы сможете делать это в уме, но пытаться решить эти проблемы без четкого представления о том, что происходит, очень и очень сложно (и может разочаровывать). Только после того, как вы уверены в том, ЧТО вам нужно сделать, вы можете сосредоточиться на том, чтобы рассказать компьютеру, КАК это сделать.
Как упоминал Джереми, вам нужен третий массив [возможно].
vNums исходный массив с числамиvMatch содержит значение из vNums для данного сегмента частоты.vFreq содержит количество для данного сегмента частотыИли, используя struct, последние два массива можно объединить в один [предпочтительно]
Вот исправленный код для версии с тремя массивами:
#include <stdio.h>
#define VEC_LEN 8
int
main(void)
{
int vFreq[VEC_LEN] = { 0, 0, 0, 0, 0, 0, 0, 0 };
double vMatch[VEC_LEN] = { 0 };
double vNums[VEC_LEN] = { 1.5, -4.8, 2.9, 6.1, 4.2, 1.5, 2.9, 6.1 };
int freqcount = 0;
int freqidx;
// loop through all values
for (int i = 0; i < VEC_LEN; i++) {
// get current value
double n = vNums[i];
// look for match to already existing entry in frequency table
for (freqidx = 0; freqidx < freqcount; ++freqidx) {
if (n == vMatch[freqidx])
break;
}
// no existing match found -- add new entry
if (freqidx >= freqcount) {
vMatch[freqidx] = n;
freqcount += 1;
}
// increase the frequency count
vFreq[freqidx] += 1;
}
// print all frequencies
for (freqidx = 0; freqidx < freqcount; ++freqidx)
printf("Value: %.1f Frequency: %d\n",vMatch[freqidx],vFreq[freqidx]);
return 0;
}
Вот результат:
Value: 1.5 Frequency: 2
Value: -4.8 Frequency: 1
Value: 2.9 Frequency: 2
Value: 6.1 Frequency: 2
Value: 4.2 Frequency: 1
Вот версия, которая имеет два массива и использует struct и указатель:
#include <stdio.h>
#define VEC_LEN 8
struct freq {
double freq_match;
int freq_count;
};
int
main(void)
{
struct freq freq_table[VEC_LEN] = { 0 };
double vNums[VEC_LEN] = { 1.5, -4.8, 2.9, 6.1, 4.2, 1.5, 2.9, 6.1 };
int freqcount = 0;
int freqidx;
struct freq *freq;
// loop through all values
for (int i = 0; i < VEC_LEN; i++) {
// get current value
double n = vNums[i];
// look for match to already existing entry in frequency table
freq = freq_table;
for (freqidx = 0; freqidx < freqcount; ++freqidx, ++freq) {
if (n == freq->freq_match)
break;
}
// no existing match found -- add new entry
if (freqidx >= freqcount) {
freq->freq_match = n;
freqcount += 1;
}
// increase the frequency count
freq->freq_count += 1;
}
// print all frequencies
freq = freq_table;
for (freqidx = 0; freqidx < freqcount; ++freqidx, ++freq)
printf("Value: %.1f Frequency: %d\n",freq->freq_match,freq->freq_count);
return 0;
}
Вот вывод программы:
Value: 1.5 Frequency: 2
Value: -4.8 Frequency: 1
Value: 2.9 Frequency: 2
Value: 6.1 Frequency: 2
Value: 4.2 Frequency: 1
Вот расширенная версия, которая исключает freqidx и использует макрос для циклов for:
#include <stdio.h>
#define VEC_LEN 8
struct freq {
double freq_match;
int freq_count;
};
#define FREQ_FORALL \
freq = &freq_table[0]; freq < &freq_table[freqcount]; ++freq
int
main(void)
{
struct freq freq_table[VEC_LEN] = { 0 };
double vNums[VEC_LEN] = { 1.5, -4.8, 2.9, 6.1, 4.2, 1.5, 2.9, 6.1 };
int freqcount = 0;
struct freq *freq;
// loop through all values
for (int i = 0; i < VEC_LEN; i++) {
// get current value
double n = vNums[i];
// look for match to already existing entry in frequency table
for (FREQ_FORALL) {
if (n == freq->freq_match)
break;
}
// no existing match found -- add new entry
if (freq >= &freq_table[freqcount]) {
freq->freq_match = n;
freqcount += 1;
}
// increase the frequency count
freq->freq_count += 1;
}
// print all frequencies
for (FREQ_FORALL)
printf("Value: %.1f Frequency: %d\n",freq->freq_match,freq->freq_count);
return 0;
}
Кстати: зачем использовать объекты
floatс константамиdouble? В C здесь более идиоматично использовать объектыdouble.