1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[C++] listの中間要素の削除はvectorより遅い場合がある、という勘違い

Posted at

※割と駄文です。

やはり中間要素の挿入や削除をしたい場合はlistを使った方が無難らしい

そりゃそうだろう、という声が聞こえてきそうですが、そもそものきっかけはとある海外のベンチマークテストの記事でした。

この記事の中に「8バイトのデータを一定数格納した各コンテナから要素を1000個Random Removeしたときの速度(ms)差」として以下のグラフが記載されています。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3136393132332f66613066376539392d633638302d653935322d356536642d6439326630376530633136662e706e67.png

このグラフを鵜呑みにして、中間要素の削除が必要な場面でもdequeやvectorを使用していたのですが、最近listじゃないと遅くなるパターンに遭遇しました。

Submission #136682542 - Codeforces
(ソースが汚くてすいません…)

長いので一部抜粋&見やすくなるように編集します。

// 問題のlist
std::list<int> remove_list(a.begin(), a.end());
    
for (auto it = remove_list.begin(); it != remove_list.end();) {
    if (*it == i)
        remove_list.erase(it++);     // ここで中間要素の削除を行なっている
    else ++it;
}

上記のコードは、listをdequeに変更すると実行時間超過でジャッジを通らなくなります。

元記事の本文を読み直してみるとわかるのですが、「挿入、削除する箇所の選択はO(n)の線型探索を用いて決めている」と書いてあり、1回の挿入or削除ごとに全要素間のイテレーションを行ってテストしていることがわかります。
listのイテレーションはdequeに比べてやや遅いことが記載されている1ので、上記のグラフは挿入・削除回数分のイテレーションの速度差を加味した上でのベンチマークである、ということになります。
前述のコード例では1回しかイテレーションを行っていません。実際にこの条件でdequeの3倍以上の速度が出ているので2、グラフをそのまま適用して「listの中間要素の削除は8バイト以下だとdequeより遅い」とするのは誤りである、と考えた方が良さそうです。

まとめ

こう言う記事は本文までちゃんと読まないとダメですね。
今読み返してみたらコメント欄で指摘されてるし…

  1. 実際にlistのイテレーションはvectorやdequeに比べて多少遅いです。といっても実用にならないほどではないですが。

  2. Codeforcesのこの問題における実行時間制限は1秒です。

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?