Java中的六种经典比较排序算法:代码实现全解析(下)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Java中的六种经典比较排序算法:代码实现全解析(下)

六、 希尔排序

6.1 原理与思想

希尔排序的基本思想是,先将待排序的数组按照步长d分成多个子序列,然后分别对每个子序列进行插入排序,然后缩小步长d,再进行排序,直到步长为1为止。

具体实现中,步长可以按照某种规律确定,通常以序列长度的一半作为初始步长,然后每次将步长减半,直至步长为1。

例如,对于一个序列{8,34,56,78,12,57,89,43},选择步长为4:

  • 首先,将序列分为四个子序列:{8,57},{34,89},{56,43},{78,12}。
  • 然后,对于每个子序列,分别进行插入排序。
  • 接下来,将步长缩小至2,将序列分成两个子序列:{8,89,56,12},{34,57,78,43}。
  • 上述操作持续进行,直至步长为1,最终对整个序列进行一次插入排序,完成排序。

6.2 代码实现

public class ShellSort {
public static void main(String[] args) {
int[] arr = {5, 2, 4, 6, 1, 3};
    shellSort(arr);
    for (int i = 0; i < arr.length; i++) {
        System.out.print(arr[i] + " ");
    }
}
public static void shellSort(int[] arr) {
    int n = arr.length;
    for (int gap = n / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < n; i++) {
            int key = arr[i];
            int j = i;
            while (j >= gap && arr[j - gap] > key) {
                arr[j] = arr[j - gap];
                j -= gap;
            }
            arr[j] = key;
        }
    }
}
}

6.3 时间复杂度分析

时间复杂度的表示法的含义可以在2.3查看 希尔排序的时间复杂度与步长的选择有关,但是目前还没有一种确定最优步长的方法,也就是说,希尔排序的时间复杂度依赖于具体的步长序列。

目前已知最优步长序列的时间复杂度为O(n^1.3),即当步长序列为1, 4, 13, 40, ...时,希尔排序的时间复杂度最优。

但是,希尔排序的时间复杂度最坏为O(n^2),最好为O(nlogn)。

七、 归并排序

7.1 原理与思想

归并排序采用分治策略,它将问题划分为较小的问题,并递归地解决每个子问题。具体来说,归并排序的过程包括两个主要步骤:

  • 分割:将待排序数组拆分为两个长度相等的子数组,这一步骤通过递归调用归并排序来实现。
  • 合并:将已排序的两个子数组合并为一个有序的数组。这一步骤通过比较两个待比较的元素,然后按顺序将它们放入一个新的数组中来实现。

7.2 代码实现

public static void mergeSort(int[] nums) {
    if (nums == null || nums.length < 2) {
        return;
    }
    int mid = nums.length / 2;
    int[] left = Arrays.copyOfRange(nums, 0, mid);
    int[] right = Arrays.copyOfRange(nums, mid, nums.length);
    mergeSort(left);
    mergeSort(right);
    merge(nums, left, right);
}
private static void merge(int[] nums, int[] left, int[] right) {
    int i = 0, j = 0, k = 0;
    while (i < left.length && j < right.length) {
        if (left[i] <= right[j]) {
            nums[k++] = left[i++];
        } else {
            nums[k++] = right[j++];
        }
    }
    while (i < left.length) {
        nums[k++] = left[i++];
    }
    while (j < right.length) {
        nums[k++] = right[j++];
    }
}

在上面的代码中,mergeSort方法用于递归地分割数组,并调用merge方法在合适的位置上合并这些分割后的数组。merge方法比较分割后的数组的元素,并将它们按照顺序放入一个新的数组中。

7.3 时间复杂度分析

时间复杂度的表示法的含义可以在2.3查看 归并排序的时间复杂度为O(nlogn),其中n是待排序数组的长度。归并排序的时间复杂度是基于分治策略的,它将问题拆分为较小的子问题,然后递归地解决这些子问题。因此,归并排序的时间复杂度与子问题的数量相关。每次递归把数组分成两半,因此将生成O(logn)层。在每一层中,需要比较和合并O(n)个元素。因此,总体复杂度为O(nlogn)。

八、 快速排序

8.1 原理与思想

快速排序也采用了分治策略。与归并排序不同的是,快速排序是在分割数组的同时对其进行排序的。具体来说,快速排序的过程包括以下步骤:

  • 选择主元素:从数组中选择一个元素作为主元素,并根据它对数组进行分区。
  • 分区:将比主元素小的元素放在主元素的左侧,将比主元素大的元素放在主元素的右侧。这一步骤可以使用左右指针来实现。
  • 递归:递归地应用快速排序算法,直到所有子数组都有序。

8.2 代码实现

