Utiliser Python pour implémenter des structures de données de base [03/4]

illustrer

        Si vous avez besoin d'utiliser ces connaissances mais que vous ne les possédez pas, cela sera frustrant et pourrait conduire à un refus de l'entretien. Que vous passiez quelques jours à « faire du blitz » ou que vous utilisiez un temps fragmenté pour continuer à apprendre, cela vaut la peine de travailler sur la structure des données. Alors, quelles sont les structures de données en Python ? Des listes, des dictionnaires, des ensembles et... des piles ? Python a-t-il une pile ? Cette série d'articles donnera des pièces de puzzle détaillées.
 

9章:Listes liées avancées

Nous avons déjà introduit les listes chaînées simples. Un nœud de liste chaînée ne contient que des données et des champs suivants. Ce chapitre présente les listes chaînées avancées.

Liste doublement chaînée, liste doublement chaînée, chaque nœud a un précédent supplémentaire pointant vers le nœud précédent. Les listes à double chaînage peuvent être utilisées pour écrire des tampons d’éditeur de texte.

class DListNode : 
    def __init__(self, data) : 
        self.data = data 
        self.prev = None 
        self.next = None 


def revTraversa(tail) : 
    curNode = tail 
    alors que cruNode n'est pas None : 
        print(curNode.data) 
        curNode = curNode .prev 


def search_sorted_doubly_linked_list(head, tail,probe, target) : 
    """ technique de sondage, qui améliore le parcours direct, mais la pire complexité temporelle est toujours O(n) 
    recherchant une liste doublement chaînée triée en utilisant la technique de sondage 
    Args : 
        head ( DListNode obj) 
        queue (DListNode obj) 
        sonde (DListNode ou None) 
        cible (DListNode.data) : données à rechercher 
    """
    si head est None : # assurez-vous que la liste n'est pas vide, 
        retournez False 
    si la sonde est Aucune : # si la sonde est nulle, initialisez-la au premier nœud 
        sonde = head 

    # si la cible vient avant le nœud de la sonde, nous traversons en arrière, sinon 
    # traversons forward 
    si cible <probe.data : 
        alors que la sonde n'est pas Aucune et cible <= sonde.data : 
            si cible == sonde.dta : 
                renvoie True 
            else : 
                sonde = sonde.prev 
    sinon : 
        tandis que la sonde n'est pas Aucune et cible >= sonde .data : 
            si cible == sonde.data : 
                renvoie True 
            sinon :
                sonde = sonde.next 
    return False 


def insert_node_into_ordered_doubly_linekd_list(value): 
    """ Il est préférable de faire un dessin pour le voir. Les opérations de liste chaînée sont faciles à confondre, alors faites attention à l'ordre d'affectation. """ newnode = 
    DListNode (valeur) 

    si head est Aucun : # liste vide 
        head = newnode 
        tail = head 

    valeur elif < head.data : # insérer avant head 
        newnode.next = head 
        head.prev = newnode 
        head = newnode 

    elif value > tail.data : # insérer après la queue 
        newnode.prev = tail 
        tail.next = newnode 
        tail = newnode 

    else : # insérer au milieu 
        le nœud du milieu = head
        tandis que le nœud n'est pas Aucun et node.data < valeur :
            node = node.next 
        newnode.next = node 
        newnode.prev = node.prev 
        node.prev.next = newnode 
        node.prev = newnode

liste chaînée circulaire

def travrseCircularList(listRef) : 
    curNode = listRef 
    done = listRef est Aucun 
    alors qu'il n'est pas Aucun : 
        curNode = curNode.next 
        print(curNode.data) 
        done = curNode est listRef # 回到遍历起始点


def searchCircularList(listRef, target) : 
    curNode = listRef 
    done = listRef est None 
    tant que ce n'est pas fait : 
        curNode = curNode.next 
        si curNode.data == target : 
            return True 
        sinon : 
            done = curNode est listRef ou curNode.data > target 
    return False 


