今日からPHPの勉強をはじめることにしました。「RoRとiPhoneアプリはどうした!?」という声が聞こえてきそうですが、PHPの優先度があがったのですよ。
というわけで、アマゾンで2冊ほど購入。マンモスのが良いと言う書評も見かけましたが、オライリーを買うことにしました。
環境構築
PHPの環境を入れて動作確認。
当面はコマンドラインを使って勉強していこうかと思うので、コマンドライン用のパッケージも入れます。
sudo apt-get install php5 php5-cli php -v PHP 5.3.2-1ubuntu4.2 with Suhosin-Patch (cli) (built: May 13 2010 20:01:00) Copyright (c) 1997-2009 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
クイックソート
とりあえず、少しだけプログラムを書いてみることに。お題はクイックソート。
(最近「Cプログラマのためのアルゴリズムとデータ構造」を読み直す機会があったので)
せっかくなので、C++とRubyでも書いてみて実行時間を比較してみました。
[要素数10の配列をソートする] x 5万回をtimeコマンドを使って計ってみた結果です。
C++(4.4.3) | PHP(5.3.2) | Ruby(1.8.7) | |
---|---|---|---|
real | 0m0.117s | 0m4.486s (38倍) | 0m14.053s (120倍) |
user | 0m0.024s | 0m4.308s | 0m10.041s |
sys | 0m0.012s | 0m0.052s | 0m3.732s |
(つд⊂)ゴシゴシ
(;゚д゚) ・・・
なんぞこれ!?
スクリプト(インタプリタ)が遅いというのは今まで知識としては知っていましたが、実際に目の当たりにすると凄いな。
処理する内容によって全然違ってくるだろうけど、これぐらい違ってくるということもあるのか。
ソフトウェアの速度が出ないときにボトルネック部分をC/C++で書き直すという対処方法もうなずける。
そしてPHPに比べてもRubyが遅い。1.9系だと速くなってるんだっけ?
ちなみにクイックソートのピボットは右端決め打ちで実装しました。(3点中央値はまた今度)
ソースコード
ソースコードさらしておきます。何かおかしかったら教えてください。
コードが間違ってたら、測定結果まったく意味ない><
- C++
#include <iostream> #include <memory.h> void print_array(int array[] , int num) { std::cout << "["; for(int i = 0 ; i < num - 1 ; i++){ std::cout << array[i] << " , "; } std::cout << array[num - 1] << "]" << std::endl; } int partition(int array[] , int left , int right) { int i = left; int j = right - 1; int pivot = array[right]; int temp; while(1) { while(array[i] < pivot){ i++; } while(array[j] > pivot && i < j){ j--; } if(i >= j){ break; } temp = array[i]; array[i] = array[j]; array[j] = temp; } temp = array[i]; array[i] = array[right]; array[right] = temp; return i; } void quick_real(int array[] , int left , int right) { if(left >= right){return;} int vertical = partition(array , left , right); quick_real(array , left , vertical - 1); quick_real(array , vertical + 1 , right); } void quick(int array[] , int num) { quick_real(array , 0 , num - 1); } int main() { int array_template[10] = {55 , 3 , 74 , 20 , 13 , 87 , 46 , 30 , 12 , 65}; int array[10]; int num = sizeof(array) / sizeof(array[0]); for(int i = 0 ; i < 50000 ; i++) { memcpy(array , array_template , sizeof(array)); //print_array(array , num); quick(array , num); //print_array(array , num); } return 0; }
- PHP
#!/usr/bin/php <?php function quick(&$array , $left = 0 , $right = -1) { if($right == -1){ $right = count($array) - 1; } if($left >= $right){ return; } $vertical = partition($array , $left , $right); quick($array , $left , $vertical - 1); quick($array , $vertical + 1 , $right); return; } function partition(&$array , $left , $right) { $i = $left; $j = $right - 1; $pivot = $array[$right]; while(true) { while($array[$i] < $pivot){ $i++; } while($array[$j] > $pivot && $i < $j){ $j--; } if($i >= $j){ break; } $temp = $array[$i]; $array[$i] = $array[$j]; $array[$j] = $temp; } $temp = $array[$i]; $array[$i] = $array[$right]; $array[$right] = $temp; return $i; } $array_template = array(55 , 3 , 74 , 20 , 13 , 87 , 46 , 30 , 12 , 65); for($i = 0 ; $i < 50000 ; $i++) { $array = $array_template; #print implode("," , $array)."\n"; quick($array); #print implode("," , $array)."\n"; } ?>
- Ruby
#!/usr/bin/ruby def quick(array , left = 0 , right = array.size - 1) return if left >= right vertical = partition(array , left , right) quick(array , left , vertical - 1) quick(array , vertical + 1 , right) end def partition(array , left , right) i = left j = right - 1 pivot = array[right] while true i += 1 while array[i] < pivot j -= 1 while array[j] > pivot and i < j break if i >= j array[i] , array[j] = array[j] , array[i] end array[i] , array[right] = array[right] , array[i] return right end array_template = [55 , 3 , 74 , 20 , 13 , 87 , 46 , 30 , 12 , 65] array = [] 50000.times do array = array_template.dup #p array quick(array) #p array end
PHPはよくdisられてるので実はあまり良いイメージは無いんだけども、使ったことも無いのにそんなこと言う資格ないですからね。ある程度つかるようになるぞ!