Utiliser Python pour implémenter des structures de données de base [02/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.

Chapitre 5 : Recherche et tri

        Le tri et la recherche sont les opérations les plus basiques et les plus fréquentes.Python a un module d'opération binaire d'opérateur et de bissectrice intégré pour implémenter la recherche, et une méthode triée intégrée pour implémenter l'opération de tri. Deux points et un tri rapide sont également souvent testés lors des entretiens. Ce chapitre parle du tri et de la recherche de base.

def binaire_search(sorted_seq, val) : 
    """ Implémentez bisect.bisect_left dans la bibliothèque standard """ 
    low = 0 
    high = len(sorted_seq) - 1 
    while low <= high : 
        mid = (high + low) // 2 
        if sorted_seq[mid] == val : 
            return mid 
        elif val < sorted_seq[mid] : 
            high = mid - 1 
        else : 
            low = mid + 1 
    return low 

  def bubble_sort(seq) : # O(n^2), n(n- 1)/2 = 1/2(n^2 + n) 
      n = len(seq) 
      pour i dans la plage(n-1) : 
          pour j dans la plage(n-1-i) : # La raison pour laquelle n-1 est ici Il faut aussi soustraire i car le plus gros élément de chaque tour de bouillonnement bouillonnera jusqu'à la fin, et il n'est pas nécessaire de comparer 
              si seq[j] > seq[j+1] : 
                  seq[j], seq[j+1] = seq[j+1],seq[j] 


def select_sort(seq): 
    peut être considéré comme une amélioration du bullage. A chaque fois, un élément minimum se retrouve à échanger. Seul l'échange est requis à chaque tour. Une fois """ 
    n = len(seq) 
    pour i dans range(n-1) : 
        min_idx = i # suppose que le ième élément est le plus petit 
        pour j dans range(i+1, n) : 
            si seq [j] < seq [min_idx]: # trouver l'index de l'élément minist 
                min_idx = j 
        if min_idx != i: # swap 
            seq[i], seq[min_idx] = seq[min_idx], seq[i] 


def insertion_sort(seq) : 
    """ each Sélectionnez l'élément suivant et insérez-le dans le tableau trié. Initialement, le tableau trié n'a qu'un seul élément """ n = len( 
    seq) 
    pour i dans range(1, n) : 
        value = seq[i ] # sauvegarde la valeur à positionner
        # trouver la position où la valeur correspond à la partie ordonnée de la liste 
        pos = i 
        tandis que pos > 0 et value < seq[pos-1] : 
            # Décaler les éléments vers la droite pendant la recherche 
            seq[pos] = seq[pos- 1] 
            pos -= 1 
        seq[pos] = value 


def merge_sorted_list(listA, listB): 
    """ 归并两个有序数组 """ 
    new_list = list() 
    a = b = 0 
    while a < len(listA) et b < len(listB) : 
        si listA[a] < listB[b] : 
            new_list.append(listA[a]) 
            a += 1 
        else : 
            new_list.append(listB[b]) 
            b += 1 

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

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

    return new_list

Chapitre 6 : Structure liée

        La liste est la structure de données la plus couramment utilisée, mais l'efficacité de la liste sera très faible lors de l'ajout ou de la soustraction d'éléments au milieu. À ce stade, la liste chaînée sera plus appropriée. L'inconvénient est que la complexité temporelle moyenne d'obtention des éléments devient Sur)

# 单链表实现
class ListNode : 
    def __init__(self, data) : 
        self.data = data 
        self.next = Aucun 


def travsersal(head, callback) : 
    curNode = head 
    alors que curNode n'est pas Aucun : 
        callback(curNode.data) 
        curNode = curNode.next 


def unorderdSearch(head, target): 
    curNode = head 
    while curNode n'est pas None et curNode.data != target: 
        curNode = curNode.next 
    return curNode is not None 


# Étant donné le pointeur de tête, ajoutez un élément à un lien non trié liste. 
def prepend (head, item): 
    newNode = ListNode (item) 
    newNode.next = head 
    head = newNode


# Étant donné la référence head, supprimez une cible d'une liste chaînée 
def remove(head, target): 
    predNode = None 
    curNode = head 
    while curNode n'est pas None et curNode.data != target: 
        # 寻找目标
        predNode = curNode 
        curNode = curNode. data 
    si curNode n'est pas None : 
        si curNode est head : 
            head = curNode.next 
        sinon : 
            predNode.next = curNode.next

Chapitre 7 : Piles

        La pile est également une structure de données couramment utilisée dans les ordinateurs. La pile est une structure de données dernier entré, premier sorti. Cela peut être compris comme le fait de mettre des plaques dans un seau. Celle mise en premier sera pressée contre le sol. Lorsque vous prenez l'assiette, la dernière sera posée et sera retirée en premier.

class Stack : 
    """ Stack ADT, en utilisant une liste python 
    Stack() 
    isEmpty() 
    length() 
    pop() : assert non vide 
    peek() : assert non vide, renvoie le haut de la pile non vide sans la supprimer 
    push(item ) 
    """ 
    def __init__(self) : 
        self._items = list() 

    def isEmpty(self) : 
        return len(self) == 0 

    def __len__(self) : 
        return len(self._items) 

    def peek(self) : 
        assert not self.isEmpty() 
        return self._items[-1] 

    def pop(self) : 
        assert not self.isEmpty() 
        return self._items.pop()

    def push(self, item) : 
        self._items.append(item) 


class Stack : 
    """ Stack ADT, utiliser la liste chaînée 
    Il est très simple à implémenter en utilisant la liste, mais si un grand nombre d'opérations push sont impliquées, la complexité se dégradera en O(n) 
    et la liste chaînée peut garantir qu'elle est toujours O(1) dans le pire des cas 
    """ 
    def __init__(self): 
        self._top = None # top node, _StackNode ou None 
        self._size = 0 # int 

    def isEmpty( self) : 
        return self._top is None 

    def __len__(self) : 
        return self._size 

    def peek(self) : 
        assert not self.isEmpty() 
        return self._top.item 

    def pop(self) : 
        assert pas self.isEmpty( ) 
        nœud = self._top
        self.top = self._top.next 
        self._size -= 1 
        return node.item 

    def _push(self, item): 
        self._top = _StackNode(item, self._top) 
        self._size += 1 


classe _StackNode : 
    def __init__ (soi, élément, lien) : 
        self.item = élément 
        self.next = lien

Chapitre 8 : Files d'attente

Les files d'attente sont également des structures de données couramment utilisées, telles que l'envoi de messages, etc. Celery peut utiliser la liste fournie par Redis pour implémenter des files d'attente de messages. Dans ce chapitre, nous utilisons la liste et la liste chaînée pour implémenter des files d'attente et des files d'attente prioritaires.

class Queue : 
    """ Queue ADT, utilisez list. Implémentation de liste, simple mais la pire efficacité push et pop est O(n) 
    Queue() 
    isEmpty() 
    length() 
    enqueue(item) 
    dequeue() 
    """ 
    def __init__( self) : 
        self._qList = list() 

    def isEmpty(self) : 
        return len(self) == 0 

    def __len__(self) : 
        return len(self._qList) 

    def enquee(self, item) : 
        self._qList.append (item) 

    def dequeue(self): 
        assert not self.isEmpty() 
        return self._qList.pop(0) 


from array import Array #Array implémenté dans le chapitre Array 
Classe ADT File d'attente : 
    """
    Tableau circulaire, implémenté via des pointeurs de tête et de queue. La complexité de l'ajout et du pop intégrés à la liste se dégradera. L'utilisation 
    de l'implémentation d'un tableau en anneau peut rendre la complexité temporelle des opérations de mise en file d'attente et de retrait de la file d'attente O(1). L'inconvénient est que la longueur du tableau doit être corrigée. 
    """ 
    def __init__(self, maxSize) : 
        self._count = 0 
        self._front = 0 
        self._back = maxSize - 1 
        self._qArray = Array(maxSize) 

    def isEmpty(self) : 
        return self._count == 0 

    def isFull(self) : 
        return self._count == len(self._qArray) 

    def __len__(self) : 
        return len(self._count) 

    def enqueue(self, item) : 
        assert not self.isFull() 
        maxSize = len(self ._qArray) 
        self._back = (self._back + 1) % maxSize # Déplacer le pointeur de queue
        self._qArray[self._back] = item 
        self._count += 1 

    def dequeue(self): 
        assert not self.isFull() 
        item = self._qArray[self._front] 
        maxSize = len(self._qArray) 
        self._front = (self._front + 1) % maxSize 
        self._count -= 1 
        return item 

class _QueueNode: 
    def __init__(self, item): 
        self.item = item 


class Queue: 
    """ File d'attente ADT, implémentation de liste chaînée. Afin de améliorer l'environnement Le tableau de types a une limite de nombre maximum, utilisez donc 
    plutôt une liste chaînée avec des nœuds de tête et de queue. 
    """ 
    def __init__(self): 
        self._qhead = Aucun 
        self._qtail = Aucun 
        self._qsize = 0

    def isEmpty(self) : 
        return self._qhead is None 

    def __len__(self) : 
        return self._count 

    def enqueue(self, item) : 
        node = _QueueNode(item) # Créez un nouveau nœud et pointez le nœud de queue vers lui 
        si self .isEmpty (): 
            self._qhead = node 
        else: 
            self._qtail.next = node 
        self._qtail = node 
        self._qcount += 1 

    def dequeue(self): 
        assert not self.isEmpty(), 'Impossible de retirer la file d'attente d'un file d'attente vide ' 
        node = self._qhead 
        si self._qhead est self._qtail : 
            self._qtail = Aucun 
        self._qhead = self._qhead.next # Déplacer le nœud principal vers l'avant
        self._count -= 1 
        renvoie 


la classe node.item UnboundedPriorityQueue : 
    """ PriorityQueue ADT : ajoute la priorité p à chaque élément. La priorité élevée est retirée de la file d'attente en premier. 
    Il existe deux types : 
    - PriorityQueue délimité : limite la priorité à une plage [ 0. ..p) 
    - PriorityQueue illimité : priorité illimitée 

    PriorityQueue() 
    BPriorityQueue(numLevels) : crée une PriorityQueue délimitée avec une priorité dans la plage 
        [0, numLevels-1] 
    isEmpty() 
    length() 
    enqueue(item, priorité) : s'il s'agit d'un PriorityQueue délimité, la priorité doit être dans la plage 
    dequeue() : la priorité la plus élevée est retirée de la file d'attente, et celles avec la même priorité sont dans l'ordre FIFO 

    - deux méthodes d'implémentation : 
    1. Lors de l'entrée dans la file d'attente, il est toujours à la fin de la file d'attente , et l'opération de retrait de la file d'attente est trouvée Retirer la file d'attente avec la priorité la plus élevée, l'opération de retrait de la file d'attente est O(n) 
    2. Maintenez toujours la file d'attente dans l'ordre, trouvez la position d'insertion à chaque fois que vous entrez dans la file d'attente, l'opération de retrait de la file d'attente est O(1)
    (Notez que si vous utilisez list pour implémenter les opérations list.append et pop, la complexité sera dégradée en raison de l'allocation de mémoire) 
    """ 
    from collections import namedtuple 
    _PriorityQEntry =namedtuple('_PriorityQEntry', 'item, priorité') 

    # Utiliser la méthode 1, utilisez la liste intégrée pour implémenter une PriorityQueue illimitée 
    def __init__(self): 
        self._qlist = list() 

    def isEmpty(self): 
        return len(self) == 0 

    def __len__(self): 
        return len(self._qlist ) 

    def enqueue(self, item, priorité) : 
        Entry = UnboundedPriorityQueue._PriorityQEntry(item, priorité) 
        self._qlist.append(entry) 

    def deque(self) : 
        assert not self.isEmpty(), 'ne peut pas être retiré d'un vide file d'attente'
    Étant donné que l'opération de retrait de la file d'attente doit parcourir pour trouver l'élément ayant la priorité la plus élevée, il s'agit en moyenne d'une opération O(n).Cependant, pour BoundedPriorityQueue, l'utilisation d'un tableau de files d'attente peut obtenir un temps constant, en 
    échangeant de l'espace contre du temps. Par exemple, si vous souhaitez faire apparaître un élément, recherchez simplement le premier élément contextuel de file d'attente non vide. 
    (Les petits nombres représentent une priorité élevée et seront retirés de la file d'attente en premier) 
    qlist 
    [0] -> ["white"]



    [1] 
    [2] -> ["noir", "vert"] 
    [3] -> ["violet", "jaune"] 
    """ 
    # Implémentation de l'ADT de file d'attente prioritaire délimitée en utilisant un tableau de # 
    # files d'attente dans dont les files d'attente sont implémentées à l'aide d'une liste chaînée. 
    from array import Array # 第二章定义的ADT 

    def __init__(self, numLevels): 
        self._qSize = 0 
        self._qLevels = Array(numLevels) 
        for i in range(numLevels) : 
            self._qLevels[i] = Queue() # File d'attente de liste chaînée Queue 

    def isEmpty(self): 
        return len(self) == 0 

    def __len__(self): 
        return len(self._qSize) 

    def mettre en file d'attente(soi, élément,priorité):
        assert priorité >= 0 et priorité < len(self._qLevels), 'invalid priorité' 
        self._qLevel[priority].enque(item) # Trouver directement l'emplacement correspondant à la priorité et mettre en file d'attente 

    def deque(self) : 
        assert not self. isEmpty (), 'ne peut pas être retiré d'une file d'attente vide' 
        i = 0 
        p = len(self._qLevels) 
        while i < p et non self._qLevels[i].isEmpty() : # Trouver la première file d'attente non vide 
            i + = 1 
        renvoie self._qLevels[i].dequeue()

Je suppose que tu aimes

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