Verwenden Sie Python, um grundlegende Datenstrukturen zu implementieren [01/4]

veranschaulichen

        Wenn Sie dieses Wissen nutzen müssen, es aber nicht haben, ist das frustrierend und kann zur Ablehnung des Vorstellungsgesprächs führen. Unabhängig davon, ob Sie ein paar Tage mit „Blitzen“ verbringen oder fragmentierte Zeit zum Weiterlernen nutzen, lohnt es sich, an der Datenstruktur zu arbeiten. Welche Datenstrukturen gibt es also in Python? Listen, Wörterbücher, Mengen und ... Stapel? Hat Python einen Stack? Diese Artikelserie enthält detaillierte Puzzleteile.
 

Kapitel 1: Abstrakter ADT-Datentyp, Definition von Daten und ihren Operationen

Was ist ADT: Abstrakter Datentyp? Jeder, der Datenstrukturen studiert hat, sollte es wissen.

So wählen Sie eine Datenstruktur für ADT aus

  1. Erfüllt die Datenstruktur die von der ADT-Domäne angegebenen Speicheranforderungen?
  2. Bieten die Datenstrukturen den Datenzugriff und die Datenbearbeitungsmöglichkeiten, um ADT vollständig zu implementieren?
  3. Effiziente Ausführung? Basierend auf Komplexitätsanalyse.

        Der folgende Code ist ein einfaches Beispiel. Um beispielsweise eine einfache Bag-Klasse zu implementieren, definieren wir zunächst deren Operationen und verwenden dann die magischen Methoden der Klasse, um diese Methoden zu implementieren:

Klasse Bag: 
    „““ 
    Konstruktor: 
    Größe 
    enthält 
    Append 
    Remove 
    Iter 
    „““ 
    def __init__(self): 
        self._items = list() 

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

    def __contains__(self, item ): 
        Artikel in self._items zurückgeben 

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

    def Remove(self, item): 
        Artikel in self._items bestätigen, „Artikel muss in der Tasche“ 
        zurückgeben self._items .remove(item) 

    def __iter__(self): 
        return _BagIterator(self._items) 


class _BagIterator:_items) 
    """ Beachten Sie, dass die Iterator-Klasse hier implementiert ist"""
    def __init__(self, seq): 
        self._bag_items = seq 
        self._cur_item = 0 

    def __iter__(self): 
        return self 

    def __next__(self): 
        if self._cur_item < len(self._bag_items): 
            item = self._bag_items[ self._cur_item] 
            self._cur_item += 1 
            Rückgabeelement 
        sonst: 
            raise StopIteration 


b = Bag() 
b.add(1) 
b.add(2) 
for i in b: # for使用__iter__构建,用__next__迭代
    print(i) 


