Fusion de la mise en œuvre du tri / analyse du montant du calcul et de l'expérimentation en Python

Cette fois, je parlerai du tri par fusion (en utilisant la gouvernance fractionnée) de l'algorithme de tri. L'algorithme de tri est un algorithme qui trie les éléments de la structure de données dans l'ordre croissant ou décroissant, et le tri par fusion est l'un des algorithmes les plus courants.

Explication de l'algorithme

Dans le tri par fusion, le tri est essentiellement effectué à l'aide d'un tableau, mais comme son nom l'indique, le tableau est divisé puis mélangé. En faisant ce mélange, nous comparerons et trierons chaque élément. En conséquence, vous obtenez un tableau trié.

Divisé

Tout d'abord, lors du fractionnement, recherchez la valeur au milieu du tableau avec mid = (low + high) / 2. Par exemple, lorsque la longueur du tableau est n, mid = (0+ (n-1)) / 2 est la valeur médiane, et il est divisé en deux tableaux de 0 à milieu et milieu + 1 à n-1. Est répété et la division se termine lorsque la longueur du tableau devient 1. Dans la division, chaque séquence est divisée en deux séquences, donc une longue séquence est le parent et deux courtes séquences de même longueur sont les enfants, comme dans la structure de bifurcation. Imaginez que cela crée une arborescence log (n) avec une profondeur de 2.

Gouvernance

Lors de la gouvernance, les premiers éléments des deux tableaux enfants sont comparés et placés au début de la liste parent. Il incrémente ensuite l'index accédé de la liste contenant l'élément sélectionné de un, compare le deuxième élément avec le premier élément de un et le stocke dans l'index suivant de la liste parente. La valeur de l'index sélectionné de cette manière est incrémentée, le travail de stockage dans la liste parent est répété jusqu'au dernier élément de l'une ou l'autre des listes enfants, et les éléments de la liste avec les éléments restants sont stockés dans l'ordre. En répétant ceci dans l'ordre du nœud final de l'arborescence au nœud racine, le tableau trié par le dernier nœud racine est terminé.

À la fin, je publierai un site Web qui explique de manière facile à comprendre avec des graphiques.

la mise en oeuvre

J'ai implémenté brièvement une fonction de tri par fusion, je vais donc l'expliquer. J'ai ajouté le numéro de ligne de 1 dans le commentaire sur le côté droit de chaque ligne.

merge_sort.py


def merge(array):                                   # line1
    mid = len(array)                                # line2
    if mid > 1:                                     # line3
        left = merge(array[:(mid/2)])               # line4
        right = merge(array[(mid/2):])              # line5
        array = []                                  # line6
        while len(left) != 0 and len(right) != 0:   # line7
            if left[0] < right[0]:                  # line8
                array.append(left.pop(0))           # line9
            else:                                   # line10
                array.append(right.pop(0))          # line11
        if len(left) != 0:                          # line12
            array.extend(left)                      # line13
        elif len(right) != 0:                       # line14
            array.extend(right)                     # line15
    return array                                    # line16

-Je l'ai fait en supposant que la valeur prise par le paramètre dans line1 est un tableau contenant uniquement des entiers dans l'élément.

-J'ai demandé la valeur de la longueur du tableau avec line2, mais c'est un peu différent de l'explication ci-dessus car j'ai créé un nouveau tableau à chaque fois que je l'ai divisé avec Python. Dans le cas d'un tableau tel que JAVA, il est divisé lors du calcul du numéro d'index d'un tableau avec un objet invariant, donc trouvez-le par la méthode décrite ci-dessus.

-En ligne3, il est jugé si la longueur du tableau est plus longue que 1 ou plus, si elle est longue, le code de ligne4 à ligne15 est exécuté, et s'il est court, le tableau est renvoyé tel quel en tant que valeur de retour.

-Dans les lignes 4 et 5, la fonction est appelée en donnant au paramètre un tableau qui coupe récursivement la liste parent en deux.

-Comme vous pouvez le voir dans le code jusqu'à présent, en appelant la fonction de manière récursive, le tableau est divisé jusqu'à ce qu'il devienne 1.

-La raison pour laquelle le tableau parent est vide en ligne6 est que la méthode append () (ajouter un élément à la fin de la liste) est utilisée pour mettre une valeur dans la liste après cela. Le tableau d'origine contenait déjà des éléments et j'ai pensé qu'il serait peu pratique d'ajouter des éléments.

-Line7 a utilisé une boucle, mais elle continuera à boucler à moins qu'une des listes ne soit vide.

-Comparez les premiers éléments des deux tableaux sur les lignes 8 à 11, supprimez le premier élément du tableau contenant des éléments plus petits et ajoutez-le à la fin du tableau parent. Continuez ce processus jusqu'à ce que l'une des listes soit vide.

-Dans les lignes 12 à 15, une liste devient vide lorsque la boucle de la ligne 7 se termine, mais l'autre liste laisse au moins un élément, donc les éléments restants de l'un ou l'autre des tableaux sont rassemblés dans la liste parent. En plus de.

