Structures de données avancées dans la pratique


Au cours des 10 années que j'ai programmées, je peux compter le nombre de structures de données que j'ai utilisées d'une part: des tableaux, des listes chaînées (je regroupe des piles et des files d'attente avec cela) et des dictionnaires. Ce n'est pas vraiment surprenant étant donné que presque toutes les applications que j'ai écrites tombent dans la catégorie forms-over-data / CRUD.

Je n'ai jamais eu besoin d'utiliser un arbre rouge-noir, une liste de saut, une file d'attente à double extrémité, une liste à liens circulaires, une file d'attente prioritaire, des tas, des graphiques ou l'une des dizaines de structures de données exotiques qui ont été étudiées au cours des 50 dernières années. J'ai l'impression de manquer.

C'est une question ouverte, mais où ces structures de données "exotiques" sont-elles utilisées dans la pratique? Quelqu'un a-t-il une expérience réelle de l'utilisation de ces structures de données pour résoudre un problème particulier?

Author: Juliet, 2008-12-23

15 answers

Quelques exemples. Ils sont vagues parce qu'ils travaillaient pour des employeurs:

  • Un tas pour obtenir les N premiers résultats Google recherche de style. (À partir des candidats dans un index, parcourez-les tous linéairement, en les passant au crible dans un min-tas de taille maximale N.) C'était pour un prototype de recherche d'images.

  • Les filtres Bloom réduisent la taille de certaines données sur ce que des millions d'utilisateurs avaient vu à un montant qui correspondrait aux serveurs existants (tout devait être en RAM pour la vitesse); la conception originale aurait eu besoin de nombreux nouveaux serveurs juste pour cette base de données.

  • Une représentation de tableau triangulaire a réduit de moitié la taille d'un tableau symétrique dense pour un moteur de recommandation (RAM à nouveau pour la même raison).

  • Les utilisateurs devaient être regroupés selon certaines associations; union-find a rendu cela facile, rapide et exact au lieu de lent, hacky et approximatif.

  • Une application pour choisir la vente au détail sites en fonction du temps de conduite pour les personnes dans le quartier utilisé Dijkstra chemin le plus court avec des files d'attente prioritaires. D'autres travaux SIG ont profité des index quadtrees et Morton.

Savoir ce qu'il y a dans data-structures-land est utile -- "des semaines dans le laboratoire peuvent vous faire économiser des heures dans la bibliothèque". Le cas bloom-filter ne valait la peine qu "à cause de l" échelle: si le problème était survenu au démarrage au lieu de Yahoo, j " aurais utilisé un vieux simple table de hachage. Les autres exemples que je pense sont raisonnables n'importe où (bien que de nos jours, vous êtes moins susceptible de les coder vous-même).

 28
Author: Darius Bacon, 2009-10-28 07:45:32

Les arbres B sont dans les bases de données.

R-trees sont pour les recherches géographiques (par exemple, si j'ai 10000 formes chacune avec une boîte englobante dispersée autour d'un plan 2D, laquelle de ces formes croise une boîte englobante arbitraire B?)

