Ces deux semblent très similaires et ont presque une structure identique. Quelle est la différence? Quelle est la complexité temporelle des différentes opérations de chacun?

Réponse

Heap garantit simplement que les éléments des niveaux supérieurs sont plus grands (pour max-heap) ou plus petits (pour min-heap) que les éléments des niveaux inférieurs, alors que BST garantit lordre (de « gauche » à « droite ») . Si vous voulez des éléments triés, choisissez BST. par Dante nest pas un geek

Heap est meilleur à findMin / findMax (O ( 1)), alors que BST est bon dans tous les domaines trouvés (O (logN)). Insert est O (logN) pour les deux structures. Si vous ne vous souciez que de findMin / findMax (par exemple lié à la priorité), optez pour le tas. Si vous voulez tout est trié, utilisez BST.

par xysun

Commentaires

  • Je pense que BST est meilleur dans findMin & findMax stackoverflow .com / a / 27074221/764592
  • Je pense que ce nest quune communication sur une idée fausse. Un arbre binaire peut être facilement modifié pour trouver min et max comme indiqué par Yeo. Il sagit en fait dune restriction du tas: la seule recherche efficace est min ou max. Le véritable avantage du tas est insertion moyenne O (1) comme je lexplique: stackoverflow.com/a/29548834/895245
  • Selon cette vidéo , vous pouvez avoir des valeurs plus élevées à un niveau inférieur, à condition que la plus grande ne descende pas de la plus basse.
  • Le tas est trié de la racine à la feuille et BST est trié de gauche à droite.
  • Et si je veux trouver la médiane en temps constant et supprimer la médiane en temps logarithmique? quelle structure de données dois-je choisir? la mise en œuvre de MinHeap fonctionnera-t-elle? Veuillez suggérer.

Réponse

Résumé

 Type BST (*) Heap Insert average log(n) 1 Insert worst log(n) log(n) or n (***) Find any worst log(n) n Find max worst 1 (**) 1 Create worst n log(n) n Delete worst log(n) log(n) 

Tous les temps moyens de ce tableau sont les mêmes que leurs pires moments sauf pour Insertion.

  • *: partout dans cette réponse, BST == Balanced BST, puisque déséquilibré aspire asymptotiquement
  • **: en utilisant une modification triviale expliquée dans cette réponse
  • ***: log(n) pour le tas de larborescence du pointeur, n pour le tas de tableaux dynamiques

Avantages du tas binaire sur un BST

Lavantage du BST par rapport au tas binaire

  • la recherche déléments arbitraires est O(log(n)). Cette est la fonctionnalité qui tue des BST.

    Pour le tas, cest O(n) en général, sauf pour le plus grand élément qui est O(1).

« Faux » avantage du tas sur BST

  • le tas est O(1) pour trouver max, BST O(log(n)).

    Ceci est une idée fausse courante, car il est trivial de modifier un BST pour garder une trace du plus grand élément, et de le mettre à jour chaque fois que cet élément pourrait être modifié: lors de linsertion dun plus grand swap, lors de la suppression, trouvez le deuxième plus grand. https://stackoverflow.com/questions/7878622/can-we-use-binary-search-tree-to-simulate-heap-operation (mentionné par Yeo ).

    En fait, il sagit dune limitation de tas par rapport aux BST: la seule recherche efficace est celle du plus grand élément.

Linsertion moyenne du tas binaire est O(1)

Sources:

Argument intuitif:

  • les niveaux inférieurs de larborescence ont exponentiellement plus déléments que les niveaux supérieurs, donc les nouveaux éléments sont presque certains daller en bas
  • insertion de tas commence par le bas , BST doit commencer par le haut

Dans un tas binaire, augmenter la valeur à un index donné est aussi O(1) pour la même raison. Mais si vous voulez faire cela, il est probable que vous souhaitiez garder un index supplémentaire à jour sur les opérations de tas https://stackoverflow.com/questions/17009056/how-to-implement-ologn-decrease-key-operation-for-min-heap-based-priority-queu par exemple pour Dijkstra. Possible sans frais de temps supplémentaire.