-Dans line16, retourne chaque tableau trié comme valeur de retour, trie le tableau parent de chaque tableau, et lorsque le nœud racine est atteint, renvoie tous les éléments de la séquence donnée au paramètre dans un état trié. Je vais.

Montant du calcul

Soit T (n) la quantité totale de calcul dans le tri par fusion, où n est le nombre d'éléments dans le tableau ou la longueur du tableau. Puisque T (0) et T (1) ne font rien, le montant du calcul est de 0. Dans le tri par fusion, le tableau est d'abord divisé par deux et le tri par fusion est appelé récursivement, donc T (n / 2) le fait deux fois avec le montant du calcul (lignes 4 et 5) lorsqu'il est appelé récursivement, donc T (n / 2) ) + T (n / 2) = 2 Lorsque T (n / 2) appelle les deux (ligne4 ~ 5). En plus de cela, le tri par fusion effectue une boucle n-1 fois dans le pire des cas, donc le montant total du calcul est T (n) = 2T (n / 2) + n -1. Vous connaissez maintenant la quantité de calcul lorsque la longueur du tableau de tri par fusion est n, mais comme le tri par fusion est appelé récursivement en divisant par deux le tableau, T (n / 2), T (n / 4), T (n / 8) ・ ・ ・ ・ ・ ・ ・ ・ ・ Nous vérifierons également le montant du calcul lorsque T (n / (2 ^ (k-1))). k est le nombre de fois où il est appelé récursivement et commence à k = 1. T(n/2) = 2T(n/4) + n/2 - 1, T(n/4) = 2T(n/8) + n/4 - 1, T(n/8) = 2T(n/16) + n/8 - 1, ・ ・ ・ ・ ・ T(n/2^(k-1)) = 2T(n/2^k) + n/2^(k-1) - 1 Est le montant du calcul lorsque k> = 1.

Substituer ceci dans l'équation de T (n) donne: T(n) = 2(2T(n/4) + n/2 - 1) + n - 1 = 4T(n/4) + 2n - (1 + 2) = 4(2T(n/8) + n/4 - 1) + 2n - (1 + 2) = 8T(n/8) + 3n - (1 + 2 + 4) = 8(2T(n/16) + n/8 - 1) + 3n - (1 + 2 + 4) = 8T(n/8) + 4n - (1 + 2 + 4 + 8) ・ ・ ・ ・ ・ = 2 ^ kT (n / 2 ^ k) + k * n- (1 + 2 + 4 + ・ ・ ・ ・ ・ + 2 ^ (k-1)) Ce sera.

avec ça T (n) = 0, si n = 0,1 T (n) = 2 ^ kT (n / 2 ^ k) + (k * n --k) - (1 + 2 + 4 + ・ ・ ・ ・ ・ + 2 ^ (k-1)), Il s'avère que si 2 <= n <= k.

Ici, le fait que les appels récursifs soient faits k fois signifie qu'il y a k couches dans la structure arborescente, et on peut dire que 2 ^ k est la valeur de n dans la k couche. Par conséquent, lorsque n = 2 ^ k et que cela est résolu pour k, k = log (n), et lorsque ceux-ci sont substitués dans l'équation de T (n), T (n) = nT (2 ^ k / 2 ^ k) + log (n) * n --log (n) - (1 + 2 + 4 + ・ ・ ・ ・ ・ + 2 ^ (log (n) -1) )) = nT(1) + nlog(n) - log(n) - (2^log(n) - 1) = nlog(n) - log(n) - (2^log(n) - 1)

Le premier terme est de T (1) = 0 à n * 0 = 0, et le dernier terme provient de la formule de somme (voir Wikipedia). Puisque nlog (n)> 2 ^ log (n), l'ordre de calcul est O (nlog (n)). En passant, dans le tri par fusion, le montant moyen du calcul et le meilleur montant de calcul sont identiques au pire montant de calcul.

Graphisme

Puisque le temps moyen a été réellement calculé et représenté graphiquement, je vais afficher le code source et le graphique.

merge_sort.py


import math
import random
import time
import matplotlib.pyplot as plt

#Copiez la fonction de tri par fusion ici

sumOfTime = 0
sumPltList = []
nlognList = []
list1 = []
#Boucle pour créer des longueurs de tableau 0-3000
for i in range(3000):
    #Boucle pour fusionner et trier 100 fois pour chaque tableau de longueur i
    for j in range(100):
        #0 pour chaque index~Entrez un nombre aléatoire de 100000
        for k in range(i):
            list1.append(random.randint(0,100000))
        #Temps avant le tri par fusion
        t0 = time.clock()
        merge(list1)
        #Temps après le tri par fusion
        t1 = time.clock()
        #Vider le tableau pour le prochain tri de fusion
        list1 = []
        #Somme des différences de temps lors du tri par fusion
        sumOfTime += t1 - t0
    #Valeur moyenne de 100 tris de fusion
    sumOfTime /= 100
    #Il n'y a aucune base car je stocke le temps moyen dans la liste et 2000000 est la queue du livre.
    sumPltList.append(sumOfTime*2000000)
    # log(0)Gérer ilog(i)Stocker i dans la liste pour comparaison
    if i != 0:
        nlognList.append(i*math.log(i)/math.log(2))
    else:
        nlognList.append(0.0)
    #Réinitialisez le temps total toutes les 100 fois
    sumOfTime = 0
