Algorithme de tri par tas (avec Code in Python et C++)

โšก Rรฉsumรฉ intelligent

L'algorithme de tri par tas trie un tableau en construisant un tas binaire et en l'extrayant de maniรจre rรฉpรฉtรฉe.tracCette ressource explique les fonctions heapify, max et min heaps, le pseudo-code et l'ensemble du processus. Python et C++ implรฉmentations avec analyse de la complexitรฉ temporelle.

  • ๐ŸŒณ Idรฉe de base : Le tri par tas construit un tas binaire complet, puis l'extrait de maniรจre rรฉpรฉtรฉe.traccs la racine pour produire un ordre triรฉ.
  • ๐Ÿ”บ Tasifier : L'opรฉration heapify restaure la propriรฉtรฉ du tas par รฉchange.ping un parent avec son enfant plus รขgรฉ.
  • ๐Ÿ‡ง๐Ÿ‡ท Stockage en baie : Un tas est stockรฉ dans un tableau oรน un nล“ud ร  l'indice i a des enfants aux indices 2i+1 et 2i+2.
  • ๏ธ Complexitรฉ: Le tri par tas s'exรฉcute en temps O(n log n) dans tous les cas et utilise O(1) d'espace supplรฉmentaire.
  • ๐Ÿ’ป Code ร€ condition de: Working : un espace de travail commun Python et C++ Les programmes illustrent la fonction heapify, la construction de tas et le tri complet.

Quโ€™est-ce que lโ€™algorithme de tri par tas ?

Le tri par tas est un algorithme de tri populaire et rapide. Il repose sur la structure de donnรฉes d'un arbre binaire complet. On recherche l'รฉlรฉment maximal et on le place au sommet du tas, c'est-ร -dire au niveau du nล“ud parent de l'arbre binaire.

Disons qu'un tableau est donnรฉ, donnรฉes = [10,5, 7, 9, 4, 11, 45, 17, 60].

Dans le tableau, si le i-iรจme (i=0,1,2,3 โ€ฆ) index est un nล“ud parent alors, (2i+1) et (2i+2) seront les enfants gauche et droit. La crรฉation d'un arbre binaire complet avec ce tableau ressemblera ร  ceci :

Algorithme de tri de tas

Nous effectuerons le processus heapify du dรฉbut ร  la fin du tableau. Initialement, si nous convertissons le tableau en arbre, il ressemblera ร  celui ci-dessus. Nous pouvons voir qu'il ne conserve aucune propriรฉtรฉ de tas (min-heap ou max tas). Nous obtiendrons le tableau triรฉ en effectuant le processus heapify pour tous les nล“uds.

Application du tri par tas

Voici une utilisation de l'algorithme de tri par tas :

  • La construction de ยซ files dโ€™attente prioritaires ยป nรฉcessite un tri par tas. Parce que le tri par tas maintient l'รฉlรฉment triรฉ aprรจs chaque insertion.
  • La structure de donnรฉes du tas est efficace pour trouver le kth le plus grand รฉlรฉment d'un tableau donnรฉ.
  • Le noyau Linux utilise le tri par tas par dรฉfaut algorithme de tri car il a une complexitรฉ spatiale O (1).

Crรฉer un tri par tas avec un exemple

Ici, nous allons construire un tas maximum ร  partir de l'arbre binaire complet suivant.

Crรฉer un tri par tas avec un exemple

Les nล“uds feuilles sont 17, 60, 4, 11 et 45. Ils n'ont aucun nล“ud enfant. C'est pourquoi ce sont des nล“uds feuilles. Nous allons donc dรฉmarrer la mรฉthode heapify ร  partir de leur nล“ud parent. Voici les รฉtapes :

ร‰tape 1) Sรฉlectionnez le sous-arbre le plus ร  gauche. Si les nล“uds enfants sont plus grands, รฉchangez le nล“ud parent avec le nล“ud enfant.

Ici, le nล“ud parent est 9. Et les nล“uds enfants sont 17 et 60. Comme 60 est le plus grand, 60 et 9 seront รฉchangรฉs pour maintenir le tas max.

Crรฉer un tri par tas avec un exemple

ร‰tape 2) Dรฉsormais, le sous-arbre le plus ร  gauche est regroupรฉ. Le nล“ud parent suivant est 7. Ce parent a deux nล“uds enfants et le plus grand est 45. Ainsi, 45 et 7 seront รฉchangรฉs.

Crรฉer un tri par tas avec un exemple

Crรฉer un tri par tas avec un exemple

ร‰tape 3) Les nล“uds 60 et 4 ont le nล“ud parent 5. Comme ยซ 5 ยป est plus petit que le nล“ud enfant 60, il sera interverti.

Crรฉer un tri par tas avec un exemple

