Können Sie sich einen bestimmten Grund vorstellen, warum das Löschen in der Regel für viele (die meisten?) Datenstrukturen erheblich schwieriger zu implementieren ist als das Einfügen?
Kurzes Beispiel: Verknüpfte Listen. Das Einfügen ist trivial, aber das Löschen hat einige Sonderfälle, die es erheblich erschweren. Selbstausgleichende binäre Suchbäume wie AVL und Rot-Schwarz sind klassische Beispiele für schmerzhafte Löschimplementierungen.
Ich möchte sagen, dass es mit der Art und Weise zu tun hat, wie die meisten Leute denken: Es fällt uns leichter, Dinge konstruktiv zu definieren, was zu einfachen Einfügungen führt.
algorithms
data-structures
Leo Brito
quelle
quelle
pop
ist mitextract-min
?Antworten:
Es ist mehr als nur ein Geisteszustand; Es gibt physikalische (dh digitale) Gründe, warum das Löschen schwieriger ist.
Wenn Sie löschen, hinterlassen Sie ein Loch, in dem sich früher etwas befand. Der Fachbegriff für die resultierende Entropie lautet "Fragmentierung". In einer verknüpften Liste müssen Sie den entfernten Knoten "patchen" und die Zuordnung des verwendeten Speichers aufheben. In binären Bäumen führt dies zu einem Ungleichgewicht des Baums. In Speichersystemen wird der Speicher für eine Weile nicht verwendet, wenn neu zugewiesene Blöcke größer sind als die beim Löschen verbleibenden Blöcke.
Kurz gesagt, das Einfügen ist einfacher, da Sie auswählen können, wo Sie einfügen möchten. Das Löschen ist schwieriger, da Sie nicht im Voraus vorhersagen können, welches Element gelöscht wird.
quelle
Warum ist das Löschen in der Regel schwieriger als das Einfügen? Datenstrukturen werden eher mit dem Gedanken an das Einfügen als an das Löschen entworfen, und das zu Recht.
Bedenken Sie Folgendes: Um etwas aus einer Datenstruktur zu löschen, muss es an erster Stelle vorhanden sein. Sie müssen es also zuerst hinzufügen, was bedeutet, dass Sie höchstens so viele Löschungen haben, wie Sie Einfügungen haben. Wenn Sie eine Datenstruktur für das Einfügen optimieren, erhalten Sie garantiert mindestens den gleichen Nutzen, als wäre sie für das Löschen optimiert worden.
Was nützt es außerdem, jedes Element nacheinander zu löschen? Warum nicht einfach eine Funktion aufrufen, die alles auf einmal löscht (möglicherweise indem Sie einfach eine neue erstellen)? Datenstrukturen sind auch dann am nützlichsten, wenn sie tatsächlich etwas enthalten. Der Fall, dass so viele Deletionen wie Insertionen vorliegen, wird in der Praxis nicht sehr häufig sein.
Wenn Sie etwas optimieren, möchten Sie die Dinge optimieren, die es am meisten tut und die die meiste Zeit in Anspruch nehmen. Im normalen Gebrauch kommt das Löschen von Elementen einer Datenstruktur seltener vor als das Einfügen.
quelle
k
ziemlich schnell eine Reihe von Elementen hinzufügen : Sortiereingabe umkehren und mit vorhandenem Vektor zusammenführen -O(k log k + n)
. Dann haben Sie eine Struktur mit ziemlich kompliziertem Einfügen, aber das Aufwenden von oberenu
Elementen ist trivial und schnell. Nehmen Sie einfach das letzteu
und verschieben Sie das Ende des Vektors. Aber wenn jemand so etwas braucht, werde ich verdammt sein. Ich hoffe, das stärkt zumindest Ihre Argumentation.Es ist nicht schwerer.
Bei doppelt verknüpften Listen ordnen Sie beim Einfügen Speicher zu und verknüpfen dann entweder mit dem Kopf oder dem vorherigen Knoten und entweder mit dem Ende oder dem nächsten Knoten. Wenn Sie löschen, wird die Verknüpfung zu genau derselben Person aufgehoben und Speicher freigegeben. Alle diese Operationen sind symmetrisch.
Dies setzt voraus, dass Sie in beiden Fällen den Knoten zum Einfügen / Löschen haben. (Und im Falle des Einfügens, dass Sie auch den Knoten vor dem Einfügen haben, könnte das Einfügen in gewisser Weise als etwas komplizierter angesehen werden.) Wenn Sie versuchen, zu löschen, müssen Sie nicht den Knoten löschen, sondern die Nutzdaten des Knotens müssen Sie dann natürlich zuerst die Liste nach der Nutzlast durchsuchen, aber das ist kein Mangel an Löschung, oder?
Bei ausgeglichenen Bäumen gilt dasselbe: Ein Baum muss in der Regel unmittelbar nach dem Einfügen und auch unmittelbar nach dem Löschen ausgeglichen werden. Es empfiehlt sich, nur eine Auswuchtroutine zu verwenden und diese nach jedem Vorgang anzuwenden, unabhängig davon, ob es sich um eine Einfügung oder eine Löschung handelt. Wenn Sie versuchen, eine Einfügung zu implementieren, bei der der Baum immer im Gleichgewicht bleibt, und eine Löschung, bei der der Baum immer im Gleichgewicht bleibt, ohne dass beide dieselbe Abgleichsroutine verwenden, verkomplizieren Sie unnötigerweise Ihr Leben.
Kurz gesagt, es gibt keinen Grund, warum das eine schwerer sein sollte als das andere, und wenn Sie dies feststellen, ist es in der Tat möglich, dass Sie der (sehr menschlichen) Tendenz zum natürlichen Denken zum Opfer fallen Konstruktiv als subtraktiv, was bedeutet, dass Sie das Löschen möglicherweise komplizierter implementieren, als es sein muss. Aber das ist ein menschliches Problem. Aus mathematischer Sicht gibt es kein Problem.
quelle
Beachten Sie, dass die Einfüge- und Löschoperationen in Bezug auf die Laufzeit im Vergleich zur Zeitkomplexität der Datenstrukturoperationen in Wikipedia dieselbe Komplexität aufweisen. Die dort hinterlegte Löschoperation ist Löschen nach Index, wobei Sie einen Verweis auf das zu löschende Strukturelement haben; Das Einfügen erfolgt nach Artikel. Die längere Laufzeit für das Löschen in der Praxis liegt darin, dass Sie normalerweise ein Element löschen müssen und nicht dessen Index, sodass Sie auch eine Suchoperation benötigen. Die meisten Datenstrukturen in der Tabelle erfordern keine zusätzliche Suche für eine Einfügung, da die Platzierungsposition nicht vom Element abhängt oder die Position implizit während der Einfügung bestimmt wird.
In Bezug auf die kognitive Komplexität gibt es eine Antwort auf die Frage: Randfälle. Das Löschen kann mehr von ihnen als das Einfügen haben (dies muss im allgemeinen Fall noch festgestellt werden). Zumindest einige dieser Randfälle können jedoch in bestimmten Designs vermieden werden (z. B. mit einem Sentinel-Knoten in einer verknüpften Liste).
quelle
Zu allen genannten Problemen kommt noch die referenzielle Datenintegrität hinzu. Für die Erstellung einer Datenstruktur wie Datenbanken in SQL ist die referenzielle Integrität von Oracle sehr wichtig.
Um sicherzustellen, dass Sie es nicht versehentlich zerstören, wurden viele verschiedene Dinge erfunden.
Zum Beispiel Kaskade beim Löschen, die nicht nur löscht, was auch immer Sie versuchen, zu löschen, sondern auch die Bereinigung von verwandten Daten auslöst.
Diese bereinigen Datenbank von Junk-Daten sowie Integrität der Daten intakt zu halten.
Zum Beispiel haben Sie Tabellen mit Eltern und Arten als zugehörige Datensätze in der zweiten Tabelle.
Wo Eltern ist Haupttabelle. Wenn Sie keine verstärkte referenzielle Integrität haben, können Sie alle Datensätze in jeder Tabelle löschen, und später wissen Sie nicht, wie Sie die vollständigen Familieninformationen abrufen können, da Sie Daten in der untergeordneten Tabelle und nichts in der übergeordneten Tabelle haben.
Aus diesem Grund können Sie bei der Überprüfung der referenziellen Integrität keine Datensätze aus der übergeordneten Tabelle löschen, bis die Datensätze aus der untergeordneten Tabelle bereinigt wurden.
Aus diesem Grund ist es in den meisten Datenquellen schwieriger, Daten zu löschen.
quelle