def add_newnode_into_ordered_circular_linked_list(listRef, value): 
    "" " 插入并维持顺序 
    1. Insérez une liste chaînée vide ; 2. Insérez la tête ; 3. Insérez la queue ; 4. Insérez le milieu dans l'ordre
    """ 
    newnode = ListNode(value) 
    si listRef est None : # liste vide 
        listRef = newnode 
        newnode.next = newnode 

    elif value < listRef.next.data : # insérer devant 
        newnode.next = listRef.next 
        listRef.next = newnode 

    valeur elif > listRef.data : # insérer à l'arrière 
        newnode.next = listRef.next 
        listRef.next = newnode 
        listRef = newnode 

    else : # insérer au milieu 
        preNode = Aucun 
        curNode = listRef 
        done = listRef est Aucun 
        tant que ce n'est pas fait :  
            preNode = curNode
            preNode = curNode.suivant 
            done = curNode est listRef ou curNode.data > valeur 

        newnode.next = curNode 
        preNode.next = newnode

En utilisant une liste chaînée circulaire à double extrémité, nous pouvons implémenter un algorithme classique d'invalidation du cache, lru :

# -*- codage : utf-8 -*- 

class Node(object) : 
    def __init__(self, prev=None, next=None, key=None, value=None) : 
        self.prev, self.next, self. clé, self.value = prev, next, key, value 


class CircularDoubleLinkedList(object): 
    def __init__(self): 
        node = Node() 
        node.prev, node.next = node, node 
        self.rootnode = node 

    def headnode(self ) : 
        return self.rootnode.next 

    def tailnode(self) : 
        return self.rootnode.prev 

    def remove(self, node) : 
        si le nœud est self.rootnode : 
            return 
        else :  
            node.prev.next = node.next
            node.next.prev = node.prev

    def append(self, node) : 
        tailnode = self.tailnode() 
        tailnode.next = nœud 
        node.next = self.rootnode 
        self.rootnode.prev = 


classe de nœud LRUCache(object) : 
    def __init__(self, maxsize=16) : 
        self.maxsize = maxsize 
        self.cache = {} 
        self.access = CircularDoubleLinkedList() 
        self.isfull = len(self.cache) >= self.maxsize 

    def __call__(self, func) : 
        def wrapper(n) : 
            cachenode = self .cache.get(n) 
            si cachenode n'est pas Aucun : # hit  
                self.access.remove(cachenode)
                self.access.append(cachenode) 
                return cachenode.value
            else : # miss 
                value = func(n) 
                if not self.isfull : 
                    tailnode = self.access.tailnode() 
                    newnode = Node(tailnode, self.access.rootnode, n, value) 
                    self.access.append(newnode) 
                    self .cache[n] = newnode 

                    self.isfull = len(self.cache) >= self.maxsize 
                    valeur de retour 
                else : # full 
                    lru_node = self.access.headnode() 
                    del self.cache[lru_node.key]  
                    self.access.remove(lru_node)
                    tailnode = self. accès.tailnode() 
                    newnode = Node(tailnode, self.access.rootnode, n, value) 
                    self.access.append(newnode) 
                    self.cache[n] = newnode 
                valeur de retour 
        return wrapper 


@LRUCache() 
def fib(n) : 
    si n <= 2 : 
        renvoie 1 
    sinon : 
        renvoie fib(n - 1) + fib(n - 2) 


pour i dans la plage (1, 35) : 
    print(fib(i))

Chapitre 10 : Récursion

La récursivité est un processus permettant de résoudre des problèmes en subdivisant un problème plus vaste en cas plus petits du problème lui-même, puis en résolvant les parties les plus petites et les plus triviales.

Fonction récursive : appelez votre propre fonction

# Fonction récursive : appelez votre propre fonction, regardez la fonction récursive la plus simple, imprimez un nombre dans l'ordre inverse 
def printRev(n) : 
    si n > 0 : 
        print(n) 
        printRev(n-1) 


printRev(3) # Sortie de 10 à 1 


# Faites un léger changement et mettez print à la fin pour obtenir la fonction d'impression d'ordre positif 
def printInOrder(n): 
    if n > 0: 
        printInOrder(n-1) 
        print(n) # La raison pour laquelle le plus petit est imprimé en premier parce que la fonction Recurse jusqu'à la pile la plus profonde lorsque n == 1. A ce moment, il n'y a plus de 
                    récursion et l'instruction print commence à être exécutée. A ce moment, n == 1, après chaque couche de la pile est sautée, une valeur plus grande est imprimée. 

printInOrder(3) # Sortie de séquence positive

Propriétés de la récursion : tous les problèmes résolus à l'aide de la pile peuvent être résolus à l'aide de la récursivité

  • Une solution récursive doit contenir un cas de base ; une sortie récursive, représentant le plus petit sous-problème (n == 0 sortie d'impression)
  • Une solution récursive doit contenir un cas récursif ; des sous-problèmes pouvant être décomposés
  • Une solution récursive doit progresser vers le cas de base. Décrémenter n pour que n soit plus proche de la sortie récursive

Récursion de queue : se produit lorsqu'une fonction inclut un seul appel récursif comme dernière instruction de la fonction. Dans ce cas, une pile n'est pas nécessaire pour stocker les valeurs à utiliser au retour de l'appel récursif et une solution peut donc être implémentée en utilisant une boucle itérative à la place.

# Recherche binaire récursive 

def recBinarySearch(target, theSeq, first, last) : 
    # Vous pouvez écrire des tests unitaires pour vérifier l'exactitude de cette fonction 
    si premier > dernier : # Sortie récursive 1 
        return False 
    else : 
        mid = (premier + dernier) / / 2 
        if theSeq[mid] == cible : 
            return True # Sortie récursive 2 
        elif theSeq[mid] > target : 
            return recBinarySearch(target, theSeq, first, mid - 1) 
        sinon : 
            return recBinarySearch(target, theSeq, mid + 1 , dernier)

Chapitre 11 : Tables de hachage

La meilleure complexité temporelle de la recherche basée sur la comparaison (recherche linéaire, recherche binaire de tableaux ordonnés) ne peut atteindre que O(logn). La recherche O(1) peut être réalisée en utilisant le hachage. L'implémentation du dict intégré de Python est le hachage. Vous constaterez que la clé de dict doit implémenter la  méthode __hash__ and  __eq__ .

Hachage : le hachage est le processus de mappage d'une recherche d'une clé à une gamme limitée d'index de tableau dans le but de fournir un accès direct aux clés.

La méthode de hachage a une fonction de hachage qui est utilisée pour calculer une valeur de hachage pour la clé, qui est utilisée comme indice de tableau et placée dans l'emplacement correspondant à l'indice. Lorsque différentes clés ont le même indice calculé en fonction de la fonction de hachage, un conflit se produit. Il existe de nombreuses façons de résoudre les conflits, comme faire de chaque emplacement une liste chaînée et le placer à la fin de la liste chaînée des emplacements après chaque conflit, mais le temps de requête se dégradera et n'est plus O(1). Il existe également une méthode de sondage. Lorsque les emplacements de la clé sont en conflit, une méthode de calcul sera utilisée pour trouver le prochain emplacement vide pour le stockage. Les méthodes de sondage incluent le sondage linéaire, le sondage quadratique, etc. L'interpréteur Python utilise la méthode d'exploration du carré quadratique. . Un autre problème est que lorsque le nombre d'emplacements utilisés par Python est supérieur aux 2/3 du nombre pré-alloué, la mémoire sera réaffectée et les données précédentes seront copiées. Par conséquent, parfois l'opération d'ajout de dict est relativement coûteuse, sacrifiant de l'espace mais il peut toujours garantir l'efficacité des requêtes O (1). S'il y a une grande quantité de données, il est recommandé d'utiliser bloomfilter ou HyperLogLog fourni par redis.

Si vous êtes intéressé, vous pouvez consulter cet article, qui présente comment l'interpréteur c implémente l'objet python dict : Implémentation du dictionnaire Python . Nous utilisons Python pour implémenter une structure de hachage similaire.

import ctypes 

class Array: # L'ADT défini au chapitre 2 est utilisé ici comme tableau d'emplacements de HashMap 
    def __init__(self, size): 
        assert size > 0, 'array size must be > 0' 
        self._size = size 
        PyArrayType = ctypes .py_object * size 
        self._elements = PyArrayType() 
        self.clear(None) 

    def __len__(self) : 
        return self._size 

    def __getitem__(self, index) : 
        assert index >= 0 et index < len(self), ' out of range' 
        return self._elements[index] 

    def __setitem__(self, index, value) : 
        assert index >= 0 et index < len(self), 'hors plage' 
        self._elements[index] = valeur 

    def clear( self ,valeur):
        """ 设置每个元素为value """ 
        for i in range(len(self)): 
            self._elements[i] = value 

    def __iter__(self): 
        return _ArrayIterator(self._elements) 


class _ArrayIterator: 
    def __init__( self, items) : 
        self._items = items 
        self._idx = 0 

    def __iter__(self) : 
        return self 

    def __next__(self) : 
        si self._idx < len(self._items) : 
            val = self._items[self._idx ] 
            self._idx += 1 
            return val 
        else: 
            raise StopIteration 


class HashMap: 
    """ HashMap ADT实现,类似于python内置的dict 
    Un slot a trois états : 
    1. HashMap.UNUSED n'a jamais été utilisé. Cet emplacement n'a pas été utilisé ou n'est pas en conflit. Tant que UNUSEd est trouvé lors de la recherche, il n'est pas nécessaire de continuer la recherche.
    2. Il a été utilisé mais supprimé. Pour le moment, il s'agit de HashMap.EMPTY. L'élément derrière le point de sonde peut avoir une clé. 
    3. Le slot utilise le nœud _MapEntry 
    """ 

    classe _MapEntry : # Les données stockées dans le slot 
        def __init__(self , key, value) : 
            self.key = key 
            self.value = value 

    UNUSED = None # Un slot inutilisé, en tant qu'instance unique de ce type de variable, est jugé ci-dessous par 
    EMPTY = _MapEntry(None, Aucun) # Slots utilisés mais supprimés 

    def __init__(self): 
        self._table = Array(7) # Initialiser 7 slots 
        self._count = 0 
        # Réallouer lorsque plus des 2/3 de l'espace est utilisé, facteur de charge = 2/3 
        self ._maxCount = len(self._table) - len(self._table) // 3 
    def __contains__(self, key) : 
        slot = self._findSlot(key, False)
 
    def __len__( soi):
        return self._count 

        return slot is not None 

    def add(self, key, value): 
        if key in self: # 覆盖原有value 
            slot = self._findSlot(key, False) 
            self._table[slot].value = value 
            return False 
        sinon : 
            slot = self._findSlot(key, True) 
            self._table[slot] = HashMap._MapEntry(key, value) 
            self._count += 1 
            if self._count == self._maxCount: # 超过2/3使用就rehash 
                self._rehash() 
            return True 

    def valueOf(self, key): 
        slot = self._findSlot(key, False) 
        assert slot n'est pas Aucun, 'Clé de carte invalide' 
        return self._table[slot].value 

    def remove(self, key) : 
        """ L'opération de suppression définit l'emplacement sur VIDE """ 
        assert key in self, 'Key error %s' % key 
        slot = self._findSlot(key, forInsert=False) 
        value = self ._table[slot].value 
        self._count -= 1 
        self._table[slot] = HashMap.EMPTY 
        valeur de retour 

    def __iter__(self) : 
        return _HashMapIteraotr(self._table) 

    def _slot_can_insert(self, slot) : 
        return (self . _table[slot] est HashMap.EMPTY ou 
                self._table[slot] est HashMap.UNUSED) 

    def _findSlot(self, key, forInsert=False): 
        """ Notez qu'il y a des erreurs dans le livre d'origine et que le code ne peut pas s'exécuter du tout. Je l'ai réécrit moi-même ici Args
        :
            forInsert (bool) : si la recherche porte sur un si la recherche porte sur une insertion 
        , renvoie :
            slot d'insertion ou None 
        """ 
        slot = self._hash1(key) 
        step = self._hash2(key) 
        _len = len(self._table) 

        if not forInsert : # 查找是否存在key 
            while self._table[slot] n'est pas HashMap.UNUSED: 
                # 如果一个槽是UNUSED, 直接跳出
                if self._table[slot] is HashMap.EMPTY: 
                    slot = (slot + step) % _len 
                    continue 
                elif self._table[ slot].key == clé : 
                    retour slot 
                slot = (slot + pas) % _len 
            return Aucun
 
        else : # Afin d'insérer la clé 
            sans self._slot_can_insert(slot): # Bouclez jusqu'à ce que vous trouviez un emplacement pouvant être inséré 
                slot = (slot + step) % _len 
            return slot 

    def _rehash(self): # Le nombre de les emplacements actuellement utilisés sont supérieurs aux 2/3 Lors de la recréation d'une nouvelle table 
        origTable = self._table 
        newSize = len(self._table) * 2 + 1 # L'original 2*n+1 fois 
        self._table = Array(newSize) 

        self._count = 0 
        self._maxCount = newSize - newSize // 3 

        # Ajoutez la valeur de clé d'origine à la nouvelle table 
        pour l'entrée dans origTable : 
            si l'entrée n'est pas HashMap.UNUSED et que l'entrée n'est pas HashMap.EMPTY : 
                slot = self._findSlot (entry.key, True) 
                self._table[slot] = entrée
                self._count += 1 

    def _hash1(self, key): 
        """ clé de hachage et de hachage""" 
        return abs(hash(clé)) % len(self._table) 
                self._idx += 1
 
    def _hash2(self, clé) :
        """ key""" 
        return 1 + abs(hash(key)) % (len(self._table)-2) 


class _HashMapIteraotr: 
    def __init__(self, array): 
        self. _array = array 
        self._idx = 0 

    def __iter__(self) : 
        return self 

    def __next__(self) : 
        si self._idx < len(self._array) : 
            si self._array[self._idx] n'est pas None et self._array [self._idx].key n'est pas Aucun : 
                key = self._array[self._idx].key 
                return key 
            else : 
                self._idx += 1 
        else : 
            raise StopIteration 


def print_h(h) :
    pour idx, i in enumerate(h): 
        print(idx, i) 
    print('\n') 


def test_HashMap(): 
    """ Quelques tests unitaires simples, mais la couverture des cas de test n'est pas très complète""" 
    h = HashMap () 
    assert len(h) == 0 
    h.add('a', 'a') 
    assert h.valueOf('a') == 'a' 
    assert len(h) == 1 

    a_v = h.remove ( 'a') 
    assert a_v == 'a' 
    assert len(h) == 0 

    h.add('a', 'a') 
    h.add('b', 'b') 
    assert len(h) = = 2 
    affirmer h.valueOf('b') == 'b' 
    b_v = h.Remove('b') 
    assert b_v == 'b'
    assert len(h) == 1 
    h.remove('a') 
    assert len(h) == 0 

    n = 10
    pour i dans la plage (n) : 
        h.add (str (i), i) 
    assert len ​​(h) == n 
    print_h (h) 
    pour i dans la plage (n): 
        assert str (i) dans h 
    pour i dans la plage (n): 
        h.remove(str(i)) 
    assert len(h) == 0

