速い・遅いには、かたちがある

よみもの+手を動かす時間:およそ25分

バラバラの数字が、手もとにある

ここまでのレッスンで、いくつもの回数を数えてきました。まっすぐさがすと10枚で最悪10回。半分に切ってさがすと、同じ10枚でも最悪4回でした。

ならべる方はどうだったでしょう。逆順の12枚を差しこみでならべると66回、分けてたばねると20回。4つの数字は、いまのところただの記録にすぎません。

このレッスンでやることは、ひとつだけです。長さを変えながら、同じ手順を測りなおす。すると、バラバラに見えた数字の奥から法則が浮かび上がります。

長さを倍にしながら、測りなおす

長さを4、8、16、32、64と倍々にして、4つの手順をエンジンで実測しました。さがす2つは「どこにもない数」をさがす最悪の場合、ならべる2つは逆順から出発しています。

長さ n半分に切る(最悪)まっすぐさがす(最悪)差しこみ(逆順)分けてたばねる(逆順)
43464
8482812
1651612032
3263249680
647642,016192

表は、横にながめてもあまり語りません。縦に、「長さが倍になったとき何が起きたか」を読んでください

  • 半分に切る:3、4、5、6、7——倍にしても1回増えるだけ。レッスン3の驚きが、列としてそのまま見えています
  • まっすぐさがす:4、8、16、32、64——長さとぴったり同じ。倍にすれば倍、レッスン2の比例です
  • 差しこみ(逆順):6、28、120、496、2,016——倍にするたびほぼ4倍。64枚で2,016回は、もう手作業の世界ではありません
  • 分けてたばねる(逆順):4、12、32、80、192——倍よりは増えるが、4倍にはほど遠い。2倍とちょっとです

同じ「倍にする」という操作に、4つの手順は4通りの増え方で応えました。この増え方のくせこそ、コース名にある「かたち」です。

差しこみと、分けてたばねるを、ならべて再生できる実験室を置いておきます。数を打ちかえて長さを変え、回数の開きが長さとともに広がっていくのをたしかめてください。

差しこみでならべるくらべた回数 0
16151413121110987654321

ならべる前。左はしの1枚は、それだけで「そろっている」

分けて、たばねるくらべた回数 0
16151413121110987654321

ならべる前。まず半分に分けることをくりかえす

1 / 152 場面

かたちに、名前を与える

増え方のくせは4種類ありました。それぞれに名前を与え、グラフに描いたらどう見えるかをことばで添えます。横軸が長さ、縦軸が回数です。

  1. 半分に切るかたち(対数、log n)——倍にしても1回増えるだけ。グラフは右へ行くほど平らに寝ていき、ほとんど水平に見えます
  2. 比例のかたち(n)——倍にすれば倍。グラフはまっすぐな直線です
  3. 分けてたばねるかたち(n log n)——倍にすると2倍とちょっと。直線よりわずかにゆるく反り上がる、直線の親戚です
  4. 総当たりのかたち(n²)——倍にするとほぼ4倍。はじめはおとなしいのに、右へ行くと壁のように立ち上がります

差しこみが「総当たり」と呼ばれるのは、逆順のとき、新しい1枚がそろった部分のぜんぶとくらべることになるからでした。レッスン4で見た「ほぼ4倍」の正体は、このかたちです。

よりみち:世の中での書き方——オーダー記法

プログラミングの世界では、このかたちを O(log n)、O(n)、O(n log n)、O(n²) と書く流儀があります。読み方は「オーダー」。意味は、いまあなたが読み取ったとおり「かたちの名前」です。本や求人票でこの記号を見かけたら、「増え方のくせの話をしているな」と読みかえてください。

かたちが、すべてを支配する

長さを100万にしてみましょう。表を伸ばすかわりに、かたちから見積もります。

  • 半分に切るかたちなら、およそ20回
  • 比例のかたちなら、100万回
  • 総当たりのかたちなら、1兆のけた

20回と1兆——同じ「さばく」仕事でも、かたちが違えば、けたが12個ずれます。ここで思い出してほしいのが、レッスン1の約束です。手順は秒ではなく、くらべた回数で測る。

機械を10倍速くしても、1兆回は1,000億回ぶんの時間にしかなりません。総当たりを半分に切るかたちに変えれば、回数そのものが20回になります。機械を速くするより、かたちを変える方が効く——物差しを機械から切り離したのは、この一点を見るためでした。

正直な注意——かたちは「大きいとき」の話

ただし、かたちが語るのは長さが大きくなったときのふるまいです。小さい列では、話が逆転することがあります。

表の回数にあらわれない手間も、現実にはあります。分けてたばねるには作業用の場所と書き写しが要り、差しこみは手もとだけで済むのでした(レッスン5)。だから数枚から数十枚の列では、総当たりのかたちのはずの差しこみが、実測では勝つことがめずらしくありません。

もうひとつ、逆順は差しこみへのいちばんの意地悪です。ほぼそろった列なら、差しこみは比例に近い回数で済みます。かたち・場所・列のなりたち——どれを重く見るかは、レッスン8でトレードオフとしてまとめて考えます。

演習:表の続きを、予言する

表は長さ64で終わっています。長さを128にしたとき、4つの手順がそれぞれ何回くらいになるか、かたちから予言してください。予言できたら、実験室はさておき——増え方のくせ(+1、2倍、ほぼ4倍、2倍とちょっと)だけを頼りに、64の行から計算してみます。

ヒント1(考え方)

64の行は 7、64、2,016、192 でした。半分に切るかたちは+1。比例は2倍。総当たりはほぼ4倍。分けてたばねるは2倍とちょっと、です。

こたえ(エンジンの実測値)

半分に切る:8回(7+1)。まっすぐさがす:128回(64×2)。差しこみ(逆順):8,128回(2,016のほぼ4倍)。分けてたばねる(逆順):448回(192の2倍とちょっと)。かたちさえ読めれば、測る前から、けたを言い当てられます。

このレッスンで分かったこと

  • 回数は、長さを倍にしながら測りなおすと法則になる——+1ずつ/2倍/ほぼ4倍/2倍とちょっと
  • 増え方のくせが手順のかたち:半分に切る(log n)・比例(n)・分けてたばねる(n log n)・総当たり(n²)
  • 世の中ではこれを O(n) や O(n²) と書く。読みは「オーダー」、意味は「かたちの名前」
  • 長さ100万なら、対数は約20回、総当たりは1兆のけた——機械を速くするより、かたちを変える方が効く
  • ただし、かたちは長さが大きいときの話。小さい列や、ほぼそろった列では、逆転もおきる