Benchmark dinsertion de bibliothèque standard C ++ GCC sur du matériel réel

Jai évalué le C ++ std::set ( Arbre rouge-noir BST ) et std::priority_queue ( tas de tableau dynamique ) pour voir si javais raison sur les temps dinsertion, et voici ce que jai obtenu:

entrez la description de limage ici

  • code de référence
  • script de tracé
  • données de tracé
  • testé sur Ubuntu 19.04, GCC 8.3.0 dans un ordinateur portable Lenovo ThinkPad P51 avec CPU: CPU Intel Core i7-7820HQ (4 cœurs / 8 threads , 2,90 GHz de base, 8 Mo de mémoire cache), RAM: 2x Samsung M471A2K43BB1-CRC (2x 16GiB, 2400 Mbps), SSD: Samsung MZVLB512HAJQ-000L7 (512 Go, 3.000 Mo / s)

Donc clairement:

Benchmark dinsertion de bibliothèque standard C ++ GCC sur gem5

gem5 est un simulateur de système complet, et fournit donc une horloge infiniment précise avec avec m5 dumpstats. Jai donc essayé de lutiliser pour estimer les horaires des insertions individuelles.

entrez la description de limage ici

Interprétation:

  • le tas est toujours constant, mais maintenant nous voyons plus en détail quil y a quelques lignes, et chaque ligne supérieure est plus clairsemée .

    Cela doit correspondre aux latences d’accès à la mémoire qui sont faites pour des insertions de plus en plus élevées.

  • TODO Je ne peux pas vraiment interpréter le BST complètement comme il ne semble pas si logarithmique et un peu plus constant.

    Avec ce plus de détails, cependant, nous pouvons voir que nous pouvons également voir quelques lignes distinctes, mais je ne suis pas sûr de ce quelles représentent: je mattendrais à ce que la ligne du bas être plus mince, puisque nous insérons du haut en bas?

Benchmarké avec cette configuration Buildroot sur un aarch64 HPI CPU .

BST ne peut pas être efficacement implémenté sur un tableau

Tas les opérations nont besoin que de remonter ou de descendre une seule branche darbre, donc O(log(n)) swaps dans le pire des cas, O(1) en moyenne.

Garder un BST équilibré nécessite des rotations darbres, ce qui peut changer lélément supérieur pour un autre, et nécessiterait de déplacer tout le tableau autour (O(n)).

Les tas peuvent être efficacement implémentés sur un tableau

Les index parents et enfants peuvent être calculés à partir de lindex actuel comme indiqué ici .

Il ny a pas dopérations déquilibrage comme BST.

Supprimer min est lopération la plus inquiétante car elle doit être descendante. Mais cela peut toujours être fait en « percolant » une seule branche du tas comme expliqué ici . Cela conduit au pire des cas O (log (n)), car le tas est toujours bien équilibré.

Si vous insérez un seul nœud pour chacun que vous supprimez, alors vous perdez lavantage de lasymptotique O (1) insert moyen que les tas fournissent car la suppression dominerait, et vous pourriez aussi bien utiliser un BST. Dijkstra met cependant à jour les nœuds plusieurs fois pour chaque suppression, donc tout va bien.

Les tas de tableaux dynamiques et les tas darbres de pointeurs

Les tas peuvent être mis en œuvre efficacement au-dessus des tas de pointeurs: https://stackoverflow.com/questions/19720438/is-it-possible-to-make-efficient-pointer-based-binary-heap-implementations

