web-dev-qa-db-ja.com

二重リンクリストは、単一リンクリストよりも効率的ですか?

今日のインタビューで私は質問を受けました。

リストを逆にしたり、前後のトラバーサルに答えたりする以外に、インタビュアーが強調し続けた「基本的な」何かがありました。私はあきらめ、もちろんインタビューの後に少し研究をしました。挿入と削除は、単一リンクリストよりも二重リンクリストの方が効率的であると思われます。変更するにはより多くの参照が必要であることは明らかであるため、二重にリンクされたリストの方がどのように効率的であるかはわかりません。誰もがその秘密を説明できますか?私は正直なところかなりの研究を行ったが、二重リンクリストにはO(n)検索が必要であるという事実であるという事実が主な問題であるため理解できなかった。

39
as3rdaccount

挿入は、常に先頭または何らかの既知の要素の後に挿入することに満足している限り、一方向にリンクされたリストでは明らかに作業が少なくなります。 (つまり、既知の要素の前に挿入することはできませんが、以下を参照してください。)

一方、削除は、削除する要素の前に要素を知る必要があるため、より複雑です。

これを行う1つの方法は、削除する要素の先行バージョンで削除APIを機能させることです。これは、新しい要素の前身となる要素を使用する挿入APIを反映していますが、あまり便利ではなく、文書化するのが困難です。ただし、通常は可能です。一般的に、リストを走査することでリストの要素に到達します。

もちろん、リストを最初から検索して削除する要素を見つけることで、その前身が何であるかを知ることができます。これは、削除APIにリストの先頭が含まれていることを前提としていますが、これも不便です。また、検索は愚かに遅いです。

ほとんど誰も使用しない方法ですが、実際には非常に効果的ですが、単一リンクリストイテレータを、イテレータの現在のターゲットの前にある要素へのポインタとして定義することです。これは単純で、要素へのポインタを直接使用するよりも1つの間接化だけが遅く、挿入と削除の両方が高速になります。欠点は、要素を削除すると他のイテレータが無効になり、要素をリストする可能性があることです。これは迷惑です。 (削除される要素のイテレータは無効になりません。これは、いくつかの要素を削除するトラバーサルには適していますが、それはあまり補償ではありません。)

おそらくデータ構造が不変であるために削除が重要でない場合、一重リンクリストは別の非常に有用なプロパティを提供します:構造共有を許可します。単一リンクリストは、幸いにも複数のヘッドのテールになります。これは、二重リンクリストでは不可能なことです。このため、一方向リンクリストは、伝統的に関数型言語の単純なデータ構造の選択肢でした。

43
rici

これは私にそれを明確にしたいくつかのコードです...

class Node{
      Node next;
      Node prev;
}

単一リンクリストのノードを削除 -O(n)-

どのノードが先行ノードかわからないため、リストを見つけるまでリストを走査する必要があります。

deleteNode(Node node){
    prevNode = tmpNode;
    tmpNode = prevNode.next;

    while (tmpNode != null) {
        if (tmpNode == node) {
            prevNode.next = tmpNode.next;
        }
        prevNode = tmpNode;
        tmpNode = prevNode.next;
    }
}

DOUBLE LINKED LISTのノードを削除 -O(1)-

次のようにリンクを簡単に更新できます。

deleteNode(Node node){
    node.prev.next = node.next;
    node.next.prev = node.prev;
}
22

二重リンクリストに関する私の考えは次のとおりです。

  • 両端でアクセス\挿入の準備ができています。

  • キューとスタックとして同時に機能します。

  • ノードの削除には、追加のポインターは必要ありません。

  • すでに両端にアクセスできるため、ヒルクライムトラバーサルを適用できます。

  • 数値を保存しており、リストがソートされている場合、中央値のポインター/変数を保持でき、統計的アプローチを使用して検索操作を非常に最適化できます。

10
Khaled.K

リンクリストの要素を削除する場合は、前の要素を次の要素にリンクする必要があります。二重リンクリストを使用すると、両方の要素へのリンクがあるため、両方の要素にすぐにアクセスできます。

これは、削除する必要のある要素へのポインターが既にあり、検索が含まれていないことを前提としています。

5
Mark Ransom

「リストを逆にしたり、順方向および逆方向の両方のトラバースに答える以外に、「基本的な」何かがありました」。

誰も言及していないようです。二重にリンクされたリストでは、削除された要素へのポインタを持つだけで、削除された要素を再挿入することができます。 KnuthのDancing Linksペーパーをご覧ください。これはかなり基本的なことだと思います。

2
user1666959
Doubly Linked list is more effective than the Singly linked list when the location of the element to be deleted is given.Because it is required to operate on "4" pointers only & "2" when the element to be deleted is at the first node or at the last node.


struct  Node {

       int  Value;
       struct Node  *Fwd;
       struct Node  *Bwd;
);


Only the below line of code will be enough to delete the element ,If the element to be deleted is not in the first or last node.

X->Bwd->Fwd = X->Fwd; X->Fwd->Bwd = X->Bwd ;
0
Parveen Kumar