12章 : Tri avancé

Le chapitre 5 présente les algorithmes de tri de base et ce chapitre présente les algorithmes de tri avancés.

Tri par fusion : diviser pour mieux régner

def merge_sorted_list(listA, listB): 
    """ s'il vous plaît, O(max(m, n)) ,mnn是数组长度""" print(' 
    fusionner la liste gauche droite', listA, listB, end='') 
    new_list = list() 
    a = b = 0 
    tandis que a < len(listA) et b < len(listB) : 
        si listA[a] < listB[b] : 
            new_list.append(listA[a]) 
            a += 1 
        sinon : 
            new_list.append(listB[b]) 
            b += 1 

    while a < len(listA) : 
        new_list.append(listA[a]) 
        a += 1 

    while b < len(listB) : 
        new_list. append(listB[b]) 
        b += 1 

    print(' ->',new_list) 
    renvoie new_list


def mergesort(theList) : 
    """ O(nlogn), appel de couche de journal, n opérations par couche 
    mergesort : diviser et conquérir Diviser et conquérir 
    1. Décomposer le tableau d'origine en sous-tableaux de plus en plus petits 
    2. Fusionner les sous-tableaux pour créer un tableau ordonné 
    """ 
    print(theList) # J'ai tapé les étapes clés, vous pouvez l'exécuter pour voir l'ensemble du processus 
    si len(theList) <= 1 : # Sortie récursive 
        return theList 
    else: 
        mid = len(theList ) // 2 

        # Décomposer récursivement les tableaux gauche et droit 
        left_half = mergesort(theList[:mid]) 
        right_half = mergesort(theList[mid:]) 

        # Fusionner les sous-tableaux ordonnés des deux côtés 
        newList = merge_sorted_list(left_half, right_half) 
        return newList 

"" "Il s'agit du processus de tri 
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1] 
[10, 9, 8, 7,6] 
[10, 9]
[10]
[9] 
fusionner la liste gauche droite [10] [9] -> [9, 10] 
[8, 7, 6] 
[8] 
[7, 6] 
[7] 
[6] 
fusionner la liste gauche droite [7] [6 ] -> [6, 7] 
fusionner la liste gauche droite [8] [6, 7] -> [6, 7, 8] 
fusionner la liste gauche droite [9, 10] [6, 7, 8] -> [6, 7, 8, 9, 10] 
[5, 4, 3, 2, 1] 
[5, 4] 
[5] 
[4] 
fusionner la liste gauche droite [5] [4] -> [4, 5] 
[3, 2, 1] 
[3] 
[2, 1] 
[2] 
[1] 
fusionner la liste gauche droite [2] [1] -> [1, 2] 
fusionner la liste gauche droite [3] [1, 2] -> [ 1, 2, 3] 
fusionner la liste gauche droite [4, 5] [1, 2, 3] -> [1, 2, 3, 4, 5] "" 
"