Limplémentation du tableau dynamique est plus efficace en termes despace. Supposons que chaque élément du tas contienne juste un pointeur vers un struct:

  • limplémentation de larborescence doit stocker trois pointeurs pour chaque élément: parent, enfant gauche et enfant droit. Ainsi, lutilisation de la mémoire est toujours 4n (3 pointeurs darbre + 1 pointeur struct).

    Les BST darbre seraient également besoin dinformations supplémentaires sur léquilibrage, par ex black-red-ness.

  • limplémentation du tableau dynamique peut être de taille 2n juste après un doublement. Donc, en moyenne, ce sera 1.5n.

Dun autre côté, le tas darbre a une meilleure insertion dans le pire des cas, parce que copier le tableau dynamique de sauvegarde pour doubler sa taille prend O(n) le pire des cas, alors que le tas de larborescence ne fait que de nouvelles petites allocations pour chaque nœud.

Pourtant, le support le doublement du tableau est O(1) amorti, donc il revient à une considération de latence maximale. Mentionné ici .

Philosophie

  • Les BST conservent une propriété globale entre un parent et tous les descendants (plus petit à gauche, plus grand à droite).

    Le nœud supérieur dun BST est lélément du milieu , ce qui nécessite une connaissance globale pour être maintenue (savoir combien il y a déléments plus petits et plus grands).

    Cette propriété globale est plus coûteuse à maintenir (log n insert), mais donne des recherches plus puissantes (log n search) .

  • Les tas conservent une propriété locale entre les parents et les enfants directs (parents> enfants).

    La note supérieure dun tas est le gros élément, qui ne nécessite que des connaissances locales à maintenir (connaître ses parents).

Comparaison de BST vs Heap vs Hashmap:

  • BST: peut être soit un raisonnable:

    • ensemble non ordonné (une structure qui détermine si un élément a déjà été inséré ou non). Mais hashmap a tendance à être meilleur en raison de linsert amorti O (1).
    • machine de tri. Mais le tas est généralement meilleur à cela, cest pourquoi heapsort est beaucoup plus connu que tri darbre
  • tas: est juste une machine de tri. Il ne peut pas sagir dun ensemble non ordonné efficace, car vous ne pouvez rechercher que lélément le plus petit / le plus grand rapidement.

  • carte de hachage: ne peut être quun ensemble non ordonné, pas une machine de tri efficace, parce que le hachage confond nimporte quel ordre.

Liste à double lien

Une liste doublement liée peut être considérée comme un sous-ensemble du tas où le premier élément a la plus grande priorité, alors comparons-les ici aussi:

  • insertion:
    • position:
      • liste doublement liée: lélément inséré doit être le premier ou le dernier, car nous navons que des pointeurs vers ces éléments.
      • tas binaire: lélément inséré peut se retrouver dans nimporte quelle position. Moins restrictif que la liste liée.
    • heure:
      • liste doublement liée: O(1) pire des cas puisque nous avons des pointeurs vers les éléments, et que la mise à jour est vraiment simple
      • tas binaire: O(1) moyen, donc pire que la liste chaînée. Compromis pour ayant une position dinsertion plus générale.
  • recherche: O(n) pour les deux

Un cas dutilisation pour cela est lorsque la clé du tas est lhorodatage actuel: dans ce cas, les nouvelles entrées iront toujours au début de la liste. Ainsi, nous pouvons même oublier complètement lhorodatage exact, et simplement garder la position dans la liste comme priorité.

Cela peut être utilisé pour implémenter un cache LRU . Tout comme pour les applications de tas comme Dijkstra , vous voudrez conserver un hashmap supplémentaire de la clé au nœud correspondant de la liste, pour trouver le nœud à mettre à jour rapidement .

Comparaison de différents BST équilibrés

