web-dev-qa-db-ja.com

O(1)複雑さ)のLinkedListのadd(int、E)はどうですか?

linked-list タグwikiの抜粋から:

リンクされたリストは、要素が次の(およびオプションで前の)要素への参照を含むデータ構造です。リンクリストはO(1)の挿入と削除を任意の位置で提供します、O(1)リストの連結、および= O(1)前(およびオプションで後)位置でのアクセス、およびO(1)次の要素へのアクセス。ランダムアクセスにはO(N)複雑であり、通常は実装されていません。

(強調鉱山)

これを読んで驚いた–単純なインデックスreadingよりも複雑度の低いランダムインデックスで、リストinsertをどうやってできるのか?

それで、私は _Java.util.LinkedList_のソースコード を見ました。 add(int, E) method は次のとおりです。

_public void add(int index, E element) {
    addBefore(element, (index==size ? header : entry(index)));
}
_

_addBefore(E, Entry<E>_ method は単なるポインタの再割り当てですが、 entry(int) method もあります。

_if (index < 0 || index >= size)
        throw new IndexOutOfBoundsException("Index: "+index+
                                            ", Size: "+size);
    Entry<E> e = header;
    if (index < (size >> 1)) {
        for (int i = 0; i <= index; i++)
            e = e.next;
    } else {
        for (int i = size; i > index; i--)
            e = e.previous;
    }
    return e;
}
_

ハーフサイズの最適化を使用しても、ここでのforループ(どちらか一方)は、このメソッド(およびadd(int, E))が最小限のワーストO(n)時間の場合のシナリオであり、確かに一定の時間ではありません。

何が欠けていますか? big-O表記を誤解していますか?

26
wchargin

まあ、それらは任意の位置での一定時間の挿入をサポートします–しかしif後にのみ、またはその後にリストエントリへのポインタがある場合挿入したいものもちろん、これはインデックスがあるだけでは機能しませんが、最適化されたコードで通常行うことではありません。

Javaではそれも可能ですが、 リスト反復子のみを使用 です。

リンクリストのこのプロパティは、arraylistなどと比較して最大の利点です。たとえば、チャットルームのユーザーリストからユーザーを削除する場合は、ユーザーのユーザーリスト内のユーザーの位置へのポインターを格納して、 、彼が部屋を出たい場合、それはO(1)操作として実装できます。

4
thejh

これは、あなたが読んでいる記事が「そのインデックスに到達する」ことを別の操作と見なしているためです。この記事では、すでにadd(int、E)を実行するインデックスにいると想定しています。

結論として:

挿入または削除操作= O(1)

nでノードを検索番目 インデックス= O(n)

14

linkingの操作は、任意のノードへの新しいノードO(1)ですが、finding(ループの助け))の操作は、関連するインデックスは間違いなくO(n)です。

魔法はありません;)

2
Mik378

あなたが引用するwikiページは言う:

O(1)任意の位置での挿入と削除position

それからあなたは尋ねます:

これを読んで驚いた–リストをランダムに挿入する方法index

ここに混乱があります。positionおよびindexという用語は、同じことを意味するために使用されていません。ウィキは、インデックスではなく、イテレータまたはポインタについて話します。

1
NPE