Tri rapide

def quicksort(theSeq, first, last): # moyenne: O(nlog(n)) 
    """ 
    quicksort : il s'agit également de diviser pour régner, mais contrairement au tri par fusion, il utilise le pivot sélectionné (pivot) au lieu du 
    tableau de Division 
    du milieu 1. Dans la première étape, sélectionnez le pivot pour diviser le tableau. Les éléments du côté gauche du pivot sont plus petits que lui et les éléments du côté droit sont supérieurs ou égaux. 2. 
    Récursion les tableaux divisés sur les côtés gauche et droit jusqu'à la sortie récursive (le nombre d'éléments du tableau est inférieur à 2) 
    3. Fusionner le pivot et les tableaux divisés gauche et droit en un tableau ordonné 
    """ 
    si premier < dernier : 
        pos = partitionSeq (theSeq, first, last) # Effectuer 
        un tri rapide de manière récursive (theSeq, first, pos - 1) 
        sur le 
        tri rapide des sous-tableaux divisés (theSeq, pos + 1, last) 
def partitionSeq(theSeq, first, last): 
    """ L'opération de partition dans un tri rapide, déplacez les éléments plus petits que le pivot vers la gauche et déplacez les éléments plus grands que le pivot vers la droite.""" 
    pivot = theSeq[first] 
    print('before partitionSeq',theSeq) 
    gauche = premier + 1



    right = last 

    while True: 
        # Trouvez le premier plus grand que pivot 
        while left <= right et theSeq[left] < pivot: 
            left += 1 

        # Commencez par la droite et trouvez le premier plus petit que pivot 
        while right >= left et theSeq[right ] >= pivot: 
            right -= 1 

        if right < left: 
            break 
        else: 
            theSeq[left], theSeq[right] = theSeq[right], theSeq[left] 

    # Mettre le pivot dans la position appropriée 
    theSeq[first ], theSeq [right] = theSeq[right], theSeq[first] 

    print('after partitionSeq {}: {}\t'.format(theSeq, pivot)) 
    return right # Renvoie la position du pivot 


