Je veux trier un int * arr par ordre décroissant et en même temps permuter les éléments correspondants d'un tableau char ** words si le deuxième élément du int * arr est supérieur au premier. Comment puis-je faire cela en utilisant qsort () et cmpfunc () ? Le tri des entiers était facile mais comment pourrais-je échanger des chaînes dans un autre tableau puisque je n'ai pas d'index dont deux éléments du tableau int sont actuellement triés?
int cmpfunc(const void * a, const void * b) {
int val1 = *(int *)a;
int val2 = *(int *)b;
if(val2 > val1) {
/* swap string positions */
return 1;
} else if(val2 < val1) {
return -1;
} else {
return 0;
}
}
``
qsort(arr,N,sizeof(int),cmpfunc);
3 Réponses :
Il existe plusieurs façons de procéder. Tout d'abord, une réponse directe à votre question:
size_t , contenant les valeurs 0 .. N . qsort sur ce tableau, où au lieu de int val1 = arr[*(int *)a]; int val2 = arr[*(int *)b];
vous faites
int val1 = *(int *)a; int val2 = *(int *)b;
puis comparez comme d'habitude.
arr (une permutation), dans l'ordre qui mettra arr dans l'ordre. Nous pouvons maintenant appliquer cette permutation aux mots arr et mots . Une option consiste simplement à parcourir le tableau d'indices chaque fois que vous souhaitez accéder aux deux tableaux dans l'ordre trié. Une autre consiste à copier les deux tableaux, puis à recopier les éléments selon la permutation. Deuxièmement: vous pouvez également faire la même chose avec un tableau de struct {int *; char **} (chacun pointant vers un membre de arr et le membre correspondant de words ), triez ce tableau par son membre int en laissant l'original les tableaux en place, et l'utiliser à partir de là.
Troisièmement: vous pouvez cesser d'avoir des tableaux parallèles pour commencer. Si les données sont si étroitement associées, alors pourquoi sont-elles dans deux variables non liées? Si vous mettez ensemble les deux types de données dans une structure pour commencer, vous pouvez trier le tableau de structures et faire tout ce que vous voulez avec ces structures, sans craindre que la corrélation ne se désynchronise.
vous avez raison, je pense que je devrais refactoriser mon code et implémenter la troisième manière que vous venez de mentionner. Une question que j'ai toujours est que la fonction de comparaison pour ces structures serait quelque chose comme ceci: int cmpfun (const void * a, const void * b) {struct obj a = * (struct obj b *) a; // idem pour b et puis-je accéder à leurs champs en utilisant le. opérateur sur chacune des structures? }
Je viens de mettre en œuvre la troisième manière que vous venez de mentionner, mais l'échange de chaînes ne fonctionne pas comme prévu. Pourriez-vous jeter un œil à cette partie du code avec moi s'il vous plaît?
Vous pouvez utiliser qsort_r () (si disponible, c'est une extension GNU. Avec les environnements Microsoft, elle s'appelle qsort_s () , mais a sinon la même sémantique) pour passer un autre argument à la fonction de comparaison, par exemple les pointeurs du tableau de base int * arr et char ** words dans une structure:
int cmpfunc(const void * a, const void * b, void *_args) {
struct cmpargs args = _args;
int *a1 = a;
int *a2 = b;
int idx1 = a - args->arr;
int idx2 = b - args->arr;
Et dans votre fonction de comparaison, vous avez maintenant accès à ceux-ci et pouvez les utiliser pour échanger:
struct cmpargs {
int *arr;
char **words;
} args;
...
args.arr = arr;
args.words = words;
qsort_r(arr,N,sizeof(int),cmpfunc, &args);
Vous pouvez maintenant échanger les éléments dans le tableau correspondant args- > mot dans votre fonction de comparaison s'il renverrait 1.
Je souhaite trier un
int * arrpar ordre décroissant et en même temps permuter les éléments correspondants d'un tableauchar ** wordssi le second L'élément de l'int* arrest supérieur au premier. Comment puis-je faire ceci en utilisantqsort ()et lecmpfunc ()?
Il n'y a pas de moyen propre de faire ce travail tel que présenté, car il nécessite des informations contextuelles que qsort () ne transmet pas à la fonction de comparaison: les adresses de base de arr code> et mots tableaux. En fait, ce dernier n'est même pas transmis à qsort () lui-même en premier lieu.
Dans une implémentation qui prend en charge les threads C11, une alternative viable est de stocker ces pointeurs dans stockage spécifique au thread , et laissez la fonction de comparaison les récupérer à partir de là. Vous pouvez alors calculer les indices des éléments comparés comme les différences de pointeur entre eux et le pointeur de base, et vous pouvez effectuer un échange normal des mots en utilisant son pointeur de base et les indices que vous avez obtenus. < / p>
Mais ce n'est probablement pas ce que vous voulez vraiment! J'en déduis que vous essayez d'obtenir la même permutation des éléments de mots que vous faites des éléments sur arr . Ce que vous décrivez n'est en aucun cas certain de produire cela, car vous ne pouvez pas du tout être sûr que qsort () effectuera un échange à chaque fois que le résultat de la comparaison ira d'une certaine manière.
Si effectivement les deux tableaux doivent être séparés, la bonne façon de faire est de préparer et de trier un tableau auxiliaire quelconque. Il existe plusieurs alternatives dans ce domaine qui vous permettront alors soit de réorganiser un ou les deux tableaux principaux, soit d'y accéder comme si vous l'aviez fait. Par exemple, vous pouvez préparer un int (* perm) [2] , avec chaque élément (un int [2] ) contenant l'élément correspondant de arr < / code> et l'index initial de cet élément. Vous triez ensuite ce tableau de tableaux comme vous le souhaitez et sortez la permutation plutôt directement. Vous pouvez alors soit réorganiser arr et mots pour les faire correspondre, soit y accéder indirectement via la permutation ( mots [perm [k] [1]] code >).
Mais vous pouvez également envisager d'écrire votre propre fonction de tri à usage spécifique au lieu d'utiliser qsort () . Une telle fonction pourrait prendre comme arguments les pointeurs de base vers les deux tableaux - correctement typés, même - et ensuite effectuer directement le co-tri dont vous avez besoin.
Vous devrez créer une autre structure de données "liant" entre les deux tableaux et écrire la fonction de comparaison correspondante.
... ou si les éléments de
arrse trouvent être des indices d'éléments demots, et que vous voulez l'apparence du tri desmotsde la même manière vous faitesarr, alors peut-être que vous n'échangez pas du tout des éléments demots. Dans ce cas, vous pouvez à la place un accès indexé indirect auxmotsviaarr. Par exemple,mots [arr [i]].@JohnBollinger malheureusement, ce n'est pas le cas et comment puis-je faire
arr [i]puisque je n'ai pas deidans lecmpfunc?Pourquoi les avez-vous dans deux tableaux différents? Pourquoi ne pas créer un tableau de structures, où la structure contient à la fois l'entier et la chaîne?
si
arrétait disponible danscmpfunc(par exemple parce que c'est une variable à la portée du fichier), alors vous pouvez dériver les indizes; Mais c'est un hack, bien sûr.@Barmar donc quelque chose comme:
struct obj {int count; char * mot; };puis créez un tableau de N telles structures et passez ce tableau dans le qsort comme base?@SteliosPapamichail Oui. Vous aurez également besoin de la fonction de comparaison correspondante fonctionnant avec ce type.
@EugeneSh. , donc je suppose que quelque chose comme
int cmpfunc (const void * structa, const void * structb) {}et à l'intérieur je convertirais cesvoid *enstruct obj *et accéder à leurs champs à partir de là en utilisant l'opérateur->?