web-dev-qa-db-ja.com

python list.append()メソッドO(1)の時間の複雑さはなぜですか?

TimeComplexity のドキュメントで見られるように、Pythonのlist型は配列を使用して実装されています。

したがって、配列が使用されており、いくつかの追加を行う場合、最終的にスペースを再割り当てし、すべての情報を新しいスペースにコピーする必要があります。
すべてのことの後、どうすればO(1)最悪の場合?

25
ohad edelstain

リンクしたドキュメントの脚注を見ると、警告が含まれていることがわかります。

これらの操作は、「Amortized Worst Case」の「Amortized」部分に依存しています。コンテナの履歴によっては、個々のアクションに驚くほど長い時間がかかる場合があります。

償却分析 を使用すると、場合によっては高価な操作を実行しなければならない場合でも、操作を個別にではなくシーケンスとして考えると、操作の「平均」コストの下限を取得できます。

したがって、個々の操作は非常に高価になる可能性があります-O(n)またはO(n ^ 2)またはさらに大きいもの-これらの操作はまれであることがわかっているため、 O(n)操作はO(n) time。

21
Jacob Ritchie

O(1)ではなく、O(1)で償却されます。

リストの予約サイズが8要素で、スペースがなくなるとサイズが2倍になるとしましょう。 50個の要素をプッシュします。

最初の8つの要素はO(1)にプッシュされます。 9番目は再割り当てと8つのコピーをトリガーし、その後にO(1) Pushが続きます。 O(1)の次の7プッシュ。 17番目は、再割り当てと16のコピーをトリガーし、その後にO(1) Pushが続きます。 O(1)の次の15プッシュ。 33番目は再割り当てと32個のコピーをトリガーし、その後にO(1) Pushが続きます。 O(1)の次の17プッシュ。

したがって、すべてのプッシュにはO(1)の複雑さがあり、O(1)で56個のコピー、O(n)で3個の再割り当てがあり、n = 8、16、および32でした。は幾何級数であり、O(n)に漸近的に等しく、n =リストの最終サイズです。これは、n個のオブジェクトをリストにプッシュする操作全体がO(n)であることを意味します。 amortize要素ごとの場合、O(n)/ n = O(1)です。

26
rlbond