#Fusionner le tri et le nlog(n)Tracez une courbe
plt.plot(sumPltList, "r-", label = "Merge_Sort")
plt.plot(nlognList, "g-", label = "O(nlogn)")
#Afficher l'étiquette en haut à gauche
plt.legend(loc=2)
#Attachez des étiquettes à l'axe des x et à l'axe des y
plt.xlabel('number of elements in a list')
plt.ylabel('time be taken')
#Affichage du graphique
plt.show()

La multiplication de 2000000 par le temps moyen est ajustée en regardant les résultats jusqu'au tableau de longueur 99, mais le graphique ci-dessous montre ce qui se passe avec les résultats jusqu'à 3000 de longueur.

マージソートとnlognの比較.png

Puisque la valeur du montant de calcul de 100 à 3000 en longueur est également proche de la valeur de nlog (n), on peut dire que l'expérience de montant de calcul est réussie.

Cette fois, j'ai expliqué, implémenté et analysé l'algorithme de tri par fusion, mais si vous trouvez quelque chose qui ne va pas ou n'est pas clair, veuillez commenter ou m'envoyer un e-mail. Je vous remercie. La prochaine fois, j'implémenterai des instructions Python ou d'autres algorithmes en Python. Merci d'avoir lu jusqu'au bout!

Lien de tri de fusion: http://www.ics.kagoshima-u.ac.jp/~fuchida/edu/algorithm/sort-algorithm/merge-sort.html

Recommended Posts

Fusion de la mise en œuvre du tri / analyse du montant du calcul et de l'expérimentation en Python
Algorithme de tri et implémentation en Python
Un mémo que j'ai écrit un tri de fusion en Python
Explication de la distance d'édition et de l'implémentation en Python
Implémentation RNN en python
Implémentation ValueObject en Python
Tri à bulles en Python
Tri personnalisé en Python3
Analyse d'association en Python
Implémentation SVM en python
Analyse de régression avec Python
Symboles logiques appris dans le mariage (et exemples d'implémentation en Python)
[Python] Comment trier un dict dans une liste et une instance dans une liste
Analyse en composants principaux (PCA) et analyse en composants indépendants (ICA) avec python
Trier naturellement le chemin en Python
Analyse des contraintes symétriques axiales avec Python
Tri décroissant avec mongodb en python
Pile et file d'attente en Python
Analyse de régression simple avec Python
Implémentation de réseau neuronal en python
Unittest et CI en Python
Description et implémentation de Maxout (Python)
Implémentation du tri rapide en Python
Trier par date en python
À propos de Python sort () et reverse ()
En Python, les éléments de la liste sont triés et sortis sous forme d'éléments et de multiples.
Paquets qui gèrent le MIDI avec Python midi et pretty_midi
Différence entre list () et [] en Python
Première analyse de régression simple en Python
Différence entre == et est en python
Nouveau dans les dictionnaires de fusion python3.9
Afficher les photos en Python et html
Implémentation de l'estimation des paramètres HMM en python
Implémentation de distribution normale mixte en python
Manipuler des fichiers et des dossiers en Python
À propos de Python et Cython dtype
Affectations et modifications des objets Python
Implémentation du jeu de vie en Python
Vérifiez et déplacez le répertoire en Python
Chiffrement avec Python: IND-CCA2 et RSA-OAEP
Trier les gros fichiers texte en Python
Hashing de données en R et Python
Synthèse de fonctions et application en Python
Exporter et exporter des fichiers en Python
Analyse du squelette planaire dans Python (2) Hotfix
Implémentation du tri original en Python
Implémentation simple de l'analyse de régression avec Keras
Inverser le pseudonyme plat et le katakana en Python2.7
Lire et écrire du texte en Python
[GUI en Python] Menu PyQt5 et barre d'outils-
Créer et lire des paquets de messages en Python
Analyse des données: application facile des statistiques descriptives et des statistiques d'estimation aux données CSV en Python
Implémentation du filtre à particules par Python et application au modèle d'espace d'états
Apprentissage profond à partir de zéro - Conseils du chapitre 4 pour la théorie de l'apprentissage profond et la mise en œuvre apprise en Python
Lors de la spécification de plusieurs clés dans le tri python
Chevauchement d'expressions régulières en Python et Java
Nouveautés de Python 3.9 (2) - Tri des graphes non circulés dirigés en Python
Différence d'authenticité entre Python et JavaScript
Notes utilisant cChardet et python3-chardet dans Python 3.3.1.
Différences entre Ruby et Python dans la portée