双方向循環リスト
加賀正樹 @kagasantwi
はじめに
効率的なプログラムを書くには?
・データを適切なデータ構造に保存する
・適切なアルゴリズムを実行する
データ構造とリスト
基本的なデータ構造(Wikipedia参照)
・配列
・連想配列
・線形リスト←これ
・木構造
・グラフ
線形リストの特徴(一部)
・ランダムアクセスができない
→a番目を参照するときは前からa回見ていく
→通常の配列ならO(1),data[a]でok
・途中での挿入・削除ができる
→例:{1,2,4,5}を{1,2,3,4,5}にするのがO(1)※
→通常の配列なら1つずつずらすのでO(n)
実現方法
値だけでなくリンクするノードの場所も持つ
つまり
・操作をするからランダムアクセスができない
→挿入・削除で要素数が変化
・どこでも操作できるわけではない
→今見てる場所でのみ操作できるO(1)※
※2ページ前のO(1)も場所による
双方向循環リスト
・任意のノードと隣接している両方のリンクを持つ
→双方向に移動可能
・先頭と末尾がリンク
→面倒な処理なしに循環する
双方向循環リストのイメージ
削除・挿入!どちらにも動ける!ループ!
双方向循環リストの強み
・円の上をぐるぐる回るような処理に強い
・要素が死んだり生まれたりする処理に強い
例
順番にキャラクターが行動するが、死ぬこともある
死んだキャラを削除することで処理速度を上げる
実装方法
C++なら#include <list>
でok!(少しややこしい)
要素が削除される一方
なら→のような書き方
もアリ
実践
AOJ 0301 (PCK2014予選7問目)
問題概要(超意訳)
・N(≦200000)人が輪になって座っている
・ある人に死神が憑りついている
・数a(≦100)が宣言さる
・奇数なら反時計回りに、偶数なら反時計周りにa人分死神が移動
・移動した先の人は死んで、時計周りに隣の人に憑りつく
・これをM(<N)回行う
・その後Q(<1000)回生存確認が行われるので、生死を答える
実践・解答例
流れ
・配列は要素数が多いのでmainの外
・入力を受け取る
・双方向循環リストを構築
・m回の殺戮(移動と削除)
・q回の出力
(ランダムアクセスができる)
計算量はO(Ma)=O(20000000)
間に合う
補足
・循環しているので、移動回数をmodで減らせることもある
・配列を使って構築するのも限度があるので、STLも学んでおく
・Wikipediaを読む

双方向循環リスト