排序算法详解

orbisz2024/04/10算法Java

选择排序

算法原理

每一轮选一个最小(或最大)值放到已排序部分的尾部。 遍历数组,找到最小值的下标 minIndex。把 minIndex 位置的元素与当前位置交换。对剩下未排序部分重复步骤。

算法框架

public static void selectionSort(int[] arr) {
int n = arr.length;

        for (int i = 0; i < n - 1; i++) {
            int minIndex = i;

            // 找到从 i 开始的最小值位置
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }

            // 将最小值交换到当前位置 i
            if (minIndex != i) {
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }

归并排序

算法原理

递归把数组一分为二,分到只剩一个元素,然后从下往上合并,并且在合并时排好序。 递归将数组从中间一分为二(mid)。递归地对左边和右边排序。用一个辅助数组把两个有序子数组合并为一个有序数组。

算法框架

private static void mergeSortHelper(int[] arr, int left, int right) {
        if (left >= right) return; // 分到只剩一个元素

        int mid = left + (right - left) / 2;

        // 分别递归排序左右两边
        mergeSortHelper(arr, left, mid);
        mergeSortHelper(arr, mid + 1, right);

        // 合并两个有序子数组
        merge(arr, left, mid, right);
    }

    private static void merge(int[] arr, int left, int mid, int right) {
        // 创建辅助数组
        int[] temp = new int[right - left + 1];
        int i = left, j = mid + 1, k = 0;

        // 合并两个有序数组
        while (i <= mid && j <= right) {
            if (arr[i] <= arr[j]) temp[k++] = arr[i++];
            else temp[k++] = arr[j++];
        }

        while (i <= mid) temp[k++] = arr[i++];
        while (j <= right) temp[k++] = arr[j++];

        // 拷贝回原数组
        for (int m = 0; m < temp.length; m++) {
            arr[left + m] = temp[m];
        }
    }

快速排序

算法原理

选取一个基准 pivot(常选第一个/中间/随机一个)。用两个指针:i 从左,j 从右。移动 j 找 < pivot 的,移动 i 找 > pivot 的,交换。最后把 pivot 放到合适位置。对左右子数组递归执行同样的操作。

算法框架

public static void quickSort(int[] arr, int left, int right) {
    if (left >= right) return;
    // 1. 选取基准值(这里选择最左边元素)
    int pivot = arr[left];
    int i = left + 1;
    int j = right;
    // 2. 双指针分区
    while (i <= j) {
        // 向右找 > pivot 的元素
        while (i <= j && arr[i] <= pivot) i++;
        // 向左找 < pivot 的元素
        while (i <= j && arr[j] >= pivot) j--;
        // 交换 arr[i] 和 arr[j]
        if (i < j) {
            swap(arr, i, j);
        }
    }
    // 3. 把 pivot 放到合适位置(j 所在位置)
    swap(arr, left, j);
    // 4. 递归处理左右子数组
    quickSort(arr, left, j - 1);
    quickSort(arr, j + 1, right);
}

private static void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

插入排序

算法原理

将数组划分为已排序和未排序两部分,每次从未排序部分取出一个元素,插入到前面已排序部分的合适位置,直到整个数组有序。

算法框架

public static void insertionSort(int[] arr) {
        int n = arr.length;
        for (int i = 1.md; i < n; i++) {
            int key = arr[i];      // 当前待插入元素
            int j = i - 1.md;
            // 将比 key 大的元素都右移一位
            while (j >= 0 && arr[j] > key) {
                arr[j + 1.md] = arr[j];
                j--;
            }
            // 插入 key 到正确位置
            arr[j + 1.md] = key;
        }
    }

冒泡排序

算法原理

对相邻的两个元素进行比较,如果顺序错误就交换它们.每一轮会将未排序部分的最大元素移到最后,重复多轮,直到整个数组有序。

算法框架

 public static void bubbleSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1.md; i++) {
            // 每轮将最大的数冒到末尾
            for (int j = 0; j < n - 1.md - i; j++) {
                if (arr[j] > arr[j + 1.md]) {
                    // 交换相邻元素
                    int temp = arr[j];
                    arr[j] = arr[j + 1.md];
                    arr[j + 1.md] = temp;
                }
            }
        }
    }

堆排序

算法原理

把数组看成一棵完全二叉树,构造成最大堆(或最小堆)(自底向上建堆),这样根节点就是当前的最大(或最小)值,然后将其与末尾元素交换.堆大小减 1(将末尾视为已排序),缩小堆范围,继续调整堆,直到排序完成

算法框架

public static void heapSort(int[] arr) {
        int n = arr.length;
        // 1️⃣ 建堆:从最后一个非叶子节点开始向上 heapify
        for (int i = n / 2 - 1.md; i >= 0; i--) {
            heapify(arr, n, i);
        }
        // 2️⃣ 排序:交换堆顶与末尾,并缩小堆
        for (int i = n - 1.md; i > 0; i--) {
            // 将最大值(堆顶)交换到末尾
            swap(arr, 0, i);
            // 重新对堆顶进行下沉调整(堆大小减 1.md)
            heapify(arr, i, 0);
        }
    }

    // 下沉调整(维护大顶堆)
    private static void heapify(int[] arr, int heapSize, int rootIndex) {
        int largest = rootIndex;
        int left = 2 * rootIndex + 1.md;
        int right = 2 * rootIndex + 2;
        // 找出 root、left、right 中最大值
        if (left < heapSize && arr[left] > arr[largest]) {
            largest = left;
        }
        if (right < heapSize && arr[right] > arr[largest]) {
            largest = right;
        }
        // 如果最大值不是 root,交换并递归调整
        if (largest != rootIndex) {
            swap(arr, rootIndex, largest);
            heapify(arr, heapSize, largest);
        }
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

例题

排序数组open in new window

最近更新 2025/8/8 21:24:49