it-swarm.com.de

Warum ist das Löschen in der Regel viel schwieriger zu implementieren als das Einfügen in viele Datenstrukturen?

Können Sie sich einen bestimmten Grund vorstellen, warum das Löschen für viele (die meisten?) Datenstrukturen in der Regel 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 schwieriger machen. 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 ist für uns einfacher, Dinge konstruktiv zu definieren, was zu einfachen Einfügungen führt.

33
Leo Brito

Es ist mehr als nur ein Geisteszustand; Es gibt physische (d. h. 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 "umflicken" und den verwendeten Speicher freigeben. 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 durch das Löschen zurückgelassenen 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 werden soll.

68
Robert Harvey

Warum ist das Löschen schwieriger als das Einfügen? Datenstrukturen werden zu Recht eher für das Einfügen als für das Löschen entworfen.

Bedenken Sie Folgendes: Um etwas aus einer Datenstruktur zu löschen, muss es zunächst vorhanden sein. Sie müssen es also zuerst hinzufügen, was bedeutet, dass Sie höchstens so viele Löschungen haben wie Einfügungen. Wenn Sie eine Datenstruktur für das Einfügen optimieren, erhalten Sie garantiert mindestens so viel Nutzen, als ob sie für das Löschen optimiert worden wäre.

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 durch einfaches Erstellen einer neuen)? Datenstrukturen sind auch dann am nützlichsten, wenn sie tatsächlich etwas enthalten. Der Fall, dass so viele Löschungen wie Einfügungen vorgenommen werden, wird in der Praxis daher nicht sehr häufig sein.

Wenn Sie etwas optimieren, möchten Sie die Dinge optimieren, die am meisten funktionieren und die am meisten Zeit in Anspruch nehmen. Bei normaler Verwendung erfolgt das Löschen von Elementen einer Datenstruktur seltener als das Einfügen.

35
Rob Watts

Es ist nicht schwieriger.

Bei doppelt verknüpften Listen wird beim Einfügen Speicher zugewiesen, und dann wird entweder mit dem Kopf oder dem vorherigen Knoten und entweder mit dem Ende oder dem nächsten Knoten verknüpft. Wenn Sie löschen, werden Sie die Verknüpfung von genau derselben trennen und dann Speicher freigeben. Alle diese Operationen sind symmetrisch.

Dies setzt voraus, dass Sie in beiden Fällen den Knoten zum Einfügen/Löschen haben. (Und im Fall 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, haben Sie nicht den zu löschenden Knoten, sondern den - Nutzlast des Knotens, dann müssen Sie natürlich zuerst die Liste nach der Nutzlast durchsuchen, aber das ist kein Mangel an Löschung, oder?

Bei ausgeglichenen Bäumen gilt das Gleiche: Ein Baum muss in der Regel unmittelbar nach dem Einfügen und auch unmittelbar nach dem Löschen ausgeglichen werden. Es ist eine gute Idee, nur eine Ausgleichsroutine zu verwenden und diese nach jeder Operation 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 ausgeglichen bleibt, und eine Löschung, bei der der Baum immer ausgeglichen bleibt, ohne dass beide dieselbe Ausgleichsroutine verwenden, erschweren Sie Ihr Leben unnötig.

Kurz gesagt, es gibt keinen Grund, warum einer schwieriger sein sollte als der andere, und wenn Sie feststellen, dass dies der Fall ist, ist es tatsächlich möglich, dass Sie ein Opfer der (sehr menschlichen) Tendenz sind, das Denken natürlicher zu finden 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.

6
Mike Nakis

Beachten Sie in Bezug auf die Laufzeit, wenn Sie sich Datenstrukturoperationen, Zeitkomplexitätsvergleich in Wikipedia ansehen, dass die Einfüge- und Löschoperationen dieselbe Komplexität haben. Der dort profilierte Löschvorgang wird nach Index gelöscht, wobei Sie einen Verweis auf das zu löschende Strukturelement haben. Das Einfügen erfolgt nach Artikel. Die längere Laufzeit zum Löschen in der Praxis ist darauf zurückzuführen, dass Sie normalerweise ein zu löschendes Element und nicht dessen Index haben. Daher benötigen Sie auch eine Suchoperation. 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 in der Frage: Randfälle. Das Löschen kann mehr davon als das Einfügen haben (dies muss im allgemeinen Fall noch festgestellt werden). Zumindest einige dieser Edge-Fälle können jedoch in bestimmten Designs vermieden werden (z. B. mit einem Sentinel-Knoten in einer verknüpften Liste).

3
outis

Zusätzlich zu allen genannten Problemen gibt es eine datenreferenzielle Integrität. Für die ordnungsgemäße Erstellung von Datenstrukturen wie Datenbanken in SQL ist die referenzielle Integrität von Oracle sehr wichtig.
Um sicherzustellen, dass Sie es nicht versehentlich zerstören, werden viele verschiedene Dinge erfunden.
Zum Beispiel eine Kaskade beim Löschen, die nicht nur löscht, was auch immer Sie löschen möchten, sondern auch die Bereinigung verwandter Daten auslöst.
Diese Datenbank bereinigt Junk-Daten und behält die Integrität der Daten bei.
Zum Beispiel haben Sie Tabellen mit Eltern und Arten als zugehörige Datensätze in der zweiten Tabelle.
Wo Eltern Haupttabelle ist. Wenn Sie keine verstärkte referenzielle Integrität haben, können Sie alle Datensätze in einer beliebigen Tabelle löschen. Später wissen Sie nicht, wie Sie vollständige 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 Datensätze erst dann aus der übergeordneten Tabelle löschen, wenn die Datensätze aus der untergeordneten Tabelle bereinigt wurden.
Und deshalb ist es in den meisten Datenquellen schwieriger, Daten zu löschen.

0
Alex