再帰処理(再帰コール)とは、あるメソッド(関数)の中で、自分自身を呼び出すことを言う。 大抵のプログラミング言語で使用できる。
再帰を使うことにより、プログラムがスリムになるが、 その動作は初心者あるいは中級者でも理解しにくいことがある。
また、メソッド(関数)コールのオーバヘッドが生じるため、実行時間がかかったり、 メモリ不足に陥るケースもある。 再帰を使わず、for 文に置き換えた方がよい場合もある。
int binary_search(int ary[], int key, int imin, int imax) {
if (imax < imin) {
return KEY_NOT_FOUND;
} else {
int imid = imin + (imax - imin) / 2;
if (ary[imid] > key) {
return binary_search(ary, key, imin, imid - 1);
} else if (ary[imid] < key) {
return binary_search(ary, key, imid + 1, imax);
} else {
return imid;
}
}
}
階層ディレクトリ下のファイル名(パス名)の一覧表を得る再帰処理は比較的分かりやすく、 また、しばしば必要とする処理である。Java言語による例を下に示す。
import java.io.File;
public class ListFiles {
static void list(File file) {
if (file.isDirectory()) {
File[] subfiles = file.listFiles();
for (File subfile : subfiles) {
list(subfile); // 再帰処理
}
} else { // 終了処理:ファイル
System.out.println(file.toString());
}
}
public static void main(String[] args) {
list(new File( "c:/_www"));
}
}
このプログラムの実行例を下に示す。 ホームページのファイルを c:\_www に置いているとき、 新規作成または更新されたファイルをサーバーに FTP転送するときに使う。 この場合は、ディレクトリやファイルの時刻も調べる。 c:\_www に新しいサブディレクトリができたときは、FTPコマンドを送り、 サーバー側にもその新しいサブディレクトリを作成する。
FFFTPのミラーリングアップロードを使えば済むが、ファイル数が増えると 実行時間がかかる。
c:\_www\.htaccess c:\_www\algorithm\osm-landparser01.html c:\_www\algorithm\point_in_polygon01.html c:\_www\algorithm\recursive_call01.html c:\_www\algorithm\src\pointf_java.txt c:\_www\android_java\onview01.html [後略]
Ramer-Douglas-Peuckerアルゴリズム(またはDouglas-Peuckerアルゴリズム)は 下に示すように、再帰を用いて折れ線データを簡略化するものである[1]。
simplySection関数は線分 points[i]-points[j] の間引きを行う関数である。 許容誤差を epsilon とする。
線分 points[i]-points[j]と途中の点 points[k] との垂直距離を調べて、 その最大値を maxDistance とする。
この最大値が epsilon を超えなければ、全ての中間点は間引いて、処理は終わりである。
最大値が許容誤差を超える場合には、 この最大値を持った点 points[maxIndex] は間引かないことに決定する。 この点を境として、ふたつの線分 points[i]-points[maxIndex]および points[maxIndex]-points[j] に分けて、 それぞれについて simplySection関数を再帰コールする。
[C/C++言語]
// Returns the distance from point p to the line between p1 and p2
double perpendicular_distance(point_t p, point_t p1, point_t p2) {
double dx = p2.x - p1.x;
double dy = p2.y - p1.y;
double d = sqrt(dx * dx + dy * dy);
return fabs(p.x * dy - p.y * dx + p2.x * p1.y - p2.y * p1.x)/d;
}
void simplifySection(point_t *points, size_t i, size_t j, double epsilon) {
if ((i + 1) == j) return;
double maxDistance = -1.0;
size_t maxIndex = i;
for (size_t k = i + 1; k < j; k++) {
double distance = perpendicular_distance(points[k], points[i], points[j]);
if (distance > maxDistance) {
maxDistance = distance;
maxIndex = k;
}
}
if (maxDistance <= epsilon) {
for (size_t k = i + 1; k < j; k++) {
points[k].unused = true; // 間引く
}
} else {
simplifySection(points, i, maxIndex, epsilon);
simplifySection(points, maxIndex, j, epsilon);
}
}