""" 
# for 语句等价于 
i = b.__iter__() 
while True: 
    Versuchen Sie:
        item = i.__next__() 
        print(item) 
    außer StopIteration: 
        break
„““

Kapitel 2: Array und Liste

        Array: feste Länge, begrenzte Operationen, spart aber Speicher; es scheint, dass ich es in meiner Karriere noch nie verwendet habe, aber ich habe es in Python3.5 ausprobiert und es verfügt über eine Array-Klasse, die direkt mit „Import Array“ importiert werden kann

        list: reserviert im Voraus Speicher und verfügt über umfangreiche Vorgänge, verbraucht jedoch Speicher. Ich habe Experimente mit sys.getsizeof durchgeführt. Mein persönliches Verständnis ist, dass es dem Vektor in C++ STL sehr ähnlich ist, der am häufigsten verwendeten Datenstruktur.

  • list.append: Wenn zuvor nicht genügend Speicher zugewiesen wurde, wird ein neuer Bereich erneut geöffnet, und dann werden die vorherigen Daten kopiert und die Komplexität verringert.
  • list.insert: verschiebt alle Elemente nach dem eingefügten Bereich, O(n)
  • list.pop: Unterschiedliche Positionen von Pop erfordern unterschiedliche Komplexität. Pop (0) hat eine Komplexität von O (1) und die erste Position von Pop () hat eine Komplexität von O (n).
  • list[]: Slice-Operation kopiert Daten (Speicherplatz reservieren) in eine andere Liste

So implementieren Sie ein ADT-Array:

ctypes-Klasse importieren 

Array: 
    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): 
        bestätige Index >= 0 und index < len(self), 'out of range' 
        return self._elements[index] 

    def __setitem__(self, index , Wert): 
        Behauptung Index >= 0 und Index < len(self), 'out of range' 
        self._elements[index] = value 

    def clear(self, value):
        „““ Setzen Sie jedes Element auf den Wert „““
        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): 
        if self._idex < len(self._items): 
            val = self._items[self._idx] 
            self._idex += 1 
            return val 
        else: 
            raise StopIteration

2.1 Zweidimensionale Arrays

class Array2D: 
    „““ Neues 
    Array2D(nrows, ncols): Konstruktor 
    numRows() 
    numCols() 
    clear(value) 
    getitem(i, j) 
    setitem(i, j, val) 
    „““ 
    def __init__(self, numrows, numcols): 
        self._the_rows = Array(numrows) # Beispiel 
        für i in range(numrows): 
            self._the_rows[i] = Array(numcols) 

    @property 
    def numRows(self): 
        return len(self._the_rows ) 

    @property 
    def NumCols(self): 
        return len(self._the_rows[0]) 

    def clear(self, value):  
        für Zeile in self._the_rows:
            row.clear(value)
 
    def __getitem__(self, ndx_tuple): # ndx_tuple: (x, y) 
        Assert len(ndx_tuple) == 2 
        row, col = ndx_tuple[0], ndx_tuple[1] 
        Assert (row >= 0 and row < self.numRows and 
                col >= 0 and col < self.NumCols) 

        the_1d_array = self._the_rows[row] 
        return the_1d_array[col] 

    def __setitem__(self, ndx_tuple, value): 
        Assert len(ndx_tuple) == 2 
        row, col = ndx_tuple[0], ndx_tuple[1] 
        affirm (row >= 0 and row < self.numRows and 
                col >= 0 and col < self.NumCols) 
        the_1d_array = self._the_rows[row] 
        the_1d_array[col] = value

2.2 Die Matrix ADT, m Zeilen, n Spalten. Es ist am besten, Pandas zum Verarbeiten der Matrix zu verwenden. Es ist schmerzhafter, sie selbst zu implementieren.

Klassenmatrix: 
    „““ 最好用pandas的DataFrame 
    Matrix(rows, ncols): Konstruktor 
    numCols() 
    getitem(row, col) 
    setitem(row, col, val) 
    scaleBy(scalar): 每个元素乘scalar 
    transpose() : Transpose hinzufügen 
    add(rhsMatrix): size must be the same 
    subtract(rhsMatrix) 
    multiply(rhsMatrix) 
    """ 
    def __init__(self, numRows, numCols): 
        self._theGrid = Array2D(numRows, numCols) 
        self._theGrid. clear(0) 

    @property 
    def numRows(self): 
        return self._theGrid.numRows 

    @property 
    def NumCols(self): 
        return self._theGrid.numCols

    def __getitem__(self, ndxTuple): 
        return self._theGrid[ndxTuple[0], ndxTuple[1]] 

    def __setitem__(self, ndxTuple, scalar): 
        self._theGrid[ndxTuple[0], ndxTuple[1]] = Skalar 

    def scaleBy(self, scalar): 
        für r in range(self.numRows): 
            für c in range(self.numCols): 
                self[r, c] *= scalar 

    def __add__(self, rhsMatrix): 
        Assert (rhsMatrix.numRows = = self.numRows und 
                rhsMatrix.numCols == self.numCols) 
        newMartrix = Matrix(self.numRows, self.numCols) 
        für r im Bereich(self.numRows): 
            für c im Bereich(self.numCols):
                newMartrix[r, c] = self[r, c] + rhsMatrix[r, c]

Kapitel 3: Mengen und Karten

Neben der Liste sind wahrscheinlich die in Python integrierten Sets und Diktate die am häufigsten verwendeten.

3.1 legt ADT fest

Eine Sammlung ist ein Container, der eine Sammlung eindeutiger Werte in einer bestimmten vergleichbaren Domäne speichert, wobei die Werte in keiner bestimmten Reihenfolge gespeichert werden.

