コラム1を読んでてビットの話で早速躓いてしまった。 ネットで解説読んで理解したのでまとめてみる。 http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13100650348
7桁の数値が10^8個あり、これらをソートしたい。
ただしメモリは1MBまでしか使えない。
数値nを右からn番目のビットを立てる事で全ての状態を一度に表現する。
(例えば全てのビットを立てれば1~9999999までの数値全てを表している事になる)。
そうすると、今扱いたいのは10^8個の数値なので、
0000 0000 0000 0000 0000 ............ 0000 (0を10^8個並べる)
と一列に並べる事が出来れば良い。
このようにすれば、
10000000[bit]=1250000[byte]=1.25[MB]≒1[MB]
となるのでメモリの問題も発生しない。
次に問題となるのは、実際には10^8個の数値を一列に並べる事が出来ないという点。
intは4[byte]=32[bit]なので、一度に扱えるのは32桁分まで。
そこで、32桁ずつ分けて表現する事を考える。
10000000 / 32 = 312500
なので全ての数値を表現するためには312500個分のintを確保する必要がある。
よってint a[312500+1]という配列を用意し、入力nが配列のどのindexになるかを計算して収めていく。
(+1するのは余りがある場合を考慮してるためだと思う。今回はぴったり収まるけど。)
a[0] = 0~31までの数字を全て表現出来る: 0000 0000 0000 0000 0000 0000 0000 0000
a[1] = 32-63までの数字を全て表現出来る: 0000 0000 0000 0000 0000 0000 0000 0000
a[2] = 64~95までの数字を全て表現出来る: 0000 0000 0000 0000 0000 0000 0000 0000
...
a[312499] = 9999967~9999999までの数値を全て表現出来る: 0000 0000 0000 0000 0000 0000 0000 0000
解答にはビット操作をふんだんに利用しているが、上記の背景の理解が不十分だったのではじめ本を読んでも理解する事ができなかった。
例えば以下のコードの場合。
void set(int i) { a[i>>SHIFT] |= (1 << (i & MASK)); }
入力として i = 50を考える。
今、SHIFT = 5, MASK = (11111)なので、
50 >> 5 = 1 (右に5シフトするとは、2^5=32で割ることと同じ。)
次に i & MASKについて。
50 & 111111(2) => 0011 0010(2) & 1 1111(2) => 1 0010 => 2^4 + 2^1 = 18 = (※ 32 + 18 = 50)
最後に、i << (18) で、これは右から18桁目にビットを立てる事になる。
以上を踏まえ、理解しやすいようにbitsetで考えると以下のようになる
#include <bitset> #include <vector> #include <iostream> void func() { std::vector<int> inputs = {50, 100, 2, 3000, 1, 90020, 30}; std::bitset<32> numbers[312500]; // 10000000/32 =312500 for(size_t i = 0; i < inputs.size(); ++i){ int input = inputs[i]; int quotient = input / 32; int remainder = input % 32; numbers[quotient][remainder] = true; } for(int i = 0; i < 312500; ++i){ for(int j = 0; j < 32; ++j){ if(numbers[i][j]){ std::cout << i*32 + j << std::endl; } } } }