web-dev-qa-db-ja.com

削除は通常、多くのデータ構造への挿入よりも実装がはるかに難しいのはなぜですか?

多くの(ほとんどの)データ構造の挿入よりも削除の実装が通常非常に難しいという具体的な理由を考えられますか?

簡単な例:リンクリスト。挿入はささいなことですが、削除にはいくつかの特別なケースがあり、非常に難しくなります。 AVLやRed-blackなどの自己バランス型バイナリ検索ツリーは、痛みを伴う削除実装の典型的な例です。

それは、ほとんどの人が考える方法と関係があると言いたいのです。物事を建設的に定義する方が簡単で、簡単に挿入できます。

33
Leo Brito

それは単なる心の状態ではありません。削除が難しい理由には、物理​​的な(つまりデジタル)理由があります。

削除すると、何かがあった場所に穴が残ります。結果のエントロピーの専門用語は "fragmentation。" です。リンクされたリストでは、削除されたノードに「パッチを適用」し、使用しているメモリの割り当てを解除する必要があります。二分木では、ツリーの不均衡を引き起こします。メモリシステムでは、新しく割り当てられたブロックが削除によって残されたブロックよりも大きい場合、メモリがしばらく使用されなくなります。

つまり、挿入する場所を選択できるため、挿入が簡単になります。どのアイテムが削除されるかを事前に予測できないため、削除は困難です。

68
Robert Harvey

挿入するより削除するのが難しい傾向があるのはなぜですか? データ構造は削除よりも挿入を念頭に置いて設計されており、当然のことながらそう設計されています。

これを考慮してください-データ構造から何かを削除するには、そもそもそこにある必要があります。したがって、最初に追加する必要があります。つまり、多くの場合、挿入と同じ数の削除があります。データ構造を挿入用に最適化すると、少なくとも削除用に最適化された場合と同じくらいの利点が得られることが保証されます。

さらに、各要素を順次削除するのにどのような用途がありますか? (おそらく新しい関数を作成するだけで)一度にすべてをクリアする関数を呼び出すだけではどうですか?また、データ構造は、実際に何かが含まれている場合に最も役立ちます。したがって、実際には、挿入と同じ数の削除があるケースはあまり一般的ではありません。

何かを最適化するときは、それが最もよく行い、最も時間がかかることを最適化する必要があります。通常の使用法では、データ構造の要素の削除は挿入よりも頻繁に行われます。

35
Rob Watts

それは難しくありません。

二重にリンクされたリストを使用すると、挿入時にメモリが割り当てられ、ヘッドまたは前のノードとリンクし、テールまたは次のノードとリンクします。削除すると、まったく同じものからリンクが解除され、メモリが解放されます。これらの操作はすべて対称です。

これは、どちらの場合も挿入/削除するノードがあることを前提としています。 (そして、挿入の場合、前に挿入するノードもあるので、ある意味で、挿入は少し複雑であると考えることができます。)削除するノードではなく、- payloadノードの場合、もちろん最初にリストでペイロードを検索する必要がありますが、これは削除の欠点ではありませんか?

バランスの取れたツリーでも同じことが当てはまります。通常、ツリーは挿入直後と削除直後のバランスをとる必要があります。バランスルーチンを1つだけ試し、挿入か削除かに関係なく、各操作の後に適用することをお勧めします。常にツリーのバランスを維持する挿入と、ツリーのバランスを常に維持する削除を実装しようとしている場合、2つが同じバランスルーチンを共有する必要はなく、不必要に人生を複雑にしています。

要するに、どちらか一方がもう一方よりも硬いはずである理由はありません。もしそうであるとわかっているのなら、あなたが考えることはより自然であると思うという(非常に人間的な)傾向の犠牲者である可能性がありますつまり、必要以上に複雑な方法で削除を実装している可能性があります。しかし、それは人間の問題です。数学的な観点からは、問題はありません。

6
Mike Nakis

ランタイムに関して、ウィキペディアの データ構造操作時間の複雑さの比較 を見ると、挿入操作と削除操作は同じ複雑さを持っていることに注意してください。そこにプロファイルされた削除操作は、削除する構造要素への参照があるインデックスによる削除です。挿入はアイテムごとです。実際の削除の実行時間が長くなるのは、通常、インデックスではなく削除するアイテムがあるため、検索操作も必要になるためです。テーブル内のほとんどのデータ構造では、挿入位置をアイテムに依存しないか、挿入中に位置が暗黙的に決定されるため、追加の検索を挿入する必要はありません。

認知の複雑さに関しては、質問に答えがあります:エッジケース。削除は、挿入よりもそれらの数が多い場合があります(これは一般的なケースではまだ確立されていません)。ただし、これらのEdgeケースの少なくとも一部は、特定の設計で回避できます(たとえば、リンクリストにセンチネルノードがある)。

3
outis

前述のすべての問題に加えて、データ参照の整合性が関係しています。 SQLのデータベースのようなデータ構造を適切に構築するには、Oracleの参照整合性が非常に重要です。
発明したさまざまなものを誤って破壊しないようにするため。
たとえば、削除のカスケードは、削除しようとしたものを削除するだけでなく、関連データのクリーンアップもトリガーします。
これにより、ジャンクデータからデータベースがクリーンアップされ、データの整合性が損なわれません。
たとえば、2番目のテーブルの関連レコードとして、親と種類のテーブルがあります。
親はメインテーブルです。参照整合性が強化されていない場合、任意のテーブルのレコードを削除できます。子テーブルにデータがあり、親テーブルには何もないため、後で完全なファミリー情報を取得する方法がわかりません。
そのため、参照整合性チェックでは、子テーブルのレコードがクリーンアップされるまで、親テーブルからレコードを削除できません。
そのため、ほとんどのデータソースでは、データを削除することがより困難です。

0
Alex