Quelqu'un peut-il me dire le point des modèles de fonctions de tas stl comme std::make_heap
? Pourquoi quelqu'un voudrait-il les utiliser? Y a-t-il une utilisation pratique?
Si vous souhaitez faire une file d'attente prioritaire à partir d'une liste, eh bien, vous pouvez utiliser make_heap:
En interne, un tas est un arbre dans lequel chaque nœud est lié à des valeurs non supérieures à sa propre valeur. Dans des tas générés par make_heap, la position spécifique d'un élément de l'arbre plutôt que d'être déterminée par des liens consommateurs de la mémoire est déterminée par sa position absolue dans la séquence, avec * d'abord toujours la valeur la plus élevée dans le tas.
Les tas permettent d'ajouter ou de supprimer des éléments de celui-ci dans le temps logarithmique à l'aide de fonctions push_heap et pop_heap, qui préservent ses propriétés du tas.
Votre question directe serait bien réparée par une classe dans des algorithmes et des structures de données. Les tas sont utilisés partout dans les algorithmes en informatique. Pour citer la fonction make_heap liée ci-dessous ", un tas est un arborescence où chaque nœud relie les valeurs non supérieures à sa propre valeur." Bien qu'il existe de nombreuses applications pour un tas, celui que j'utilise le plus souvent est dans les problèmes de recherche lorsque vous souhaitez garder une trace d'une liste triée de N valeurs efficacement.
J'avais une confusion similaire à la vôtre lorsque j'ai rencontré les fonctions de tas stl. Ma question était un peu différente. Je me demandais "Pourquoi le tas de stl n'est-il pas dans la même classe de structures de données que STD :: Vector?" Je pensais que cela fonctionnerait comme ceci:
std::heap< int > my_heap;
my_heap.heap_insert( 7 );
my_heap.heap_insert( 3 );
L'idée derrière le tas de STL fonctionne bien que c'est qu'ils vous permettent de créer une structure de données de tas de plusieurs conteneurs STL sous-jacents différents, notamment STD :: Vector. Cela peut être vraiment utile si vous souhaitez transmettre le conteneur pour une utilisation ailleurs dans vos programmes. C'est aussi un peu gentil, car vous pouvez choisir le conteneur sous-jacent de votre tas si vous choisissez d'utiliser une autre chose que STD :: Vecteur. Tout ce que vous avez vraiment besoin est ce qui suit:
template <class RandomAccessIterator>
void make_heap ( RandomAccessIterator first, RandomAccessIterator last );
Cela signifie que vous pouvez faire de nombreux conteneurs différents dans un tas, un comparateur est également facultatif dans la signature de la méthode, vous pouvez en savoir plus sur les différentes choses que vous pouvez essayer dans les pages STL pour la fonction make_heap.
Liens:
std::make_heap
Ne devrait presque jamais être utilisé dans la pratique. Bien qu'il soit vrai que les tas sont utiles pour les files d'attente prioritaires, cela n'explique pas pourquoi vous voudriez maintenir manuellement la structure. std::priority_queue
A une interface beaucoup plus utile si tout ce dont vous avez besoin est une file d'attente prioritaire.
Si vous utilisez make_heap
Et ses frères et sœurs directement, vous devez vous assurer de les utiliser à chaque fois que vous modifiez le conteneur sous-jacent. Je les ai vus utilisés deux ou trois fois et chaque fois Ils ont été utilisés de manière incorrecte.
Je n'ai utilisé que les opérations de démarrage directement une fois moi-même, car je devais utiliser un vecteur comme une file d'attente prioritaire pendant un moment, puis triez-la. Vous aurez probablement jamais besoin de std::make_heap
.
Si vous avez besoin d'une file d'attente prioritaire avec la possibilité de modifier des éléments, vous pouvez utiliser std::set
. Vous pouvez obtenir le plus petit ou le plus grand élément avec *s.begin()
ou *s.rbegin()
_ respectivement et mettez à jour un élément en supprimant l'ancienne valeur et en insérant le nouveau.
Il existe essentiellement deux façons de construire un tas [binaire]: Créez un tas vide et insérez chaque élément dans celui-ci à la fois, ou prenez une plage de valeurs et de les tases.
Chaque opération de poussée sur un tas prend O(logn) TIME, donc si vous appuyez sur N articles sur un tas, il faudra O(NlogN) Time. Cependant, pour construire un tas binaire à partir d'une gamme de valeurs ne prend que O(N) temps.
Ainsi, il est plus logique d'insérer chaque élément dans un tableau (ou d'un autre conteneur prenant en charge les itérateurs d'accès aléatoires), puis appelle make_heap () sur la matrice que pour maintenir la structure du tas pendant l'insertion.
En plus de ce qui précède, l'algorithme de tri de la STL est Introsort , qui est un mélange de QuickSort et de TeasPort (il échoue à partir de Quicksort à Heapsort si le premier se déroule mal). make_heap crée une structure de tas, nécessaire pour faire fonctionner le tas, ce qui est nécessaire pour Introsort.