簡潔ビットベクトルで可能な操作
完備辞書はビットベクトルBに対して以下の操作を提供します1
- : B[i]を返す
- : B[1, i]のbの数を返す
- : Bの先頭からi番目のbの位置を返す
index | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
B | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 0 |
rank
索引の構築
rankを定数時間で実行するために,索引として大ブロックL,小ブロックS,テーブルPを作成します.
- 大ブロックLには,長さlごとに直前までに現れた1の総数を記録します.
- 小ブロックSには,長さsごとに直前までに現れた1の総数を記録します. その際,メモリ節約のため所属する大ブロックに記録した数との差分を記録するようにします.
- テーブルPには,長さsのすべてのbitパターンとそのrankの値を記録します.
lを16,sを8としたときは以下のようになります.
索引の空間計算量
ビットベクトルの長さがnのとき各索引のサイズは下のようになります.
大ブロックL:ビット
小ブロックS:ビット
テーブルP:ビット
小ブロックは大ブロックからの差分を記録するため,ひとつのブロックはビットとなります. ここでlを,sをとすると,合計サイズをn + o(n)ビットに抑えることができます.
rank操作
を求めるには,iの所属する大ブロックLの値,iの所属する小ブロックSの値,小ブロックの位置からiまでの1の数を足し合わせる必要があります.
大ブロックの位置xは,小ブロックの位置yは,テーブルPのパターンpはB[s(y - 1) + 1, i]となります2.
よってrankは以下のように求めることができます .
以上のすべての操作は定数時間で可能なため,rankは定数時間で計算できます. また,という関係があるためも定数時間で計算することができます.
具体例として,lを16,sを8としたときのを求めてみます.
大ブロックの位置xはなので2となります.
小ブロックの位置yはなので4となります.
テーブルPのパターンpはなので[1, 1, 1, 0, 1]となります.
以上のことからと求めることができました.
select
select操作
selectはrankよりも複雑なので,select用の索引は作らずにrank用の索引を2分探索して求めることが多いみたいです.rank自体は定数時間で求められるのでこの操作はO(lg n)で実行可能です.
を求めるには, かつとなるようなiを見つければいいです.
このとき,ビットベクトルBを直接探索するのではなく,大ブロックLと小ブロックSと順に2分探索することで高速化が可能です.
まずとなるような最大のpを大ブロックLを2分探索して見つけます.
つぎにとなるような最大のqを小ブロックSを2分探索して見つけます.
ここでiはq番目の小ブロックに所属していることがわかるので,あとはを辞書引きするか前から探索するかして求めることができます.