Les Deques de la forme dans le C++ STL sont des vecteurs cultivables (plus économes en mémoire que les listes chaînées, et à temps constant pour "jeter un coup d'œil" aux éléments arbitraires au milieu). Aussi loin que je me souvienne, je n'ai jamais utilisé le deque à son pleine étendue (insérer/supprimer des deux extrémités) mais il est assez général que vous pouvez l'utiliser comme une pile (insérer/supprimer d'une extrémité) ou une file d'attente (insérer à une extrémité, supprimer de l'autre) et avoir également un accès haute performance pour afficher des éléments arbitraires au milieu.

Je viens de finir de lire Génériques et collections Java the la partie "génériques" me fait mal à la tête, mais la partie collections était utile et ils soulignent certaines des différences entre les listes de saut et les arbres (les deux peuvent implémenter des cartes / ensembles): les listes de saut vous donnent une itération en temps constant intégrée d'un élément à l'autre (les arbres sont O(log n) ) et sont beaucoup plus simples pour implémenter des algorithmes sans verrouillage dans des situations multithread.

Les files d'attente prioritaires

Sont utilisées entre autres pour la planification (voici une page Web qui discute brièvement de l'application); les tas sont généralement utilisés pour les implémenter. J'ai également trouvé que le heapsort (pour moi au moins) est le plus facile des tries O(n log n) à comprendre et de mettre en œuvre.

 11
Author: Jason S, 2008-12-23 16:37:01

Ils sont souvent utilisés dans les coulisses des bibliothèques. Par exemple, une structure de données de dictionnaire ordonnée (c'est-à-dire un tableau associatif qui indique une traversée triée par clés) est aussi susceptible de ne pas être implémentée à l'aide d'un arbre rouge-noir.

De nombreuses structures de données (splay trees viennent à l'esprit) sont intéressantes pour leur comportement optimal dans certaines circonstances (localité temporelle de référence dans le cas des splay trees), elles sont donc principalement pertinentes pour utilisez dans ces cas. Dans la plupart des cas, le véritable avantage d'une connaissance pratique de ces structures de données est de pouvoir les utiliser dans les bonnes circonstances avec une compréhension raisonnable de leur comportement.

Prenez le tri, par exemple:

  • Dans la plupart des cas quicksort ou un quicksort modifié qui tombe à une autre méthode lorsque le les segments individuels deviennent assez petits est généralement le tri le plus rapide algorithme pour la plupart des fins. Cependant, quicksort a tendance à montrer comportement sous optimal sur données presque triées.

  • Le principal avantage d'un tas sort est que cela peut être fait dans situ avec intermédiaire minimal stockage, ce qui le rend assez bon pour une utilisation dans la mémoire contrainte système. Alors qu'il est plus lent en moyenne (bien que toujours n log(n)), il ne souffre pas de la mauvaise performance du pire des cas de quicksort.

  • Un troisième exemple est un fusion trier , ce qui peut être fait séquentiel, c'est la meilleure choix pour trier les ensembles de données beaucoup plus grand que votre mémoire principale. Un autre nom pour cela est le "tri externe", ce qui signifie que vous pouvez trier en utilisant un stockage externe (disque ou bande) pour des résultats intermédiaires.

 7
Author: ConcernedOfTunbridgeWells, 2011-05-20 08:51:05

Cela dépend du niveau d'abstraction auquel vous travaillez.

Je sais que j'ai la même expérience que vous. Au niveau actuel d'abstraction de la plupart des développements logiciels. Dictionnaire et la Liste sont les principales structures de données que nous utilisons.

Je pense que si vous regardez le code de niveau inférieur, vous verrez plus de structures de données "exotiques".

 4
Author: John Sonmez, 2008-12-23 15:53:27

Je pense que vous voyez des structures de données sophistiquées utilisées la plupart des algorithmes de niveau supérieur. L'exemple principal qui me vient à l'esprit est A* qui utilise un graphique et une File d'attente prioritaire implémentée par un tas.

 2
Author: , 2008-12-23 18:33:16

Dans finance, vous devez utiliser un arbre pour calculer la valeur d'un instrument qui dépend de nombreuses autres valeurs dynamiques. Les feuilles de calcul ont un arbre de dépendances similaire, et les compilateurs créent un arbre de syntaxe abstraite avant de traduire en code machine.

 2
Author: RossFabricant, 2009-02-18 03:36:22

Des tas de Fibonacci sont utilisés pour les implémentations efficaces de l'algorithme de Dijkstra.

 2
Author: kolistivra, 2010-04-21 22:44:50

Oui, parfois. Le problème que je vois c'est qu'un certain nombre de gens, bien qu'ils les connaissent, ils ne savent pas comment les appliquer. La plupart des gens reviennent aux tableaux aux listes liées,etc. Ils feront le travail dans la plupart des cas en tant que structure de données plus avancée (parfois, vous devez vraiment "lancer" en place), ils sont juste moins efficaces. Les gens ont tendance à faire ce qui est plus facile pour eux, mais ce n'est pas nécessairement la meilleure façon de faire quelque chose. Je ne peux pas leur reprocher, je suis sûr que je le fais aussi, mais c'est pourquoi vous ne voyez pas beaucoup de concepts "avancés" dans la programmation.

 1
Author: kemiller2002, 2008-12-23 15:54:17

Je viens de trouver une utilisation pour les graphiques en posant une question sur stackoverflow:)

 1
Author: Dan R., 2017-05-23 12:24:43

J'ai utilisé des listes chaînées circulaires pour implémenter des files d'attente (en C) que je vais parcourir pour toujours, c'est-à-dire une file d'attente de connexion réseau.

Mais je trouve que lorsque j'utilise des langages de niveau supérieur, je ne me dérange pas d'implémenter des files d'attente de cette manière, car je peux développer et réduire dynamiquement une liste sans trop m'en soucier. Bien sûr, il y a un prix de performance pour cela, parce que j'ai moins de contrôle sur le moment où l'allocation de mémoire se produit, mais c'est l'un des prix que nous payons pour pouvoir avoir des listes très flexibles.

 0
Author: Daniel Papasian, 2008-12-23 16:04:12

Vous aurez tendance à voir des structures de données plus compliquées lorsque cela est dicté par les besoins du code. Habituellement, je vais voir cela lorsque vous avez affaire à du code plus complexe à des niveaux inférieurs, c'est-à-dire dans le système d'exploitation principal, en écrivant des parties fondamentales d'une bibliothèque de classes (implémentation de string, array, etc.), en écrivant du code extrêmement performant ou multithread, etc. L'autre endroit, je pense qu'ils jouent un rôle important dans la mise en œuvre des algorithmes spécifiques, la recherche, l'échantillonnage, l'analyse statistique, les algorithmes d'optimisation, etc. sont souvent écrits avec des structures de données particulières à l'esprit.

 0
Author: Peter Oehlert, 2008-12-23 16:16:17

J'utilise souvent des ensembles, des collections triées (gardez toujours leurs éléments dans l'ordre trié et supportez l'insertion rapide d'éléments) et des listes paresseuses.

 0
Author: Jules, 2008-12-23 16:38:22

Les arbres équilibrés (rouge-noir, etc.) sont généralement utilisés dans l'implémentation d'un type de données abstrait.

Il n'y a qu'un nombre relativement faible de types de données abstraites, tels que

  • liste
  • carte
  • carte ordonnée
  • carte multiple
  • plusieurs cartes ordonnées
  • file d'attente prioritaire (qui ressemble beaucoup à une carte multi ordonnée)

De même, un ensemble ressemble beaucoup à une carte, mais vous n'avez pas besoin des valeurs, seulement des clés.

J'ai trouvé la plupart des ceux-ci sont utiles de temps en temps; une file d'attente prioritaire est une structure de données très utile et a des applications dans toutes sortes d'algorithmes (par exemple, la planification, la recherche de chemin, etc.).

Vous avez dit "Dictionnaire", vous vouliez probablement dire une carte ou une carte ordonnée.

Certaines cartes ne sont pas ordonnées (généralement implémentées sous forme de hachage) - c'est un sous-ensemble utile d'une carte ordonnée.

 0
Author: MarkR, 2009-10-28 07:51:57

J'ai utilisé une liste circulaire pour la mise en cache.

Un modèle de classe C++ fournit une interface pour obtenir des objets (Cache<Obj, Len>). Plusieurs instatinations de celui-ci renvoient différents types d '"écrans" comme dans différentes vues d'une interface graphique. Dans les coulisses, si l'écran demandé n'est pas disponible, il est créé (opération coûteuse) et poussé à la tête du tampon d'anneau, poussant le plus ancien (déchargeant ses textures, etc.).

Ainsi un compromis est atteint entre toujours lire un tas de fichiers image à partir du disque dur, et simplement charger toutes les images dans la RAM et les garder pour toujours. Le compromis est contrôlé par la longueur des différents tampons.

 0
Author: Vorac, 2018-05-06 10:13:47