8
votes

Comment calculer la différence entre deux ensembles en C?

J'ai deux tableaux, disez A et B avec | A | = 8 et | B | = 4. Je veux calculer la différence définie A-B. Comment procéder? Veuillez noter qu'il n'y a pas d'éléments répétés dans l'un ou l'autre des ensembles.

Edit: Merci beaucoup tout le monde pour une myriade de solutions élégantes. Depuis que je suis en phase de prototypage de mon projet, j'ai mis en œuvre la solution la plus simple racontée par Brian et Owen. Mais j'apprécie l'utilisation intelligente des structures de données comme suggéré ici par le reste d'entre vous, même si je ne suis pas un informaticien, mais un ingénieur et que je n'ai jamais étudié les structures de données comme un cours. On dirait qu'il est à propos de temps que je devrais vraiment commencer à lire des CLRS que je termine depuis un certain temps :) Merci encore!


8 commentaires

Il n'y a pas de telle chose que c-stl. Voulez-vous dire C ++?


Je connais. Je voulais juste clarifier que je ne voulais pas de solutions à base de STL.


Depuis que STL est une chose C ++ - seule, il suffit de dire que vous utilisez c et de le laisser à cela; Si la réponse de quelqu'un a recommandé à STL, ils seraient révélés (et à juste titre).


Je veux dire, pas une légère contre vous ou quoi que ce soit, mais c'est toujours un peu drôle de la façon dont vous êtes allé à une si grande douleur pour prévenir la confusion et ensuite-oups! - Est allé dans l'autre sens et que quelqu'un a de toute façon confuse de toute façon (la loi de Murphy frappe à nouveau, J'imagine).


Nan. Je suis un étudiant diplômé et ce problème est arrivé dans mes travaux de recherche. J'ai déjà utilisé des ensembles Python à cette fin, mais maintenant je dois mettre en œuvre dans C.


@Cirno et Blueraja, c'est bon et je comprends. En fait, j'aime vraiment quand les utilisateurs expérimentés comme vous modifiez et corrigez mes erreurs. C'est tout ce qu'est Stackoverflow!


Quels sont ces ensembles de (entiers, chaînes, ...)? Sont a et b triés? Quelle est leur taille? (E.g N ^ 2 algorithmes fera-t-il? Nlogn?) Combien de fois avez-vous besoin de prendre cette différence de jeu?


A et B sont des matrices de pointeurs (64 bits) qui pointent vers des objets alloués dynamiquement en mémoire, et ils ne sont définitivement pas triés. (Puis-je trier les pointeurs?) Pour être exact, A est de taille 32 et B est de taille 8 et tout le fonctionnement de la différenciation définie doit être fait des dizaines de milliers de temps.


6 Réponses :


7
votes

Itérate sur chaque élément de A, si chacun de ces éléments ne sont pas en B, puis ajoutez-les à un nouvel ensemble C.


4 commentaires

Et comment puis-je mettre en œuvre "si chacun de ces éléments ne sont pas en b"? C'est exactement le point que je ne pouvais pas sembler avoir!


@Aamir - Vous pouvez soit itérer sur B si l'ensemble est non ordonné (vous donnant un O (n * m) exécution) ou vous pouvez faire une recherche binaire sur B si l'ensemble est commandé (en vous donnant un O (n log M) runtime)


Cela le fera (désolé pour le formatage): int FoundInb = 0; pour (int j = 0; j


Mieux si vous pouvez charger B dans une table de hachage de sorte que le test "Est-ce dans B" peut être effectué dans O (1).



5
votes

Cela dépend de la manière dont vous souhaitez représenter vos ensembles, mais s'ils ne sont que des bits emballés, vous pouvez utiliser des opérateurs bitwises, par exemple. d = a & ~ b; vous donnerait la différence de réglage A-B si les ensembles correspondent à un type d'entier. Pour les ensembles plus importants, vous pouvez utiliser des tableaux de types entier et itérer, par exemple xxx


0 commentaires

13
votes

Trier les tableaux A et B de
le résultat sera en C
laissez A - le premier elem d'un
Soit B - le premier elem de Puis:
1) Pendant que A 2) Pendant que A> B: B = Next elem de 3) Si A = B: A = Elem Suivant de A et B = Elem Suivant de B
4) Si B va à la fin: insérez le reste de A dans C et arrêtez de
5) Si un mot se termine: arrêtez


0 commentaires

1
votes

Pour les ensembles plus importants, je vous suggère de trier les chiffres et de les utiliser en émulant le code sur http://www.cplusplus.com/reference/algorithm/set_difefence/ qui serait O (n * logn), mais puisque les tailles de jeu sont si petites, la solution donnée par Brian semble bien même si elle est bien théoriquement plus lent à O (n ^ 2).


2 commentaires