Bien que linsertion asymptotique et trouver les temps pour toutes les structures de données qui sont communément classées comme «BST équilibrées» que jai vues jusquà présent sont les mêmes, différents BBST ont des compromis différents. Je nai pas encore étudié complètement cela, mais il serait bon de résumer ces compromis ici:

  • Arbre rouge-noir . Semble être le BBST le plus couramment utilisé à partir de 2019, par ex. cest celui utilisé par limplémentation C ++ de GCC 8.3.0
  • arbre AVL . Semble être un peu plus équilibré que BST, il pourrait donc être préférable pour la latence de recherche, au prix de découvertes légèrement plus chères.Le wiki résume: «Les arborescences AVL sont souvent comparées aux arborescences rouge-noir car les deux prennent en charge le même ensemble d’opérations et prennent [le même] temps pour les opérations de base. Pour les applications nécessitant une recherche intensive, les arborescences AVL sont plus rapides que les arbres rouge-noir car ils sont plus strictement équilibrés. Semblables aux arbres rouge-noir, les arbres AVL sont équilibrés en hauteur. Les deux ne sont, en général, ni pondérés ni équilibrés en mu pour les mu < 1 / 2; autrement dit, les nœuds frères peuvent avoir des nombres de descendants extrêmement différents. « 
  • WAVL . Le article original mentionne les avantages de cette version en termes de limites sur les opérations de rééquilibrage et de rotation.

Voir aussi

Question similaire sur CS: What ' est la différence entre un arbre de recherche binaire et un tas binaire?

Commentaires

  • Excellente réponse . Les applications courantes du tas sont la médiane, k min, les k éléments supérieurs. Pour ces opérations les plus courantes, supprimez min puis insert (généralement nous avons un petit tas avec peu dopérations dinsertion pure). Il semble donc quen pratique, pour ces algorithmes, il ne surpasse pas la BST.
  • Réponse exceptionnelle !!! En utilisant deque comme structure de tas sous-jacente, vous pouvez réduire considérablement les temps de redimensionnement, même sil sagit toujours du pire des cas, car il doit réallouer un tableau (plus petit) de pointeurs vers des morceaux.

Réponse

Les deux arbres de recherche binaires et les tas binaires sont des structures de données arborescentes.

Les tas exigent que les nœuds aient une priorité sur leurs enfants. Dans un tas max, les enfants de chaque nœud doivent être inférieurs à lui-même. Cest le contraire pour un tas min:

Binary Max Heap

Les arbres de recherche binaire (BST) suivent un ordre spécifique (pré-ordre, dans-ordre, post-ordre) parmi les nœuds frères. Larbre doit être trié, contrairement aux tas:

Arbre de recherche binaire

BST a une moyenne de $ O (\ log n) $ pour linsertion, la suppression et la recherche.
Les tas binaires ont une valeur moyenne de $ O (1) $ pour findMin / findMax et $ O (\ log n) $ pour insertion et suppression.

Commentaires

  • @FrankW Extraction is $ O (\ log n) $, no?

Answer

Avec la structure de données, il faut distinguer les niveaux de préoccupation.

  1. Les structures de données abstraites (objets stockés, leurs opérations) dans ce q les questions sont différentes. Lun implémente une file dattente prioritaire, lautre un ensemble. Une file dattente prioritaire nest pas intéressée à trouver un élément arbitraire, seulement celui avec la plus grande priorité.

  2. La mise en œuvre concrète des structures. Ici, à première vue, les deux sont des arbres (binaires), avec des propriétés structurelles différentes. Lordre relatif des clés et les structures globales possibles diffèrent. (Un peu imprécis, dans un BST, les clés sont ordonnées de gauche à droite, dans un tas elles sont ordonnées de haut en bas.) Comme IPlant le remarque correctement, un tas doit également être « complet » .

  3. Il y a une dernière différence dans la implémentation de bas niveau . Un arbre de recherche binaire (déséquilibré) a une implémentation standard utilisant des pointeurs. Un tas binaire au contraire a une implémentation efficace en utilisant un tableau (précisément à cause de la structure restreinte).

Réponse

En plus des réponses précédentes, le tas doit avoir la propriété de structure de tas ; larborescence doit être pleine, et la couche la plus basse, qui ne peut pas toujours être pleine, doit être remplie de lextrême gauche à lextrême droite sans espaces.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *