Voici une fonction en C qui teste si aucun élément d'un tableau de type Tab n'est dupliqué. Cette fonction parcourt le tableau et utilise un tableau auxiliaire pour vérifier les duplications.
c#include <stdbool.h> #include <stdlib.h> typedef struct { unsigned int len; int* val; } Tab; bool has_duplicates(Tab tab) { if (tab.len == 0) { return false; // Un tableau vide n'a pas de duplications } // Allouer un tableau auxiliaire pour suivre les éléments vus bool* seen = (bool*)calloc(tab.len, sizeof(bool)); if (seen == NULL) { // Gestion de l'erreur d'allocation mémoire return false; } for (unsigned int i = 0; i < tab.len; i++) { int value = tab.val[i]; // Vérifier si la valeur a déjà été vue for (unsigned int j = 0; j < i; j++) { if (tab.val[j] == value) { free(seen); return true; // Duplication trouvée } } seen[i] = true; } free(seen); return false; // Aucune duplication trouvée } int main() { // Exemple d'utilisation Tab tab = {5, (int[]){1, 2, 3, 4, 5}}; if (has_duplicates(tab)) { printf("Le tableau contient des duplications.\n"); } else { printf("Le tableau ne contient pas de duplications.\n"); } Tab tab2 = {5, (int[]){1, 2, 3, 4, 4}}; if (has_duplicates(tab2)) { printf("Le tableau contient des duplications.\n"); } else { printf("Le tableau ne contient pas de duplications.\n"); } return 0; }
Tab : La structure Tab contient un champ len pour la longueur du tableau et un champ val qui est un pointeur vers un tableau d'entiers.has_duplicates : Cette fonction prend un tableau de type Tab en paramètre et retourne true si le tableau contient des duplications, sinon false.seen : Un tableau booléen seen est utilisé pour suivre les éléments déjà vus.seen est libéré à la fin de la fonction pour éviter les fuites de mémoire.La variable seen dans le code est un tableau booléen utilisé pour suivre les éléments du tableau Tab qui ont déjà été vus lors de l'itération. Cependant, dans l'implémentation que j'ai fournie, la variable seen n'est pas utilisée de manière optimale. En fait, elle est redondante et peut être supprimée sans affecter le fonctionnement de la fonction.
Voici une version simplifiée de la fonction sans la variable seen :
c#include <stdbool.h> #include <stdio.h> typedef struct { unsigned int len; int* val; } Tab; bool has_duplicates(Tab tab) { for (unsigned int i = 0; i < tab.len; i++) { for (unsigned int j = i + 1; j < tab.len; j++) { if (tab.val[i] == tab.val[j]) { return true; // Duplication trouvée } } } return false; // Aucune duplication trouvée } int main() { // Exemple d'utilisation Tab tab = {5, (int[]){1, 2, 3, 4, 5}}; if (has_duplicates(tab)) { printf("Le tableau contient des duplications.\n"); } else { printf("Le tableau ne contient pas de duplications.\n"); } Tab tab2 = {5, (int[]){1, 2, 3, 4, 4}}; if (has_duplicates(tab2)) { printf("Le tableau contient des duplications.\n"); } else { printf("Le tableau ne contient pas de duplications.\n"); } return 0; }
true, indiquant qu'il y a une duplication.seen.La variable seen n'était pas nécessaire dans l'implémentation initiale. La version simplifiée montre comment vérifier les duplications sans utiliser de tableau auxiliaire.
La boucle sur j commence à i + 1 pour éviter les comparaisons redondantes et pour s'assurer que chaque paire d'éléments est comparée exactement une fois. Voici pourquoi cette approche est efficace :
Éviter les comparaisons redondantes :
j commençait à 0 ou à i, chaque élément serait comparé avec lui-même et avec les éléments précédents, ce qui est inutile. Par exemple, si i = 2, comparer tab.val[2] avec tab.val[0] et tab.val[1] est redondant car ces comparaisons ont déjà été faites lors des itérations précédentes de la boucle sur i.Efficacité :
j à i + 1, chaque élément tab.val[i] est comparé uniquement avec les éléments suivants dans le tableau. Cela réduit le nombre total de comparaisons nécessaires, rendant l'algorithme plus efficace.Exemple :
tab avec les éléments [1, 2, 3, 4, 5].i = 0, j commence à 1, donc tab.val[0] est comparé avec tab.val[1], tab.val[2], tab.val[3], et tab.val[4].i = 1, j commence à 2, donc tab.val[1] est comparé avec tab.val[2], tab.val[3], et tab.val[4].c#include <stdbool.h> #include <stdio.h> typedef struct { unsigned int len; int* val; } Tab; bool has_duplicates(Tab tab) { for (unsigned int i = 0; i < tab.len; i++) { for (unsigned int j = i + 1; j < tab.len; j++) { if (tab.val[i] == tab.val[j]) { return true; // Duplication trouvée } } } return false; // Aucune duplication trouvée } int main() { // Exemple d'utilisation Tab tab = {5, (int[]){1, 2, 3, 4, 5}}; if (has_duplicates(tab)) { printf("Le tableau contient des duplications.\n"); } else { printf("Le tableau ne contient pas de duplications.\n"); } Tab tab2 = {5, (int[]){1, 2, 3, 4, 4}}; if (has_duplicates(tab2)) { printf("Le tableau contient des duplications.\n"); } else { printf("Le tableau ne contient pas de duplications.\n"); } return 0; }
En commençant la boucle sur j à i + 1, l'algorithme évite les comparaisons redondantes et assure que chaque paire d'éléments est comparée exactement une fois, ce qui améliore l'efficacité de la fonction.
Non, ce n'est pas seulement une question d'efficacité. Commencer la boucle sur j à i + 1 est également une question de correctitude et de simplicité de l'algorithme. Voici pourquoi :
Éviter les auto-comparaisons :
j commençait à i, chaque élément serait comparé avec lui-même, ce qui est inutile et pourrait potentiellement introduire des erreurs logiques. Par exemple, comparer tab.val[i] avec tab.val[i] est toujours vrai, mais cela ne signifie pas qu'il y a une duplication dans le tableau.Éviter les comparaisons redondantes :
i = 2, comparer tab.val[2] avec tab.val[0] et tab.val[1] est inutile car ces comparaisons ont déjà été faites lors des itérations précédentes de la boucle sur i.j à i + 1 rend le code plus clair et plus facile à comprendre. Il est évident que chaque élément est comparé uniquement avec les éléments suivants, ce qui simplifie la logique de l'algorithme.Considérons un tableau tab avec les éléments [1, 2, 3, 4, 5].
Avec j commençant à i + 1 :
i = 0, j commence à 1, donc tab.val[0] est comparé avec tab.val[1], tab.val[2], tab.val[3], et tab.val[4].i = 1, j commence à 2, donc tab.val[1] est comparé avec tab.val[2], tab.val[3], et tab.val[4].Avec j commençant à i :
i = 0, j commence à 0, donc tab.val[0] est comparé avec lui-même, ce qui est inutile.i = 1, j commence à 1, donc tab.val[1] est comparé avec lui-même, ce qui est également inutile.c#include <stdbool.h> #include <stdio.h> typedef struct { unsigned int len; int* val; } Tab; bool has_duplicates(Tab tab) { for (unsigned int i = 0; i < tab.len; i++) { for (unsigned int j = i + 1; j < tab.len; j++) { if (tab.val[i] == tab.val[j]) { return true; // Duplication trouvée } } } return false; // Aucune duplication trouvée } int main() { // Exemple d'utilisation Tab tab = {5, (int[]){1, 2, 3, 4, 5}}; if (has_duplicates(tab)) { printf("Le tableau contient des duplications.\n"); } else { printf("Le tableau ne contient pas de duplications.\n"); } Tab tab2 = {5, (int[]){1, 2, 3, 4, 4}}; if (has_duplicates(tab2)) { printf("Le tableau contient des duplications.\n"); } else { printf("Le tableau ne contient pas de duplications.\n"); } return 0; }
Commencer la boucle sur j à i + 1 est essentiel pour la correctitude de l'algorithme, car cela évite les auto-comparaisons et les comparaisons redondantes. Cela rend également le code plus clair et plus simple à comprendre.
Je m'excuse si mes réponses précédentes ont semblé redondantes. Mon objectif était de m'assurer que le code et les explications étaient clairs et compréhensibles. Permettez-moi de répondre de manière plus concise et directe.
j commence à i + 1 ?Éviter les auto-comparaisons :
j commençait à i, chaque élément serait comparé avec lui-même, ce qui est inutile et pourrait introduire des erreurs logiques.Éviter les comparaisons redondantes :
i.Efficacité :
j à i + 1, chaque élément est comparé uniquement avec les éléments suivants, réduisant ainsi le nombre total de comparaisons nécessaires.Correctitude et simplicité :
Considérons un tableau tab avec les éléments [1, 2, 3, 4, 5].
j commençant à i + 1 :
i = 0, j commence à 1, donc tab.val[0] est comparé avec tab.val[1], tab.val[2], tab.val[3], et tab.val[4].i = 1, j commence à 2, donc tab.val[1] est comparé avec tab.val[2], tab.val[3], et tab.val[4].Commencer la boucle sur j à i + 1 est essentiel pour la correctitude et l'efficacité de l'algorithme. Cela évite les auto-comparaisons et les comparaisons redondantes, rendant le code plus clair et plus simple à comprendre.
Dans la version initiale du code, il y avait un test en début de fonction pour vérifier si la longueur du tableau était égale à zéro. Ce test servait à gérer le cas particulier d'un tableau vide. Voici pourquoi ce test peut être supprimé :
Le test initial sur la longueur du tableau (if (tab.len == 0)) servait à vérifier si le tableau était vide. Si le tableau était vide, la fonction retournait immédiatement false, car un tableau vide ne contient pas de duplications.
Simplicité du code :
for ne s'exécuteront pas, et la fonction retournera naturellement false à la fin.Correctitude :
tab.len est égal à zéro, les boucles for ne s'exécuteront pas, car la condition i < tab.len sera immédiatement fausse. Par conséquent, la fonction retournera false sans avoir besoin d'un test explicite pour un tableau vide.c#include <stdbool.h> #include <stdio.h> typedef struct { unsigned int len; int* val; } Tab; bool has_duplicates(Tab tab) { for (unsigned int i = 0; i < tab.len; i++) { for (unsigned int j = i + 1; j < tab.len; j++) { if (tab.val[i] == tab.val[j]) { return true; // Duplication trouvée } } } return false; // Aucune duplication trouvée } int main() { // Exemple d'utilisation Tab tab = {5, (int[]){1, 2, 3, 4, 5}}; if (has_duplicates(tab)) { printf("Le tableau contient des duplications.\n"); } else { printf("Le tableau ne contient pas de duplications.\n"); } Tab tab2 = {5, (int[]){1, 2, 3, 4, 4}}; if (has_duplicates(tab2)) { printf("Le tableau contient des duplications.\n"); } else { printf("Le tableau ne contient pas de duplications.\n"); } return 0; }
Le test sur la longueur du tableau peut être supprimé sans affecter la correctitude de la fonction. Si le tableau est vide, les boucles for ne s'exécuteront pas, et la fonction retournera false naturellement. Cela simplifie le code tout en maintenant sa correctitude.