class Set: 
    „““ 使用list实现set ADT 
    Set() 
    length() 
    enthält(Element) 
    add(Element) 
    Remove(Element) 
    equal(Element) 
    isSubsetOf(setB) 
    Union(setB) 
    intersect(setB) 
    Differenz(setB) 
    Iterator () 
    """ 
    def __init__(self): 
        self._theElements = list() 

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

    def __contains__(self, element): 
        return element in self._theElements 

    def add(self, element): 
        wenn Element nicht in self: 
            self._theElements.append(element)

    def remove(self, element): 
        Element in self bestätigen, „Das Element muss gesetzt werden“ 
        self._theElements.remove(element) 

    def __eq__(self, setB): 
        if len(self) != len(setB): 
            false zurückgeben 
        sonst: 
            return self.isSubsetOf(setB) 

    def isSubsetOf(self, setB): 
        für Element in self: 
            wenn Element nicht in setB: 
                return False 
        return True 

    def union(self, setB): 
        newSet = Set() 
        newSet._theElements.extend (self._theElements) 
        für Element in setB: 
            wenn Element nicht in self:
                newSet._theElements.append(element) 
        gibt newSet zurück

3.2 Maps oder Dict: Schlüssel-Wert-Paare, intern von Python mithilfe von Hash implementiert.

Klasse Map: 
    „““ Map ADT-Listenimplementierung 
    Map() 
    length() 
    contains(key) 
    add(key, value) 
    remove(key) 
    valudOf(key) 
    iterator() 
    „““ 
    def __init__(self): 
        self._entryList = list() 

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

    def __contains__(self, key): 
        ndx = self._findPosition(key) 
        return ndx is not None 

    def add(self, key, value): 
        ndx = self ._findPosition(key) 
        wenn ndx nicht None ist: 
            self._entryList[ndx].value = value 
            return False
        sonst: 
            Eintrag = _MapEntry(Schlüssel, Wert) 
            self._entryList.append(Eintrag) 
            gibt True zurück 

    def valueOf(selbst, Schlüssel): 
        ndx = self._findPosition(Schlüssel) 
        behaupten, ndx ist nicht None, „Ungültiger Kartenschlüssel“ 
        gibt self zurück. _entryList[ndx].value 

    def remove(self, key): 
        ndx = self._findPosition(key) 
        affirm ndx is not None, 'Invalid map key' 
        self._entryList.pop(ndx) 

    def __iter__(self): 
        return _MapIterator( self._entryList) 

    def _findPosition(self, key): 
        for i in range(len(self)): 
            if self._entryList[i].key == key:
                return i 
        return None 


class _MapEntry: # oder usecollections.namedtuple('_MapEntry', 'key,value') 
    def __init__(self, key, value): 
        self.key = key 
        self.value = value

3.3 Das multiArray ADT, ein mehrdimensionales Array, wird im Allgemeinen unter Verwendung eines eindimensionalen Arrays simuliert, und dann werden die Elemente durch Berechnen des Indexes erhalten

Klasse MultiArray: 
    „““ Zeilen-Haupt- oder Spalten-Hauptreihenfolge, dies ist Zeilen-Hauptreihenfolge 
    MultiArray(d1, d2, ...dn) 
    dims(): die Anzahl der Dimensionen 
    length(dim): die Länge des gegebenen Arrays Dimension 
    klar(Wert) 
    getitem(i1, i2, ... in), Index(i1,i2,i3) = i1*(d2*d3) + i2*d3 + i3 
    setitem(i1, i2, ... in) 
    Beschreibung: index(i1,i2,...in) = i1*f1 + i2*f2 + ... + i(n-1)*f(n-1) + in*1 """ 
    def 
    __init__ (self, *dimensions): 
        # Implementierung von MultiArray ADT unter Verwendung eines 1-D #-Arrays, Sie können dies auch 
        tun.。assessieren Sie len(dimensions) > 1, 'Das Array muss 2 oder mehr Dimensionen haben' 
        self._dims = Maße
        # Berechnen Sie die Gesamtzahl der Elemente im Array 
        size = 1 
        für d in den Dimensionen: 
            Assert d > 0, 'Dimensions must be > 0' 
            size *= d 
        # Erstellen Sie das 1-D-Array zum Speichern der Elemente 
        self._elements = Array (size) 
        # Erstellen Sie ein 1-D-Array zum Speichern der Gleichungsfaktoren 
        self._factors = Array(len(dimensions)) 
        self._computeFactors() 

    @property 
    def numDims(self): 
        return len(self._dims) 

    def length(self , dim): 
        bestätige dim > 0 und dim < len(self._dims), „Dimensionskomponente außerhalb des Bereichs“ 
        gibt self._dims[dim-1] zurück

    def clear(self, value): 
        self._elements.clear(value) 

    def __getitem__(self, ndxTuple): 
        Assert len(ndxTuple) == self.numDims, 'Invalid # of array subscripts' 
        index = self._computeIndex(ndxTuple) 
        Der Assert-Index ist nicht None, „Array-Index außerhalb des Bereichs“. 
        return self._elements[index] 

    def __setitem__(self, ndxTuple, value): 
        Assert len(ndxTuple) == self.numDims, „Ungültige Anzahl der Array-Subskripte“ 
        index = self._computeIndex(ndxTuple) 
        behauptet, Index sei nicht None, „Array-Index außerhalb des Bereichs“ 
        self._elements[index] = value 

    def _computeIndex(self, ndxTuple):
        # unter Verwendung der Gleichung: i1*f1 + i2*f2 + ... + in*fn 
        offset = 0 
        für j in range(len(ndxTuple)): 
            wenn ndxTuple[j] < 0 oder ndxTuple[j] >= self. _dims[j]: 
                return None 
            else: 
                offset += ndexTuple[j] * self._factors[j] 
        return offset

Teil 4: Algorithmusanalyse

Die Big-O-Notation wird im Allgemeinen verwendet, um die durchschnittliche Zeitkomplexität des Algorithmus zu messen: 1 < log(n) < n < nlog(n) < n^2 < n^3 < a^n. Das Verständnis der durchschnittlichen zeitlichen Komplexität gängiger Datenstrukturoperationen ist hilfreich, um effizientere Datenstrukturen zu verwenden. Natürlich muss sie manchmal zeitlich und räumlich gemessen werden, und einige Operationen können sich sogar verschlechtern, wie z. B. die Anhängeoperation der Liste. Wenn Der Listenplatz reicht nicht aus, wird neuen Platz eröffnen, die Operationskomplexität verringert sich auf O(n) und manchmal ist es notwendig, eine amortisierte Analyse (amortisiert) zu verwenden.

Ich denke du magst

Origin blog.csdn.net/gongdiwudu/article/details/132787294
Empfohlen
Rangfolge