配列の代わりにリンクリストを使用するための具体的なルールは何ですか?


18

リンクリストは、要素の安易な挿入と削除が必要な場合、および要素がメモリ内で隣接していないことが重要でない場合に使用できます。

これは非常に抽象的であり、配列ではなくリンクリストを使用する理由を具体的に説明したいと思います。私はプログラミングの経験があまりないので、実際の経験はあまりありません。


3
正直なところ、何かを書いた経験があり、データ構造の変更がコードに与える影響を確認するまで、例があなたにとってそれほど意味があるとは思いません。興味のあるものを書いて、どのデータ構造とコンテナが最適かを調べるか、既存のコードを調べて、各コンテナが選択された理由と、それが変更する効果を考えてください。
役に立たない

ここで合理的であるよりもはるかに長い形式の実例なしに、データ構造選択のトレードオフと副作用を(経験の浅い)OPに伝えることは有益だとは思わない。回答として与えられた例は問題なく、質問に答えられますが、実際に理解するための暗黙の要求ではありません。
役に立たない

回答:


37

ここに、例と類推の間の一部の方法があります。いくつかの用事があるので、紙をつかんで次のように書きます。

  • バンク
  • 食料品
  • ドライクリーニングを降ろす

それから、切手も買う必要があることを覚えています。あなたの町の地理のために、あなたは銀行の後にそれをする必要があります。リスト全体を新しい紙にコピーできます。

  • バンク
  • 切手
  • 食料品
  • ドライクリーニングを降ろす

またはあなたが持っていたものに落書きすることができます:

  • 銀行.......スタンプ
  • 食料品
  • ドライクリーニングを降ろす

他の用事について考えたように、リストの一番下にそれらを書くかもしれませんが、矢印でそれを行う順序を思い出させます。これはリンクされたリストです。何かを追加するたびにリスト全体をコピーするよりも速くて簡単です。

次に、銀行にいる間、携帯電話が鳴ります。「ねえ、切手を手に入れました。もう受け取らないでください」。STAMPSをリストから外すだけで、STAMPSなしでまったく新しいものを書き換えることはできません。

これで、実際にコードでお使いのリストを実装できます(お使いの地理に基づいてお使いの順番を並べるアプリかもしれません)。実際にコードでリンクリストを使用する可能性は十分にあります。多数のアイテムを追加および削除する必要がありますが、順序は重要ですが、挿入または削除のたびにリスト全体を再コピーする必要はありません。



@Dennisはい、移動セマンティクスのおかげでわかります。ただし、これはすべての言語に当てはまるわけではないため、この例は有効です。
ケイトグレゴリー

1
@KateGregoryは十分に公平ですが、学校(または他の場所)で学習するクールなデータ構造よりも「基本的な」データ構造の方が優れていることが多いことを指摘しておくと良いでしょう。理論的には適切ですが、現実的には貧弱な選択である可能性があるため、新しい卒業生がどこでもLLを使用するのは望ましくありません。適切なデータ構造を使用することは重要であり、人々はそれを過度に複雑にします。少し関連するのは、データ構造に関するジョナサンブロー(「ブレイド」の作成者)によるこの講演です。
デニス

1
@Ray:4つの要素のオーダーがあると予想される場合、リンクリストはツリー構造よりも優れている可能性があり、比較は比較的安価です。カットオフがどこにないのか、正確にはわかりません。また、ツリー構造ではデータをソートできる必要がありますが、リスト構造では挿入順序(または任意の順序)を維持できます。
デビッドストーン

2
この類推は非常に正確だとは思いません。人間として、(少なくともこのような短いリストに対して)O(1)の要素を見つけることができます。ただし、リンクリストにランダムに挿入する場合は、平均で半分の要素を走査する必要があり、挿入する位置を見つけるためにのみO(n)がかかります。実際の挿入のコストはO(1)のみですが、配列を使用すると、コストもO(n)のみになります。その理由は、移動セマンティクスだけでなく、アルゴリズムによるものです。ただし、big-Oによって隠された一定の要因は、非連続のメモリアクセスのために、いいね!リストでははるかに大きくなります。
5gon12eder

18
  • チェーンを使用してハッシュの衝突を解決するハッシュテーブルには、通常、バケット内の要素のバケットごとに1つのリンクリストがあります。
  • 単純なメモリアロケータは、未使用のメモリ領域の空きリスト、基本的には空きメモリ自体の中にリストポインタを持つリンクリストを使用します
  • ではFATファイルシステム、大規模なファイルのメタデータは、FATエントリのリンクリストとして編成されています。

12

C言語の「呼び出しスタック」は、x86(および他のほとんどの)バイナリAPIのリンクリストとして実装されます。

つまり、C言語のプロシージャ呼び出しは、先入れ先出しの原則に従います。(おそらく再帰的な)関数呼び出しを実行した結果は、「呼び出しスタック」、または単に「スタック」と呼ばれることもあります。

CALLx86命令は、「コールスタック」を使用してリンクリストをimplmenting終わります。CALL命令%EIPレジスタの内容は、命令のアドレスをプッシュした後のCALL上にスタックメモリを。呼び出された関数のプロローグは、%EBPレジスタの内容(呼び出し関数のローカル変数の最下位アドレス)をスタックメモリにプッシュします。次に、呼び出された関数プロローグは、%EBPを現在の関数のスタックベースに設定します。

つまり、%EBPは、呼び出し元の関数の%EBP値のアドレスを保持するメモリ位置へのポインタです。これはリンクされたリストにすぎず、を介してハードウェアに部分的に実装されますCALL

これが何に役立つかというと、x86 CPUが関数呼び出し、特に関数が独自の引数のコピーと関数のローカル変数を持つ関数呼び出しを実装する方法です。すべての関数呼び出しは、「呼び出しスタック」に情報をプッシュします。これにより、CPUは、呼び出し先関数または呼び出し元関数からの干渉を受けることなく、呼び出し元関数で中断した場所を取得できます。


3

リンクリストを使用して、メッセージキューを実装できます。

メッセージキューは、後の処理のためにイベントに関する情報を格納する構造です。たとえば、ユーザーがキーを押すかマウスを動かすと、これがイベントになります。アプリケーションは、イベントが発生した瞬間にビジーになる可能性があるため、イベントが発生した正確な瞬間にイベントを処理することは期待できません。そのため、イベントはメッセージキュー(どのキーが押されたか、またはマウスがどこに移動したかに関する情報)に配置され、アプリケーションに余裕がある場合、メッセージキューをチェックし、イベントを取得して処理しますそれら。(これはミリ秒単位の時間枠内で発生するため、目立ちません。)

先ほど説明した使用シナリオから、メッセージキューに格納されているイベントへのランダムアクセスを決して気にしないことは明らかです。メッセージを保存して取得できるようにするだけです。したがって、最適な挿入/削除時間を提供するリンクリストを使用することは理にかなっています。

(メッセージキューが循環配列リストを使用して実装される可能性が高い、またはより可能性が高い、またはほぼ同じであるということを指摘するために突き合わないでください。それは技術的な詳細であり、制限があります:その中の限られた数のメッセージ。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.