Crรฉer un tri par tas avec un exemple

ร‰tape 4) Dรฉsormais, le nล“ud 5 a le nล“ud enfant 17,9. Cela ne maintient pas la propriรฉtรฉ max tas. Ainsi, 5 sera remplacรฉ par 17.

Crรฉer un tri par tas avec un exemple

ร‰tape 5) Le nล“ud 10 sera remplacรฉ par le nล“ud 60, puis par le nล“ud 17. Le processus ressemblera ร  ce qui suit.

Crรฉer un tri par tas avec un exemple

Crรฉer un tri par tas avec un exemple

ร‰tape 6) Jusqu'ร  l'รฉtape 5, nous avons crรฉรฉ le tas maximum. Chaque nล“ud parent est plus grand que ses nล“uds enfants. Le nล“ud racine a la valeur maximale (60).

ร€ noter: Pour crรฉer le tableau triรฉ, nous devons remplacer le nล“ud de valeur maximale par son successeur.

Ce processus est appelรฉ "extract maxยป. Comme 60 est le nล“ud max, nous allons fixer sa position au 0รจme index et crรฉer le tas sans nล“ud 60.

Crรฉer un tri par tas avec un exemple

Crรฉer un tri par tas avec un exemple

ร‰tape 7) Une fois 60 รฉliminรฉ, la valeur maximale suivante est 45. Nous allons suivre le processus ยซ Ex ยป.tract Maxโ€ ร  nouveau ร  partir du nล“ud 45.

Cette fois, nous obtiendrons 45 et remplacerons le nล“ud racine par son successeur 17.

Nous devons performer ยปExtract Maxยป jusqu'ร  ce que tous les รฉlรฉments soient triรฉs.

Aprรจs avoir suivi ces รฉtapes jusqu'ร  ce que nous extracPour toutes les valeurs maximales, nous obtiendrons le tableau suivant.

Crรฉer un tri par tas avec un exemple

Quโ€™est-ce que le tas binaire ?

Un tas binaire est une sorte de tas complet arbre binaire Structure de donnรฉes. Dans ce type de structure arborescente, le nล“ud parent est soit plus grand, soit plus petit que les nล“uds enfants. Si le nล“ud parent est plus petit, alors le tas est appelรฉ ยซ Min Heap ยป et si le nล“ud parent est plus grand, le tas est appelรฉ ยซ Max Heap ยป.

Voici des exemples de tas min et max.

Tas minimum et tas maximum
Tas minimum et tas maximum

Dans la figure ci-dessus, si vous remarquez le ยซ Min Heap ยป, le nล“ud parent est toujours plus petit que ses nล“uds enfants. En tรชte de lโ€™arbre, on retrouve la plus petite valeur 10.

De mรชme, pour le ยซ Max Heap ยป, le nล“ud parent est toujours plus grand que les nล“uds enfants. L'รฉlรฉment maximum est prรฉsent au nล“ud principal du ยซ Max Heap ยป.

Quโ€™est-ce que ยซ Heapify ยป ?

ยซ Heapify ยป est le principe du tas qui assure la position du nล“ud. Dans Heapify, un tas maximum maintient toujours une relation avec le parent et l'enfant, et ce nล“ud parent sera plus grand que les nล“uds enfants.

Par exemple, si un nouveau nล“ud est ajoutรฉ, il faut restructurer le tas. Cependant, il peut รชtre nรฉcessaire de modifier ou d'รฉchanger des nล“uds, ou encore de rรฉorganiser un tableau. Ce processus de restructurationping Un tas est appelรฉ ยซempilerยป.

Voici un exemple du fonctionnement de heapify :

Ajout d'un nouveau nล“ud et Heapify
Ajouter un nouveau nล“ud et tasifier

Voici les รฉtapes pour heapify :

ร‰tape 1) Ajout du nล“ud 65 comme enfant droit du nล“ud 60.

ร‰tape 2) Vรฉrifiez si le nล“ud nouvellement ajoutรฉ est supรฉrieur au parent.

ร‰tape 3) Comme il est supรฉrieur au nล“ud parent, nous avons รฉchangรฉ le bon enfant avec son parent.

Comment construire le tas

Avant de construire le tas ou de regrouper un arbre, nous devons savoir comment nous allons le stocker. Comme le tas est un arbre binaire complet, il est prรฉfรฉrable d'utiliser un tableau pour contenir les donnรฉes du tas.

Disons qu'un tableau contient un total de n รฉlรฉments. Si le ยซ i ยป รจme index est un nล“ud parent, alors le nล“ud de gauche sera ร  lโ€™index (2i+1), et le nล“ud de droite sera ร  l'index (2i+2). Nous supposons que l'index du tableau commence ร  0.

En utilisant cela, stockons un tas maximum dans un tableau semblable ร  celui-ci :

