SIZE(20){COLOR(magenta){Rコードの最適化例:クイックソート}}  [[Rコード最適化のコツと実例集]] に戻る~

「工学のためのデータサイエンス入門」215-216頁の例、再帰的関数の例。このコードもアルゴリズムの説明を忠実にコード化したという意味で教育的ですが、いかんせんこのままでは遅過ぎ、大きな x を扱えません。

 # オリジナルコード(注:少し編集。なお本の中の i0 <- sample(1, 1:n) は間違いです) 
 quick <- 
   function(data){  
     n <- length(data)  
     if (n <= 1) return(data) # 以下二行は例外処理(これは if 文の出番) 
     if (n == 2) {if (data[1] < data[2]) return(data) else return(data[2:1])} 
     i0 <- sample(1:n, 1)  
     s1 <- s2 <- numeric(0)  # 最終長さが未定のベクトルを利用(出来れば避けたい)
     x <- data[-i0]  
     for (i in 1:(n-1)){     # このループが目障り  
       if (x[i] < data[i0]) s1 <- c(s1,x[i]) else  s2 <- c(s2,x[i]) 
     }  
     if (length(s1) == 0) return(c(data[i0], quick(s2))) # 以下3行も似たようなことをしていて気になる 
     if (length(s2) == 0) return(c(quick(s1), data[i0]))  
     return(c(quick(s1), data[i0], quick(s2)))
 }

 # Chambers によるコード(少し編集)、「データによるプログランミング」森北出版 (2002) 68頁
 # ほれぼれする見事なコード(さすが S 言語の開発者!)
 # 上のコードの for loop をベクトルの添字操作で隠す(高速化のおまけつき)
 # 条件 length(x) <= 1 を length(x) == 1 にしてはいけません (x が空の可能性あり)
 # x[x < fence] は x の要素の内で値が fennce 未満のもの全体(numeric(0), i.e. 長さゼロとなる可能性)
 # x[x == fence] は x の要素の内で値が丁度 fennce のもの全体
 # x[x == fence] を 単に fence としては絶対いけません(タイを含む可能性)
 # x[x > fence] は x の要素の内で値が fence を越えるもの(numeric(0), i.e. 長さゼロとなる可能性)
 # ベクトルに numeric(0) を連結しても変わらないことを利用して quick() の最後の目障りな三行を一行ですます
 quicksort <- 
   function (x) {
     if (length(x) <= 1) return(x)
     if (length(x) == 2) {if (x[1] <= x[2]) return(x) else return(x[2:1])}
     fence = sample(x,1)
     fence = sample(x,1)  # 添字を使わず x の要素を直接無作為に取り出している
     return( c(quicksort(x[x < fence]), x[x == fence], quicksort(x[x > fence])) )
   }

 # 最悪ケースで比較
 system.time(x <- quick(10000:1))
 [1] 5.58 0.02 5.61 0.00 0.00
 system.time(x <- quicksort(10000:1))
 [1] 0.63 0.00 0.64 0.00 0.00
 system.time(x <- sort(100000:1))  # もちろん組み込み関数 sort() を使えば一瞬
 [1] 0.01 0.00 0.03 0.00 0.00


トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS