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


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

    选择排序(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. 归并排序:在大多数情况下效率最高,但需要额外的内存空间。
  • 相关阅读:
    Golang 并发 Channel的用法
    PMP每日一练 | 考试不迷路-8.29(包含敏捷+多选)
    【C#排序算法】(二)插入排序
    Day726.Java平台模块系统 -Java8后最重要新特性
    新生必看:如何选择适合自己的自考专业?
    计算机网络第一章习题_网络概述
    信息系统项目管理师---第十三章项目合同管理历年考题
    电容笔和触控笔的区别是什么?好用的电容笔测评
    六、Python类的高级知识
    Sentinel —实时监控
  • 原文地址:https://blog.csdn.net/qq_52010229/article/details/139690796