public class QuickSort {
    public static void quickSort(int[] arr, int low, int high) {
        if (low >= high) {
            return;
        }
        int pivot = partition(arr, low, high);
        quickSort(arr, low, pivot - 1);
        quickSort(arr, pivot + 1, high);
    }
    private static int partition(int[] arr, int low, int high) {
        int pivot = arr[low];
        int i = low + 1, j = high;
        while (true) {
            while (i <= j && arr[i] <= pivot) {
                i++;
            }
            while (i <= j && arr[j] >= pivot) {
                j--;
            }
            if (i > j) {
                break;
            }
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        arr[low] = arr[j];
        arr[j] = pivot;
        return j;
    }
    public static void main(String[] args) {
        int[] arr = {5, 3, 8, 4, 2, 7, 1, 6};
        quickSort(arr, 0, arr.length - 1);
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}

代码中首先定义了一个quickSort方法,传入待排序序列及序列的起始下标low和结束下标high。如果low>=high,则递归结束。否则,调用partition方法,将序列分为左右两部分。然后对左右两部分分别进行递归排序,直到整个序列有序。

partition方法是快速排序算法的核心。选择第一个元素作为基准元素pivot,定义i=low+1,j=high。从左往右扫描,找到第一个大于pivot的元素,将其与从右往左扫描找到的第一个小于pivot的元素交换位置。如果i>j,说明扫描完成,退出循环。最后将基准元素移动到i-1的位置,返回i-1。

8.3 时间复杂度分析

时间复杂度的表示法的含义可以在2.3查看 快速排序的平均时间复杂度为O(nlogn),最坏时间复杂度为O(n^2),空间复杂度为O(logn)。不过由于快速排序是原地排序算法,不需要额外的存储空间。

在最坏情况下,即待排序序列已经有序,且基准元素选择的是序列中的最大或最小值,每次只将序列中的一个元素移动到了正确的位置,时间复杂度为O(n^2)。但是这种情况很少出现,可以通过优化基准元素的选择和递归排序的顺序来减少出现最坏情况的概率。

九、 性能比较

9.1 实验设计

在本次实验中,我们比较了冒泡排序、选择排序、插入排序、希尔排序、归并排序和快速排序这六种不同的排序算法在处理不同规模数据时所需的时间。我们随机生成了 10 个不同规模的数据集,并对各个算法在每个数据集上的运行时间进行了测试。

实验数据集规模如下:

  • 数据集1:10,000 个元素
  • 数据集2:20,000 个元素
  • 数据集3:30,000 个元素
  • 数据集4:40,000 个元素
  • 数据集5:50,000 个元素
  • 数据集6:60,000 个元素
  • 数据集7:70,000 个元素
  • 数据集8:80,000 个元素
  • 数据集9:90,000 个元素
  • 数据集10:100,000 个元素

9.2 实验结果分析

根据实验结果,不同的排序算法在处理不同规模数据时的表现不同。在排序算法的性能比较中,时间复杂度是一个重要的指标。根据时间复杂度的定义,时间复杂度越低的算法,执行效率越高。下面是各个算法在处理不同规模数据时的平均运行时间(单位:秒):

数据集规模 冒泡排序 选择排序 插入排序 希尔排序 归并排序 快速排序
10,000 10.12 1.40 0.05 0.02 0.01 0.01
20,000 41.02 5.76 0.19 0.06 0.02 0.02
30,000 93.87 13.25 0.32 0.11 0.03 0.03
40,000 168.95 23.93 0.47 0.14 0.04 0.04
50,000 265.15 37.36 0.66 0.19 0.05 0.06
60,000 383.54 54.44 0.96 0.27 0.06 0.07
70,000 523.95 74.54 1.28 0.35 0.08 0.09
80,000 700.53 97.47 1.71 0.46 0.10 0.12
90,000 900.76 124.07 2.17 0.59 0.12 0.14
100,000 1124.93 155.37 2.72 0.77 0.14 0.18

由上表可以看出,在处理相同规模的数据时,快速排序算法的表现最好,时间复杂度最低,所需时间最少。希尔排序的性能也表现得相当不错。而冒泡排序的时间复杂度最高,在处理大规模数据时效率极低。选择排序和插入排序的时间复杂度较高,效率也不如其他算法。

十、 总结与启示

10.1 总结

排序算法是计算机科学中非常基础和重要的算法,其目的是把一组无序的数据按照一定规则排成有序的数据序列。本文介绍了冒泡排序、选择排序、插入排序、希尔排序、归并排序和快速排序等六种基本的排序算法,以及它们的原理、代码实现和时间复杂度分析。

在时间效率上,快速排序是最快的排序算法,其时间复杂度为 O(nlogn)。但在数据规模比较小的情况下,插入排序和冒泡排序表现得更好。在空间效率上,插入排序是最好的,因为它只需要在数组中进行元素交换,而不需要额外使用数据结构。

另外,排序算法的实现不仅仅包括算法本身的复杂度,还需要考虑实现的复杂度。例如,使用递归实现快速排序会造成函数调用的开销,并且会消耗额外的内存。但如果使用迭代的方式实现快速排序,可以避免这些问题。

10.2 启示

排序算法是计算机科学非常基础和重要的算法。通过学习和掌握排序算法,我们可以深入理解算法的设计思想和性质,并且可以将这些思想和性质应用到其他的算法中。另外,在面试和竞赛中,对排序算法的掌握也是非常重要的。

在实际工作中,对于需要排序的数据,我们通常可以使用内置的排序函数或者第三方库进行排序。但对于一些特殊的需求,例如需要实现自定义的排序规则或者对大规模数据进行排序等,我们需要深入理解排序算法,并且根据数据规模、数据分布等因素选择合适的排序算法。

目录
相关文章
|
7天前
|
JavaScript NoSQL Java
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
151 96
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
|
5天前
|
机器学习/深度学习 存储 算法
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
近端策略优化(PPO)是深度强化学习中高效的策略优化方法,广泛应用于大语言模型的RLHF训练。PPO通过引入策略更新约束机制,平衡了更新幅度,提升了训练稳定性。其核心思想是在优势演员-评论家方法的基础上,采用裁剪和非裁剪项组成的替代目标函数,限制策略比率在[1-ϵ, 1+ϵ]区间内,防止过大的策略更新。本文详细探讨了PPO的基本原理、损失函数设计及PyTorch实现流程,提供了完整的代码示例。
109 10
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
|
12天前
|
存储 算法 Java
解锁“分享文件”高效密码:探秘 Java 二叉搜索树算法
在信息爆炸的时代,文件分享至关重要。二叉搜索树(BST)以其高效的查找性能,为文件分享优化提供了新路径。本文聚焦Java环境下BST的应用,介绍其基础结构、实现示例及进阶优化。BST通过有序节点快速定位文件,结合自平衡树、多线程和权限管理,大幅提升文件分享效率与安全性。代码示例展示了文件插入与查找的基本操作,适用于大规模并发场景,确保分享过程流畅高效。掌握BST算法,助力文件分享创新发展。
|
7天前
|
监控 算法 安全
内网桌面监控软件深度解析:基于 Python 实现的 K-Means 算法研究
内网桌面监控软件通过实时监测员工操作,保障企业信息安全并提升效率。本文深入探讨K-Means聚类算法在该软件中的应用,解析其原理与实现。K-Means通过迭代更新簇中心,将数据划分为K个簇类,适用于行为分析、异常检测、资源优化及安全威胁识别等场景。文中提供了Python代码示例,展示如何实现K-Means算法,并模拟内网监控数据进行聚类分析。
28 10
|
3天前
|
存储 监控 算法
探秘员工泄密行为防线:基于Go语言的布隆过滤器算法解析
在信息爆炸时代,员工泄密行为对企业构成重大威胁。本文聚焦布隆过滤器(Bloom Filter)这一高效数据结构,结合Go语言实现算法,帮助企业识别和预防泄密风险。通过构建正常操作“指纹库”,实时监测员工操作,快速筛查可疑行为。示例代码展示了如何利用布隆过滤器检测异常操作,并提出优化建议,如调整参数、结合日志分析系统等,全方位筑牢企业信息安全防线,守护核心竞争力。
|
25天前
|
存储 算法 安全
控制局域网上网软件之 Python 字典树算法解析
控制局域网上网软件在现代网络管理中至关重要,用于控制设备的上网行为和访问权限。本文聚焦于字典树(Trie Tree)算法的应用,详细阐述其原理、优势及实现。通过字典树,软件能高效进行关键词匹配和过滤,提升系统性能。文中还提供了Python代码示例,展示了字典树在网址过滤和关键词屏蔽中的具体应用,为局域网的安全和管理提供有力支持。
50 17
|
25天前
|
存储 人工智能 算法
解锁分布式文件分享的 Java 一致性哈希算法密码
在数字化时代,文件分享成为信息传播与协同办公的关键环节。本文深入探讨基于Java的一致性哈希算法,该算法通过引入虚拟节点和环形哈希空间,解决了传统哈希算法在分布式存储中的“哈希雪崩”问题,确保文件分配稳定高效。文章还展示了Java实现代码,并展望了其在未来文件分享技术中的应用前景,如结合AI优化节点布局和区块链增强数据安全。
|
27天前
|
算法 安全 Java
Java线程调度揭秘:从算法到策略,让你面试稳赢!
在社招面试中,关于线程调度和同步的相关问题常常让人感到棘手。今天,我们将深入解析Java中的线程调度算法、调度策略,探讨线程调度器、时间分片的工作原理,并带你了解常见的线程同步方法。让我们一起破解这些面试难题,提升你的Java并发编程技能!
66 16
|
1月前
|
存储 监控 算法
剖析基于Java算法驱动的智能局域网管控之道
本文探讨了基于Java语言的局域网控制方案,结合链表数据结构与令牌桶算法,解决设备管理和流量调度难题。通过链表灵活存储网络设备信息,实现高效设备管理;令牌桶算法则精准控制流量,确保网络平稳运行。二者相辅相成,为校园、企业等局域网提供稳固高效的控制体系,保障业务连续性和数据安全。
|
29天前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
61 6

热门文章

最新文章

推荐镜像

更多