Java | ソートアルゴリズムの図解(バブルソート/選択ソート/高速ソートのイメージ)

Java Java
スポンサーリンク

では 各ソートの「ステップ毎に配列を表示」する完全な Java コード を用意しした。

  • 同じ初期配列をコピーして使うので、アルゴリズムごとの変化を比較できます。
  • 各重要な操作(比較・交換・パーティション完了など)で配列を表示します。
  • 初学者が「どの要素が比べられている/交換されているか」を追いやすいように、表示は分かりやすくしています。

以下をそのまま SortVisualizer.java として保存して javacjava で実行してください。

import java.util.Arrays;

public class SortVisualizer {

    // ヘルパー: 配列を見やすく表示(ステップ説明付き)
    private static void printStep(String tag, int[] arr) {
        System.out.println(tag + " : " + Arrays.toString(arr));
    }

    // バブルソートをステップ可視化
    public static void bubbleSortVisual(int[] arr) {
        System.out.println("\n=== Bubble Sort (Visualization) ===");
        printStep("start", arr);
        int n = arr.length;
        int step = 1;
        for (int i = 0; i < n - 1; i++) {
            boolean swapped = false;
            for (int j = 0; j < n - 1 - i; j++) {
                System.out.println("compare (idx " + j + "," + (j+1) + "): " + arr[j] + " ? " + arr[j+1]);
                if (arr[j] > arr[j + 1]) {
                    // swap
                    int tmp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tmp;
                    System.out.println(" swap -> step " + (step++) );
                    printStep("  arr", arr);
                    swapped = true;
                }
            }
            if (!swapped) {
                System.out.println("no swaps in this pass -> already sorted");
                break;
            }
            System.out.println("end of pass " + (i+1));
        }
        printStep("result", arr);
    }

    // 選択ソートをステップ可視化
    public static void selectionSortVisual(int[] arr) {
        System.out.println("\n=== Selection Sort (Visualization) ===");
        printStep("start", arr);
        int n = arr.length;
        int step = 1;
        for (int i = 0; i < n - 1; i++) {
            int minIdx = i;
            System.out.println("\nselect position " + i + " (find min from idx " + i + " to " + (n-1) + ")");
            for (int j = i + 1; j < n; j++) {
                System.out.println(" compare idx " + minIdx + "(" + arr[minIdx] + ") with idx " + j + "(" + arr[j] + ")");
                if (arr[j] < arr[minIdx]) {
                    minIdx = j;
                    System.out.println("  new min at idx " + minIdx + " (" + arr[minIdx] + ")");
                }
            }
            if (minIdx != i) {
                System.out.println(" swap idx " + i + " and idx " + minIdx + " -> step " + (step++));
                int tmp = arr[i];
                arr[i] = arr[minIdx];
                arr[minIdx] = tmp;
                printStep("  arr", arr);
            } else {
                System.out.println(" no swap needed for position " + i);
            }
        }
        printStep("result", arr);
    }

    // クイックソート(可視化) — partition のたびに表示、swap のたびに表示
    public static void quickSortVisual(int[] arr) {
        System.out.println("\n=== Quick Sort (Visualization) ===");
        printStep("start", arr);
        quickSortHelper(arr, 0, arr.length - 1, 1);
        printStep("result", arr);
    }

    // quickSort の再帰ヘルパ(返り値は次のステップ番号)
    private static int quickSortHelper(int[] arr, int lo, int hi, int stepStart) {
        if (lo >= hi) return stepStart;
        System.out.println("\nquickSort range [" + lo + "," + hi + "], current: " + Arrays.toString(Arrays.copyOfRange(arr, lo, hi+1)));
        int pivotIndex = partitionVisual(arr, lo, hi, stepStart);
        int nextStep = pivotIndex >= 0 ? pivotIndex : stepStart;
        // pivotIndex を partitionVisual が最後に出力した step の番号(返却)として使うのではなく、
        // partition 内で標準出力しているので、ここでは再帰だけ行う。
        quickSortHelper(arr, lo, (lo + hi) / 2, nextStep); // 左側を処理(単純に範囲を分けるイメージ)
        quickSortHelper(arr, ((lo + hi) / 2) + 1, hi, nextStep);
        return nextStep;
    }

    // シンプルな partition 可視化(ここでは Lomuto 風の分割を段階的に表示)
    private static int partitionVisual(int[] arr, int lo, int hi, int stepStart) {
        int pivot = arr[hi]; // 右端を pivot にする(分かりやすさ重視)
        System.out.println(" partition with pivot arr[" + hi + "]=" + pivot);
        int i = lo - 1;
        int step = stepStart;
        for (int j = lo; j <= hi - 1; j++) {
            System.out.println(" compare arr[" + j + "]=" + arr[j] + " with pivot " + pivot);
            if (arr[j] <= pivot) {
                i++;
                if (i != j) {
                    System.out.println("  swap idx " + i + " and " + j + " -> step " + (step++));
                    int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
                    printStep("   arr", arr);
                } else {
                    System.out.println("  no swap needed (same index " + i + ")");
                }
            }
        }
        // pivot を適切な位置に置く
        if (i + 1 != hi) {
            System.out.println(" place pivot by swapping idx " + (i+1) + " and " + hi + " -> step " + (step++));
            int tmp = arr[i+1]; arr[i+1] = arr[hi]; arr[hi] = tmp;
            printStep("   arr", arr);
        } else {
            System.out.println(" pivot already in correct place");
        }
        System.out.println(" partition done, pivot index = " + (i+1));
        return step;
    }

    // 配列コピー(プリミティブ配列用)
    private static int[] copyOf(int[] src) {
        return Arrays.copyOf(src, src.length);
    }

    // 実行用 main(同じ初期配列で3種を比較表示)
    public static void main(String[] args) {
        int[] initial = {5, 3, 8, 4, 1, 7};

        // バブルソート(配列をコピーして渡す)
        bubbleSortVisual(copyOf(initial));

        // 選択ソート
        selectionSortVisual(copyOf(initial));

        // クイックソート(可視化)
        quickSortVisual(copyOf(initial));
    }
}
Java

実行するとどうなるか(出力のイメージ)

  • バブルソートは「compare …」「swap -> step X」「arr: […]」を繰り返して、途中の変化が逐次見られます。
  • 選択ソートは「select position i」「compare …」「new min …」「swap」などが表示されます。
  • クイックソートはパーティションごとに「pivot = …」「compare …」「swap …」「pivot placed」と出力され、部分配列ごとの動きが追えます。

補足とカスタマイズ案

  • 出力が多いので配列が長いと読みにくいです。学習やデバッグ用として 長さ 10 以下 程度で試すのがオススメ。
  • クイックソートの再帰の範囲分割を簡略化してあります(可視化を優先)。必要なら正規の quickSort(arr, lo, p-1) / quickSort(arr, p+1, hi) に合わせて出力をもっと厳密に変えます。
  • 視覚化をもっと豪華にしたければ(色付きターミナル、アニメーション、遅延表示など)、別途ライブラリや Thread.sleep(...) を使って実装できます(希望があれば作ります)。
Java
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました