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日

相关文章

  • 浅析JS获取url中的参数实例代码

    首先,获取URL中的参数是Web开发经常需要的功能。JavaScript提供了多种方式可以获取URL参数,本文将介绍其中两种最常见的方式:URLSearchParams和正则表达式。 使用URLSearchParams URLSearchParams是一个原生对象,主要用来操作URL查询参数。使用URLSearchParams获取URL参数非常方便。 我们可…

    Java 2023年6月15日
    00
  • 个人小程序接入支付解决方案

    接下来为您详细讲解“个人小程序接入支付解决方案”的完整攻略。 一、前提准备 为了成功接入支付,我们需要满足以下前提条件: 小程序已经获得认证 小程序拥有自己的“支付商户号” 小程序已经做好了“小程序支付开通”和“支付证书配置” 小程序后台已经开启“JSAPI支付方式” 二、接入支付解决方案 接下来,我们可以分别按照以下几步来完成个人小程序的支付接入: 1. …

    Java 2023年5月23日
    00
  • mybatis快速上手并运行程序

    MyBatis快速上手指南 MyBatis是一个持久化框架,可以帮助Java开发人员快速高效地进行数据库操作。本文将介绍如何快速上手MyBatis并运行程序。 环境准备 安装Java环境(JDK),版本需大于等于1.8 安装并配置Maven,用于管理项目依赖 准备一个MySQL数据库 步骤 1. 创建Maven项目 使用以下命令在本地创建一个Maven项目:…

    Java 2023年5月20日
    00
  • 使用Spring安全表达式控制系统功能访问权限问题

    使用Spring安全表达式可以通过在方法执行前进行鉴权,从而控制系统功能的访问权限。下面是使用Spring安全表达式控制系统功能访问权限的完整攻略: 引入Spring Security依赖 在Maven项目的POM文件中,引入Spring Security依赖: <dependency> <groupId>org.springfram…

    Java 2023年5月20日
    00
  • Java读写文件,在文件中搜索内容,并输出含有该内容的所有行方式

    下面是“Java读写文件,在文件中搜索内容,并输出含有该内容的所有行方式”的完整攻略: 读取文件 Java提供了多种读取文件的方式,其中比较常用的是使用FileInputStream或者BufferedReader类进行文件读取。下面是使用BufferedReader读取文件的示例代码: try (BufferedReader reader = new Bu…

    Java 2023年5月26日
    00
  • springmvc处理模型数据ModelAndView过程详解

    下面为您详细讲解“SpringMVC处理模型数据ModelAndView过程详解”的完整攻略。 1. 什么是SpringMVC处理模型数据ModelAndView? 在SpringMVC中,控制器返回的数据可以是很多类型,其中之一即为ModelAndView类型。ModelAndView是一个包含了模型数据和视图名的数据结构,它用于将处理器方法需要的内容以及…

    Java 2023年6月15日
    00
  • Java解析XML(4种方式)案例详解

    Java解析XML(4种方式)案例详解 1. Java解析XML的概念 在Java开发中,我们经常需要读取和修改一些XML格式的文件。XML全称为Extensible Markup Language(可扩展标记语言),是W3C组织推出的标记语言。 XML是一种纯文本格式,用来描述数据。它通过标签的方式来组织数据,标签包含了属性和值,这些在XML文件中都可以很…

    Java 2023年5月19日
    00
  • 使用Java打印数字组成的魔方阵及字符组成的钻石图形

    下面我详细讲解一下“使用Java打印数字组成的魔方阵及字符组成的钻石图形”的完整攻略。 打印数字组成的魔方阵 思路 魔方阵是由 $n^2$ 个数字组成的方阵,其中每一行、每一列、每一条对角线上的数字之和都相等。我们可以使用以下的算法来生成 $n \times n$ 的魔方阵: 将数字 1 放在第一行的中间列。 依次将后续的数字放入前一个数字的右上角(如果已经…

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