I have found the following interesting challenge on the web:
Deficient Numbers
A number is considered deficient if the sum of its factors is less than twice that number.
For example: 10 is a deficient number because its factors are 1, 2, 5, 10 and their sum is 1 + 2 + 5 + 10 = 18 which is less than 10 * 2 = 20.
Challenges
Easy level: write a program to verify whether a given number is deficient or not.
Medium level: write a program to find all the deficient numbers in a range.
Hard level: given a number, write a program to display its factors, their sum and then verify whether it's deficient or not.
I implemented it in C:
#include <stdlib.h>
#include <stdio.h>
#define DEBUG 1
/*
XXX EASY-OPTION IMPLEMENTATION
A list data structure is used to store the factors of a given number.
A simple boolean-like data type is then returned by the main isDeficient function.
*/
typedef enum bool bool;
enum bool {
false, true
};
typedef struct ListElem ListElem;
struct ListElem {
int value;
ListElem* next;
};
typedef struct List List;
struct List {
ListElem* head;
int length;
};
List* listInit() {
List* list = (List*) malloc(sizeof(List));
list->head = NULL;
list->length = 0;
return list;
}
ListElem* listAppend(List* list, int elem) {
ListElem* newHead = (ListElem*) malloc(sizeof(ListElem));
newHead->value = elem;
newHead->next = list->head;
list->head = newHead;
list->length++;
return newHead;
}
void listPrint(List* list) {
ListElem* head = list->head;
printf("list > ");
do {
printf("%i ", head->value);
head = head->next;
} while (head != NULL);
printf("\n");
}
void listSort(List* list) {
int inactive = 0, debug = 0;
while (inactive < list->length - 1) {
inactive = 0;
ListElem* previous = NULL; // Initialise pointers...
ListElem* current = list->head;
ListElem* next = list->head->next;
for (int i = 0; i < list->length - 1; i++) {
if (current->value > next->value) {
if (i != 0)
previous->next = next;
current->next = next->next;
next->next = current;
if (i == 0) // Update list head...
list->head = next;
inactive = 0;
previous = next;
next = current->next;
} else {
inactive++;
previous = current;
current = next;
next = next->next;
}
}
debug += list->length - 1;
}
#if DEBUG
printf("Debug info: sorting toke %i iterations.\n", debug);
#endif
}
bool isInList(List* l, int elem) {
ListElem* listElem = l->head;
for (int i = 0; i < l->length; i++) {
int value = listElem->value;
if (value == elem)
return true;
listElem = listElem->next;
}
return false;
}
List* findFactors(int n) {
List* factors = listInit();
int tempRes = 0;
int debug = 1;
listAppend(factors, 1);
if (!(isInList(factors, n))) // Avoid duplicates only when n = 1...
listAppend(factors, n);
for (int d = 2; d <= n / 2; d++) { // The <= operator is necessary when n = 4 or the iterations don't start...
if (!(n % d)) {
tempRes = n / d;
if (isInList(factors, tempRes))
break;
listAppend(factors, d);
if (!(isInList(factors, tempRes))) // Avoid duplicate entries when the divisor and the result of the division are the same...
listAppend(factors, tempRes);
}
debug++;
}
#if DEBUG
printf("Debug info: %i's factors found with %i iterations.\n", n, debug);
listSort(factors);
listPrint(factors);
#endif
return factors;
}
int calculateSum(List* list) {
int sum = 0;
ListElem* listElem = list->head;
for (int i = 0; i < list->length; i++) {
sum += listElem->value;
listElem = listElem->next;
}
return sum;
}
bool isDeficient(int n) {
List* f = findFactors(n);
if (calculateSum(f) < 2 * n)
return true;
return false;
}
// XXX MEDIUM-OPTION IMPLEMENTATION
List* findDeficients(int min, int max) {
List* deficients = listInit();
for (int i = min; i <= max; i++) {
if (isDeficient(i))
listAppend(deficients, i);
}
return deficients;
}
// XXX HARD-OPTION IMPLEMENTATION
int main(int argc, char* argv[]) {
if (argc != 2) {
printf("Error: arguments are not one!\n");
return 0;
}
int n = atoi(argv[1]);
List* facts = findFactors(n);
printf("The factors of %i are:\n", n);
listPrint(facts);
int sum = calculateSum(facts);
printf("Their sum is:\n%i\n", sum);
if (sum < 2 * n)
printf("%i IS deficient.\n", n);
else
printf("%i IS NOT deficient.\n", n);
return 0;
}
What about it? In particular, I would like to ask you for a feedback about the List structure and the sorting function. Is their code readable and understandable? Could it be improved with regard to performance?
printf("Error: arguments are not one!\n")
1) Error messages should be output tostderr
rather thanstdout
. 2) when the error message is about the command line parameters being missing, It is typical to output ausage
message similar to:fprintf( stderr, "USAGE: %s factors\n", argv[0] );
\$\endgroup\$printf("Error: arguments are not one!\n"); return 0;
Returning 0 frommain()
indicates success, but the program was not successful. Suggest usingexit( EXIT_FAILURE );
(both the constant andexit()
are found instdlib.h
\$\endgroup\$