def test_partitionSeq(): 
    je = [0,1,2,3,4]
    assert partitionSeq(l, 0, len(l)-1) == 0 
    l = [4,3,2,1,0] 
        quicksort(to_sort, 0, len(to_sort)-1) # Notez que le tri sur place est utilisé ici et que le tableau est directement modifié.
    assert partitionSeq(l, 0, len(l)-1) == 4 
    l = [2,3,0,1,4] 
    assert partitionSeq(l, 0, len(l)-1) == 2 

test_partitionSeq() 


def test_quicksort() : 
    def _is_sorted(seq) : 
        pour i dans la plage (len(seq)-1) : 
            si seq[i] > seq[i+1] : 
                renvoie False 
        renvoie True 

    à partir d'un randint d'importation aléatoire 
    pour i dans la plage ( 100) : 
        _len = randint(1, 100) 
        to_sort = [] 
        pour i dans range(_len) : 
            to_sort.append(randint(0, 100)) 
        print(to_sort) 
        assert _is_sorted(to_sort) 

test_quicksort()

En utilisant l'opération partitionSeq de tri rapide, nous pouvons également implémenter un autre algorithme, nth_element, pour trouver rapidement le kième plus grand élément dans un tableau non ordonné.

def nth_element(seq, beg, end, k) : 
    si beg == end : 
        return seq[beg] 
    pivot_index = partitionSeq(seq, beg, end) 
    if pivot_index == k : 
        return seq[k] 
    elif pivot_index > k : 
        return nth_element(seq, beg, pivot_index-1, k) 
    else : 
        return nth_element(seq, pivot_index+1, end, k) 

def test_nth_element() : 
    à partir d'une importation aléatoire shuffle 
    n = 10 
    l = list(range(n)) 
    shuffle( l) 
    print(l) 
    pour i in range(len(l)) : 
        assert nth_element(l, 0, len(l)-1, i) == i 

test_nth_element()

Je suppose que tu aimes

Origine blog.csdn.net/gongdiwudu/article/details/118143996
conseillé
Classement