Reprรฉsentation basรฉe sur un tableau du tas maximum
Reprรฉsentation basรฉe sur un tableau du tas maximum

L'algorithme heapify conserve la propriรฉtรฉ tas. Si le parent n'a pas la valeur extrรชme (infรฉrieure ou supรฉrieure), il sera รฉchangรฉ avec le nล“ud enfant le plus extrรชme.

Voici les รฉtapes pour regrouper un tas maximum :

ร‰tape 1) Commencez par le nล“ud feuille.

ร‰tape 2) Trouvez le maximum entre le parent et les enfants.

ร‰tape 3) ร‰changez les nล“uds si le nล“ud enfant a une valeur supรฉrieure ร  celle du parent.

ร‰tape 4) Montez d'un niveau.

ร‰tape 5) Suivez les รฉtapes 2,3,4 jusqu'ร  ce que nous atteignions l'index 0 ou trions l'arbre entier.

Voici le pseudo-code pour heapify rรฉcursif (tas max) :

def heapify():
  inputโ†’ array, size, i
  largest = i
  left = 2*i + 1
  right = 2*i + 2
if left<n and array[largest ] < array[left]:
  largest = left
if right<n and array[largest ] < array[right]:
  largest = right
If largest not equals i:
  swap(array[i],array[largest])
  heapify(array,n,largest)

Faux Code pour le tri par tas

Voici le pseudo-code de l'algorithme de tri par tas :

Heapify(numbers as an array, n as integer, i as integer):
  largest = i
  left = 2i+1
  right= 2i+2
if(left<=n) and (numbers[i]<numbers[left])
  largest=left
if(right<=n) and (numbers[i]<numbers[right])
  largest=right
if(largest  != i)
  swap(numbers[i], numbers[largest])
  Heapify(numbers,n,largest)
HeapSort(numbers as an array):
  n= numbers.size()
for i in range n/2 to 1
  Heapify(numbers,n,i)
for i in range n to 2
  Swap numbers[i] with numbers[1]
  Heapify(numbers,i,0)

Exemple de tri par tas Code in C++

#include <iostream>
using namespace std;
void display(int arr[], int n)
{
    for (int i = 0; i < n; i++)
    {
        cout << arr[i] << "\t";
    }
    cout << endl;
}
void heapify(int numbers[], int n, int i)
{
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;
    if (left < n && numbers[left] < numbers[largest])
    {
        largest = left;
    }
    if (right < n && numbers[right] < numbers[largest])
    {
        largest = right;
    }
    if (largest != i)
    {
	//uncomment the following line to see details in output
        //cout<<"Swapping "<< numbers[i]<< " and "<<numbers[largest]<<endl;
        swap(numbers[i], numbers[largest]);
        heapify(numbers, n, largest);
    }
}
void heapSort(int numbers[], int n)
{
    for (int i = n/2 - 1; i >= 0; i--)
    {
        heapify(numbers, n, i);
//uncomment the following line to see details in output
 //cout<<"Heapify:\t";
  //display(numbers,n);
    }
    for (int i = n - 1; i >= 0; i--)
    {
        swap(numbers[0], numbers[i]);
        heapify(numbers, i, 0);
    }
}
int main()
{
    int numbers[] = { 10,5, 7, 9, 4, 11, 45, 17, 60};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    cout<<"Initial Array:\t";
    display(numbers,size);
    heapSort(numbers, size);
    cout<<"Sorted Array (descending order):\t";
    display(numbers, size);
}

Sortie :

Initial Array:  10      5       7       9       4       11      45      17      60
Sorted Array (descending order):  60      45      17      11      10      9       7       5       4

Exemple de tri par tas Code in Python

def display(arr):
    for i in range(len(arr)):
    print(arr[i], end = "\t")
print()
def heapify(numbers, n, i):
    largest = i
left = 2 * i + 1
right = 2 * i + 2
if left < n and numbers[left] < numbers[largest]:
    largest = left
if right < n and numbers[right] < numbers[largest]:
    largest = right
if largest != i:
    numbers[i], numbers[largest] = numbers[largest], numbers[i]