La différence définie que vous avez liée doit être O (n), pas O (n log n) - tant que l'opération de la copie ne fait pas que des grappes sur des insertions dans un nouvel arbre. Une copie de sous-arrondi bien écrite pour un arbre binaire est O (n).


Ah j'ai oublié de préciser que je voulais dire O (nlogn) supposant que Quicksort est utilisé dans la phase de tri).



5
votes

Les éléments suivants supposent que les ensembles sont stockés sous forme de conteneur trié (comme STD :: Set Set).

Il existe un algorithme commun pour la fusion de deux listes ordonnées pour produire un tiers. L'idée est que lorsque vous regardez les têtes des deux listes, vous pouvez déterminer quel est l'extrait inférieur, et l'ajoutez à la queue de la sortie, puis répétez.

Il y a des variantes qui détectent le cas où les deux têtes sont égales et le traitent spécialement. Définir des intersections et des syndicats sont des exemples de cela.

Avec une différence asymétrique définie, le point clé est que pour A-B, lorsque vous extrayez la tête de B, vous le jetez. Lorsque vous extrayez la tête de A, vous l'ajoutez à l'entrée sauf si la tête de B est égale, auquel cas vous extrayez-le aussi et jetez les deux.

Bien que cette approche soit conçue pour les structures de données d'accès séquentielles (et le stockage de bande, etc.), il est parfois très utile de faire la même chose pour une structure de données d'accès aléatoire tant qu'il est raisonnablement efficace d'y accéder séquentiellement. Et vous n'avez pas nécessairement d'extraire des choses pour réel - vous pouvez faire la copie et la pas.

Le point clé est que vous traversez les entrées séquentiellement, en examinant toujours la valeur restante la plus basse, de sorte que (si les entrées n'ont pas de duplicate), vous ferez les éléments correspondants. Vous savez donc toujours si votre prochaine valeur la plus basse à gérer est un élément d'un sans correspondance en B et l'élément de B sans correspondance dans A, ou un élément égal à la fois A et B.

Plus généralement, l'algorithme de la différence définie dépend de la représentation de l'ensemble. Par exemple, si l'ensemble est représenté sous la forme d'un vecteur bit, ce qui précède serait surcommode et lent - vous venez de boucler à travers les vecteurs faisant des opérations sur le bitwise. Si l'ensemble est représenté sous forme de hashtable (comme dans le TR1 Unommked_sed_set), ce qui précède est incorrect car il nécessite des entrées commandées.

Si vous avez votre propre code d'arbre binaire que vous utilisez pour les ensembles, une bonne option consiste à convertir les deux arbres en listes liées, à utiliser sur les listes, puis à convertir la liste résultante à un arbre parfaitement équilibré. La différence relative à la liste liée est très simple et les deux conversions sont réutilisables pour d'autres opérations similaires.

Modifier

sur la complexité - à l'aide de ces algorithmes commandés en forme de fusion est O (n) à condition que vous puissiez effectuer les traverser dans l'ordre dans O (n). La conversion d'une liste et de son dos est également O (n) car chacune des trois étapes est O (n) - arborescente, différence et liste-liste.

Tree-to-List fait essentiellement une travertielle de profondeur, déconstruisant l'arbre comme ça va. Il y a une astuce pour faire de cette itératif, stocker la "pile" dans les nœuds à manipulation partielle - changer un pointeur à gauche dans un point de parent juste avant de passer à l'enfant gauche. C'est une bonne idée si l'arbre peut être grand et déséquilibré.

Conversion d'une liste en un arbre implique essentiellement une première traversée d'un arborescence imaginaire (basée sur la taille, connue du début) le construisant pour le réel comme vous allez. Si un arbre a 5 nœuds, par exemple, vous pouvez dire que la racine sera nœud 3. Vous recursez pour créer un sous-arbre à deux nœuds à gauche, puis saisissez l'élément suivant de la liste pour cette racine, puis recueille pour construire une deux -Node sous-arbre à droite.

La conversion de liste à arborescence ne doit pas nécessairement être mise en œuvre itérative - la récursive est une amende, car le résultat est toujours parfaitement équilibré. Si vous ne pouvez pas gérer la profondeur de la restauration du journal N, vous ne pouvez certainement pas gérer l'arbre complet de toute façon.


0 commentaires

2
votes

Implémentez un objet de jeu dans C. Vous pouvez le faire à l'aide d'une table de hachage pour le stockage sous-jacent. Ceci est évidemment un exercice non trivial, mais quelques Ouvrez Source Solutions existe. Ensuite, vous devez simplement ajouter tous les éléments d'A, puis itérer sur B et supprimer tout ce qui sont des éléments de votre ensemble.

Le point clé consiste à utiliser la bonne structure de données pour le travail.


0 commentaires