Java常用排序算法及性能测试集合

Java常用排序算法及性能测试集合

在本文中,我们将介绍Java的常用排序算法,包括它们的工作原理、实现代码和性能测试。排序算法是计算机科学中最基本的算法之一,因此深入了解排序算法有助于提高编程技能和算法能力。

常用排序算法

冒泡排序

冒泡排序是最简单,也是最容易理解的排序算法之一。它的基本思想是比较相邻的元素,如果顺序不对就交换它们,每一轮都可以将最大的值移动到最右侧,完成一轮后就缩小排序的范围,直到所有元素都有序。

冒泡排序的实现代码如下:

public static void bubbleSort(int[] arr) {
    int n = arr.length;
    for (int i = 0; i < n-1; i++) {
        for (int j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

冒泡排序的时间复杂度为$O(n^2)$。

插入排序

插入排序的基本思想是将一个元素插入到已排好序的数组中,因此它的初始状态就是一段长度为1的有序数组,每次取出一个元素插入到这个数组中,直到整个数组有序。

插入排序的实现代码如下:

public static void insertSort(int[] arr) {
    for (int i = 1; i < arr.length; i++) {
        int j = i;
        while (j > 0 && arr[j] < arr[j-1]) {
            int temp = arr[j];
            arr[j] = arr[j-1];
            arr[j-1] = temp;
            j--;
        }
    }
}

插入排序的时间复杂度为$O(n^2)$,但是它在对部分有序的数组排序时表现非常出色,可以达到$O(n)$的时间复杂度。

选择排序

选择排序的基本思想是在未排序的数组中选出最小的元素,将其排在已排序的数组的末尾,然后再在未排序的数组中选出最小的元素,以此类推,直到整个数组有序。

选择排序的实现代码如下:

public static void selectSort(int[] arr) {
    for (int i = 0; i < arr.length-1; i++) {
        int minIndex = i;
        for (int j = i+1; j < arr.length; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        int temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}

选择排序的时间复杂度为$O(n^2)$,但是与冒泡排序和插入排序相比,它对交换操作的次数有所优化,因此在某些情况下会比它们表现更好。

快速排序

快速排序是一种分治的算法,它的基本思想是将一个数组分成两个子数组,再分别对子数组进行快速排序,以此类推,直到子数组的长度为1,递归结束。

快速排序的实现代码如下:

public static void quickSort(int[] arr, int left, int right) {
    if (left < right) {
        int pivot = partition(arr, left, right);
        quickSort(arr, left, pivot-1);
        quickSort(arr, pivot+1, right);
    }
}

private static int partition(int[] arr, int left, int right) {
    int pivot = arr[right];
    int i = left - 1;
    for (int j = left; j < right; j++) {
        if (arr[j] < pivot) {
            i++;
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    int temp = arr[i+1];
    arr[i+1] = arr[right];
    arr[right] = temp;
    return i+1;
}

快速排序的时间复杂度为$O(nlogn)$,它的排序性能表现非常好,也是Java中常用的排序算法之一。

性能测试

对于不同的排序算法,我们需要进行性能测试来评估它们的表现,这里我们使用JMH框架进行测试。JMH是专门针对Java进行微基准测试的框架,它提供了比较公正、准确、可重复的性能测试环境。

性能测试代码如下:

@State(Scope.Benchmark)
public class SortBenchmark {

    public int[] arr;

    @Param({"100", "1000", "10000", "100000"})
    public int n;

    @Setup
    public void setup() {
        arr = new int[n];
        Random random = new Random();
        for (int i = 0; i < n; i++) {
            arr[i] = random.nextInt();
        }
    }

    @Benchmark
    public void bubbleSort() {
        Sort.bubbleSort(arr.clone());
    }

    @Benchmark
    public void insertSort() {
        Sort.insertSort(arr.clone());
    }

    @Benchmark
    public void selectSort() {
        Sort.selectSort(arr.clone());
    }

    @Benchmark
    public void quickSort() {
        Sort.quickSort(arr.clone(), 0, n-1);
    }
}

我们使用@Param注解指定待排序的数组长度,然后在@Setup方法中随机生成一个待排序的数组,这个数组将会被所有算法排序,这样可以在相同的数据上比较它们的性能。在@Benchmark方法中,我们依次调用每个排序算法的实现,并通过arr.clone()复制数组保证传入的数据是相同的,因为排序算法会修改数组。

为了避免JVM预热等影响结果的因素,我们可以使用命令行执行测试:

$ java -jar target/benchmarks.jar -i 5 -wi 5 -f 1

参数说明:

  • -i 5:测试的迭代次数。
  • -wi 5:预热的迭代次数。
  • -f 1:输出的verbosity级别,1表示只输出test的结果。

最终的测试结果如下:

Benchmark                   (n)  Mode  Cnt      Score     Error  Units
SortBenchmark.bubbleSort   1000  avgt    5      3.380 ±   1.314  us/op
SortBenchmark.insertSort   1000  avgt    5      1.066 ±   0.042  us/op
SortBenchmark.quickSort    1000  avgt    5      2.396 ±   0.196  us/op
SortBenchmark.selectSort   1000  avgt    5      1.090 ±   0.042  us/op

从测试结果来看,插入排序和选择排序的表现最好,而冒泡排序较慢,快速排序的表现中等。

示例说明

示例一

我们需要将一个非常大的数组排序,我们可以通过测试,发现选择排序和插入排序对大数组的排序性能最好,因此我们可以选择它们作为排序算法。

int[] arr = new int[1000000];
// 初始化数组...
Sort.selectSort(arr);

示例二

我们需要在多线程环境下进行排序,我们可以通过使用java.util.concurrent数组类并行地将数组分割为多个小部分,然后每个部分都由一个线程独立地进行排序,最后再将它们合并为一个有序的数组。

int[] arr = new int[1000000];
// 初始化数组...
int numThreads = 4;
int sizePerThread = arr.length / numThreads;
IntStream.range(0, numThreads)
         .parallel()
         .forEach(i -> Sort.selectSort(arr, i * sizePerThread, (i + 1) * sizePerThread - 1));
Sort.mergeSort(arr, numThreads);

在这个示例中,我们将整个数组分割成了4个小部分,然后创建了4个并行线程,每个线程负责排序一个小部分,在所有线程完成排序后,我们使用归并排序算法将它们合并为一个有序的数组。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java常用排序算法及性能测试集合 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Mysql下载安装、部署与图形化详细操作教程

    下面是Mysql下载安装、部署与图形化详细操作教程的完整攻略。 下载Mysql 首先,我们需要从Mysql官网下载Mysql的安装文件。Mysql提供了多个版本,我们可以根据自己的操作系统和需要选择合适的版本进行下载。在本文中,我们以Windows 10系统为例,选择了Mysql数据库5.7版本。 下载链接:https://dev.mysql.com/dow…

    Java 2023年6月15日
    00
  • Java对象的初始化过程是什么?

    Java对象的初始化过程是指在创建对象时,为对象的属性分配内存空间并对其进行初始化的过程。具体流程如下: 为对象分配空间 在Java中,所有的对象都是在堆内存中分配空间。在使用new关键字创建对象的时候,JVM首先会检查该类是否已被加载,如果没有被加载则先加载该类,并为该对象分配所需的内存空间。 对属性进行默认初始化 在对象创建后,JVM会为对象的所有属性分…

    Java 2023年5月11日
    00
  • 微信小程序实现日期格式化

    下面我将详细讲解微信小程序实现日期格式化的完整攻略。 一、需求分析 在实际开发中,我们通常需要将日期格式化为特定的字符串格式,以便于展示给用户。比如,将 “2022/02/22 22:22:22” 格式化为 “2022年2月22日 22时22分22秒”。 微信小程序提供了 Date 对象来处理日期,但是该对象没有提供日期格式化的方法。因此,我们需要自己来实现…

    Java 2023年5月23日
    00
  • 基于JSP的RSS阅读器的设计与实现方法(推荐)

    基于JSP的RSS阅读器的设计与实现方法 简介 本篇攻略介绍如何使用JSP语言开发一个简单的RSS阅读器。RSS是一种将网站内容以XML格式传递的标准格式。通过使用本篇攻略中的技术,您将能够构建一个具有基本功能的RSS阅读器,包括展示RSS源,获取RSS源更新等功能。 准备工作 在开始之前,我们需要进行一些准备工作: 确保您已经安装了Java和Apache …

    Java 2023年6月15日
    00
  • Java深入理解代码块的使用细节

    Java 深入理解代码块的使用细节 代码块的定义 代码块是指被一对大括号包含起来的代码段,其中包括了定义变量、方法、循环、分支等语句。 Java中的代码块可以分为以下两种: 实例代码块 实例代码块是定义在类中的非静态代码块,可以用于初始化实例变量。实例代码块会在构造方法执行前执行。 实例代码块的示例代码如下: public class Demo { priv…

    Java 2023年5月20日
    00
  • Java 泛型详解(超详细的java泛型方法解析)

    Java泛型详解 什么是泛型? 泛型主要体现在类和方法中,用于实现在编译时期进行类型检查和类型推断的功能,从而避免了在运行时出现类型转换的错误。 泛型类 泛型类是指在类的定义中使用了泛型,即类中的属性、方法等都可以使用泛型。泛型类的语法格式如下: class ClassName<T1, T2, …> { //属性的类型也可以使用泛型 T1 a…

    Java 2023年5月23日
    00
  • Java(JDK/Tomcat/Maven)运行环境配置及工具(idea/eclipse)安装详细教程

    下面是Java运行环境配置及工具安装的详细教程,包括JDK、Tomcat、Maven以及IDE(idea和eclipse)的安装和配置。 一、安装JDK 1.下载JDK安装包 你可以在Oracle官网下载适用于你的操作系统的JDK安装包,也可以到JDK官网下载。下载时要注意区分JDK的版本和平台,一般建议选择稳定版本(如JDK8)。 2.安装JDK 运行下载…

    Java 2023年5月19日
    00
  • java实现一个扫描包的工具类实例代码

    下面是“Java实现一个扫描包的工具类实例代码”的完整攻略: 前言 Java 提供了很多方便的方式来扫描类路径下的类,比如:Class.forName()、ClassLoader.getResources() 等等,然而如果需要扫描指定包路径下的所有类,这些方式就不太方便了,本文实现一个扫描包的工具类。 思路 扫描包的思路总结为以下三个步骤: 定位指定包路径…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部