heapify(numbers, n, largest)
def heapSort(items, n):
    for i in range(n //2,-1,-1):
        heapify(items, n, i) for i in range(n - 1, -1, -1):
        items[0], items[i] = items[i], items[0] heapify(items, i, 0) numbers = [10, 5, 7, 9, 4, 11, 45, 17, 60] print("Initial List:\t", end = "") display(numbers) print("After HeapSort:\t", end = "") heapSort(numbers, len(numbers)) display(numbers)

Sortie :

Initial List:   10      5       7       9       4       11      45      17      60
After HeapSort: 60      45      17      11      10      9       7       5       4

Analyse de la complexitรฉ temporelle et spatiale du tri par tas

Il existe une complexitรฉ temporelle et une complexitรฉ spatiale que nous pouvons analyser pour le tri par tas. Pour la complexitรฉ temporelle, nous avons les cas suivants :

  1. Meilleur cas
  2. Cas moyen
  3. Pire cas

Le tas est implรฉmentรฉ sur un arbre binaire complet. Ainsi, au niveau infรฉrieur de lโ€™arbre binaire, il y aura le nombre maximum de nล“uds. Si le niveau infรฉrieur a n nล“uds, alors le niveau supรฉrieur aura n/2 nล“uds.

Analyse de la complexitรฉ temporelle et spatiale

Dans cet exemple, le niveau 3 comporte quatre รฉlรฉments, le niveau 2 comporte deux รฉlรฉments et le niveau 1 comporte un รฉlรฉment. S'il y a un nombre total de n รฉlรฉments, la hauteur ou le niveau total sera Historique2(n). Ainsi, lโ€™insertion dโ€™un seul รฉlรฉment peut prendre un maximum de Log(n) itรฉrations.

Lorsque nous voulons prendre la valeur maximale du tas, nous prenons simplement le nล“ud racine. Lร  encore, exรฉcutez le heapify. Chaque tas prend Historique2(n) temps. ExtracL'obtention du maximum prend un temps O(1).

Meilleur cas de complexitรฉ temporelle pour l'algorithme de tri par tas

Lorsque tous les รฉlรฉments sont dรฉjร  triรฉs dans le tableau, il faudra O(n) temps pour construire le tas. Parce que si la liste est triรฉe, l'insertion d'un รฉlรฉment prendra le temps constant O(1).

Ainsi, il faudra O(n) temps pour crรฉer un tas maximum ou un tas min dans le meilleur des cas.

Complexitรฉ du temps moyen d'un cas pour l'algorithme de tri par tas

Insรฉrer un รฉlรฉment ou extracL'obtention d'un maximum coรปte un temps O(log(n)). Ainsi, la complexitรฉ temporelle moyenne de l'algorithme de tri par tas est de O(log(n)). O(n log(n)).

Dans le pire des cas, complexitรฉ temporelle pour l'algorithme de tri par tas

Semblable au cas moyen, dans le pire des cas, nous pourrions effectuer n fois un tas. Chaque heapify coรปtera du temps O(log(n)). Ainsi, la complexitรฉ temporelle dans le pire des cas sera O(n log(n)).

Complexitรฉ spatiale pour l'algorithme de tri par tas

Le tri par tas est un algorithme conรงu sur place. Cela signifie qu'aucune mรฉmoire supplรฉmentaire ou temporaire n'est nรฉcessaire pour effectuer la tรขche. Si nous voyons l'implรฉmentation, nous remarquerons que nous avons utilisรฉ swap() pour effectuer l'รฉchange des nล“uds. Aucune autre liste ou tableau n'รฉtait nรฉcessaire. Ainsi, la complexitรฉ spatiale est O(1).

FAQ

Le tri par tas n'est pas un algorithme de tri stable, car la construction et l'extracL'extraction d'รฉlรฉments du tas peut rรฉorganiser les รฉlรฉments รฉgaux. Si la prรฉservation de l'ordre initial des clรฉs รฉgales est importante, un algorithme stable comme le tri fusion est prรฉfรฉrable.

Le tri par tas garantit une complexitรฉ temporelle de O(n log n) dans tous les cas et utilise un espace supplรฉmentaire de O(1). Le tri rapide est gรฉnรฉralement plus rapide en pratique, mais sa complexitรฉ peut atteindre O(nยฒ) en cas de mauvais pivots. Le tri par tas privilรฉgie la fiabilitรฉ du tri dans le pire des cas au dรฉtriment de la vitesse.

Le tri par tas et le tri fusion s'exรฉcutent tous deux en O(n log n). Le tri par tas effectue le tri sur place avec un espace supplรฉmentaire de O(1), mais il est instable. Le tri fusion est stable, mais nรฉcessite un espace supplรฉmentaire de O(n) pour la fusion.

Les tuteurs IA peuvent animer le processus de construction du tas, montrer comment se forme le tas maximal, et trace chaque extracร‰tape t-max. Cette aide visuelle et interactive facilite la comprรฉhension, pour les dรฉbutants, du fonctionnement du tri par tas dans un tableau.

Oui. Les assistants de programmation IA peuvent traduire une implรฉmentation de tri par tas entre des langages tels que C++, Python et Java pendant que vous gardezping La logique est intacte. Il est tout de mรชme conseillรฉ de compiler et de tester le code converti afin de vรฉrifier que le rรฉsultat est correct.

Rรฉsumez cet article avec :