基础排序算法详解与对比分析

排序算法是计算机科学中最基础和重要的算法之一。本文将详细介绍几种经典的排序算法,包括选择排序、插入排序、希尔排序、堆排序和归并排序,并进行代码实现和对比分析。

选择排序(Selection Sort)

选择排序的基本思想是每次从未排序部分选择最小的元素,将其与未排序部分的第一个元素交换,从而逐步建立有序序列。其实现代码如下:

public class SelectionSort {

    // 选择排序方法
    public static void selectionSort(int[] array) {
        int n = array.length;
        for (int i = 0; i < n - 1; i++) {
            // 找到未排序部分的最小元素
            int minIndex = i;
            for (int j = i + 1; j < n; j++) {
                if (array[j] < array[minIndex]) {
                    minIndex = j;
                }
            }
            // 将最小元素与未排序部分的第一个元素交换
            int temp = array[minIndex];
            array[minIndex] = array[i];
            array[i] = temp;
        }
    }
}
插入排序(Insertion Sort)

插入排序的基本思想是将数组划分为已排序和未排序两部分,逐个将未排序部分的元素插入到已排序部分的适当位置。其实现代码如下:

public class InsertionSort {

    // 插入排序方法
    public static void insertionSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int key = array[i];
            int j = i - 1;

            // 将当前元素插入到已排序部分的正确位置
            while (j >= 0 && array[j] > key) {
                array[j + 1] = array[j];
                j--;
            }
            array[j + 1] = key;
        }
    }
}
希尔排序(Shell Sort)

希尔排序是插入排序的改进版,通过将数组分成多个子数组分别进行插入排序,然后逐步减少子数组的规模,最终进行一次标准的插入排序。其实现代码如下,使用给定的增量序列 (h = 7, 3, 1):

public class ShellSort {

    // 希尔排序方法
    public static void shellSort(int[] array) {
        int n = array.length;

        // 使用给定的增量序列 h = 7, 3, 1
        int[] gaps = {7, 3, 1};
        for (int gap : gaps) {
            // 对每个增量序列进行排序
            for (int i = gap; i < n; i++) {
                int temp = array[i];
                int j = i;
                // 将 temp 插入到合适的位置
                while (j >= gap && array[j - gap] > temp) {
                    array[j] = array[j - gap];
                    j -= gap;
                }
                array[j] = temp;
            }
        }
    }
}
堆排序(Heap Sort)

堆排序的基本思想是将数组构建成一个堆,然后重复地将堆顶元素(最大元素)与未排序部分的最后一个元素交换,并将剩余部分重新调整为堆,直到整个数组有序。其实现代码如下:

public class HeapSort {

    // 堆排序方法
    public static void heapSort(int[] array) {
        int n = array.length;

        // 构建最大堆
        for (int i = n / 2 - 1; i >= 0; i--) {
            heapify(array, n, i);
        }

        // 一个个将堆顶元素与末尾元素交换,并重新调整堆
        for (int i = n - 1; i > 0; i--) {
            // 交换堆顶元素和末尾元素
            int temp = array[0];
            array[0] = array[i];
            array[i] = temp;

            // 重新调整堆
            heapify(array, i, 0);
        }
    }

    // 将以i为根的子树调整为最大堆
    private static void heapify(int[] array, int n, int i) {
        int largest = i; // 根节点
        int left = 2 * i + 1; // 左子节点
        int right = 2 * i + 2; // 右子节点

        // 如果左子节点比根节点大
        if (left < n && array[left] > array[largest]) {
            largest = left;
        }

        // 如果右子节点比目前最大的节点大
        if (right < n && array[right] > array[largest]) {
            largest = right;
        }

        // 如果最大的节点不是根节点
        if (largest != i) {
            int swap = array[i];
            array[i] = array[largest];
            array[largest] = swap;

            // 递归地调整受影响的子树
            heapify(array, n, largest);
        }
    }
}
归并排序(Merge Sort)

归并排序的基本思想是将数组分成两部分,分别进行排序,然后合并两个有序的子数组。其实现代码如下:

public class MergeSort {

    // 归并排序方法
    public static void mergeSort(int[] array) {
        if (array.length > 1) {
            int mid = array.length / 2;

            // 分成两个子数组
            int[] left = new int[mid];
            int[] right = new int[array.length - mid];

            System.arraycopy(array, 0, left, 0, mid);
            System.arraycopy(array, mid, right, 0, array.length - mid);

            // 递归排序两个子数组
            mergeSort(left);
            mergeSort(right);

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

    // 合并两个有序子数组
    private static void merge(int[] array, int[] left, int[] right) {
        int i = 0, j = 0, k = 0;
        while (i < left.length && j < right.length) {
            if (left[i] <= right[j]) {
                array[k++] = left[i++];
            } else {
                array[k++] = right[j++];
            }
        }
        while (i < left.length) {
            array[k++] = left[i++];
        }
        while (j < right.length) {
            array[k++] = right[j++];
        }
    }
}

算法对比分析

对这些排序算法的运行时间和空间复杂度进行对比分析如下:

排序算法最好情况时间复杂度最坏情况时间复杂度空间复杂度备注
选择排序Θ(N²)Θ(N²)Θ(1)简单但效率低,适用于小规模数据集
堆排序(不使用多余空间)Θ(N)Θ(N log N)Θ(1)相对较快,但在缓存性能方面表现较差
归并排序Θ(N log N)Θ(N log N)Θ(N)在大多数情况下最快,但需要额外的内存空间
插入排序(不使用多余空间)Θ(N)Θ(N²)Θ(1)最适合小规模或近乎有序的数据集
希尔排序Θ(N)Ω(N log N) O(?)Θ(1)理论丰富,性能视增量序列而定

结论

  1. 选择排序:简单直观,但在处理大规模数据时效率低下,适合小规模数据集。
  2. 插入排序:在数据几乎有序或规模较小时非常高效。
  3. 希尔排序:通过增量序列优化插入排序,性能依赖于具体的增量序列选择。
  4. 堆排序:时间复杂度较低,特别是在最坏情况下,但在处理大规模数据时,缓存性能表现不佳。
  5. 归并排序:在大多数情况下效率最高,但需要额外的内存空间。
  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

poison_Program

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值