Java实现常见排序算法的优化

Java实现常见排序算法的优化攻略

本文将介绍如何使用Java实现几种常见的排序算法并对其进行优化,提高算法效率。

常见排序算法的分类

常见的排序算法分为两类:

  1. 比较类排序: 直接通过比较元素大小来确定元素间的相对次序,如冒泡排序、选择排序、插入排序、希尔排序、归并排序和快速排序等。这类算法时间复杂度下限为Ω(nlogn),也是大多数排序算法的时间复杂度上限。
  2. 非比较类排序: 不直接比较元素的大小,而根据具体问题的特定要求,通过非比较的方法确定元素间的相对次序,如计数排序、桶排序、基数排序等。这类算法时间复杂度可以达到O(n)。

常见排序算法的实现与优化

冒泡排序

冒泡排序是一种简单的交换排序算法,时间复杂度为O(n^2)。其基本思想是将相邻的元素两两比较,如果前面的元素大于后面的元素则交换这两个元素的位置,直到没有任何一对数字需要比较。

普通实现:

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

优化1: 增加一个标志位,如果在一次排序中没有进行任何交换,则说明序列已具有有序性,排序提前结束。

public static void bubbleSort1(int[] arr) {
    boolean flag;
    for (int i = 0; i < arr.length - 1; i++) {
        flag = false;
        for (int j = 0; j < arr.length - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
                flag = true;
            }
        }
        if (!flag) {
            break;
        }
    }
}

优化2: 记录最后一次交换的位置,该位置以下的数据已经有序,无需再进行比较。

public static void bubbleSort2(int[] arr) {
    boolean flag;
    int lastExchangeIndex = 0;
    int sortBorder = arr.length - 1;
    for (int i = 0; i < arr.length - 1; i++) {
        flag = false;
        for (int j = 0; j < sortBorder; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
                flag = true;
                lastExchangeIndex = j;
            }
        }
        sortBorder = lastExchangeIndex;
        if (!flag) {
            break;
        }
    }
}

快速排序

快速排序是一种基于分治思想的排序算法,时间复杂度为O(nlogn)。其基本思想是选取一个数(一般为第一个数)作为基准,将小于基准的数放到其左边,大于基准的数放到其右边,然后再依次对左右两部分进行递归排序。

普通实现:

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

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

优化1: 选取基准点的方法可以优化,在序列的开头、结尾和中间位置各选取一个元素,取这三个数的中位数作为基准。

private static int median3(int[] arr, int left, int right) {
    int mid = left + (right - left) / 2;
    if (arr[left] > arr[mid]) {
        int temp = arr[left];
        arr[left] = arr[mid];
        arr[mid] = temp;
    }
    if (arr[left] > arr[right]) {
        int temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
    }
    if (arr[mid] > arr[right]) {
        int temp = arr[mid];
        arr[mid] = arr[right];
        arr[right] = temp;
    }
    int pivot = arr[mid];
    arr[mid] = arr[left];
    arr[left] = pivot;
    return pivot;
}

public static void quickSort1(int[] arr, int left, int right) {
    if (left < right) {
        int partitionIndex = partition1(arr, left, right);
        quickSort1(arr, left, partitionIndex - 1);
        quickSort1(arr, partitionIndex + 1, right);
    }
}

private static int partition1(int[] arr, int left, int right) {
    int pivot = median3(arr, left, right);
    int i = left;
    int j = right;
    while (i < j) {
        while (i < j && arr[j] >= pivot) {
            j--;
        }
        while (i < j && arr[i] <= pivot) {
            i++;
        }
        if (i < j) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    arr[left] = arr[i];
    arr[i] = pivot;
    return i;
}

优化2: 对于小规模的子序列,使用插入排序。

public static void quickSort2(int[] arr, int left, int right) {
    if (left < right) {
        if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
            insertionSort(arr, left, right);
        } else {
            int partitionIndex = partition1(arr, left, right);
            quickSort2(arr, left, partitionIndex - 1);
            quickSort2(arr, partitionIndex + 1, right);
        }
    }
}

private static void insertionSort(int[] arr, int left, int right) {
    for (int i = left + 1; i <= right; i++) {
        int temp = arr[i];
        int j = i - 1;
        while (j >= left && arr[j] > temp) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = temp;
    }
}

示例说明

示例1——冒泡排序

public static void main(String[] args) {
    int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1};
    System.out.println("排序前:" + Arrays.toString(arr));
    bubbleSort2(arr);
    System.out.println("排序后:" + Arrays.toString(arr));
}

输出结果:

排序前:[9, 8, 7, 6, 5, 4, 3, 2, 1]
排序后:[1, 2, 3, 4, 5, 6, 7, 8, 9]

示例2——快速排序

public static void main(String[] args) {
    int[] arr = {45, 99, 12, 19, 33, 78, 53, 46, 28, 89, 67, 56};
    System.out.println("排序前:" + Arrays.toString(arr));
    quickSort2(arr, 0, arr.length - 1);
    System.out.println("排序后:" + Arrays.toString(arr));
}

输出结果:

排序前:[45, 99, 12, 19, 33, 78, 53, 46, 28, 89, 67, 56]
排序后:[12, 19, 28, 33, 45, 46, 53, 56, 67, 78, 89, 99]

总结

通过对常见排序算法的优化,可以大大提高算法效率。在实际开发中要根据具体的需求和数据规模来选择合适的排序算法并进行优化。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java实现常见排序算法的优化 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Android数据库相关整理

    Android数据库相关整理 Android作为目前最为流行的智能手机操作系统之一,其应用程序的数据存储涉及到SQLite、Room等多个数据库框架,针对这些框架的使用规范及优势劣势进行整理,提供给开发者更好的选择。 SQLite SQLite是Android内置的轻量级关系型数据库,是一种无需单独安装,即可直接使用的文件型数据库;由于其体积小、速度较快,被…

    其他 2023年3月28日
    00
  • Mybatis中的config.xml配置文件详细解析

    Mybatis是一款非常流行的ORM框架,它的核心思想是将数据库操作映射成为Java方法,让开发者可以更加专注于业务逻辑的实现。而Mybatis的配置文件config.xml则是整个框架的重要组成部分,本文将对其进行一一讲解。 整体结构 Mybatis的config.xml配置文件整体结构非常简洁,分为configuration、properties、typ…

    other 2023年6月25日
    00
  • python中子类与父类的关系基础知识点

    我们来详细讲解一下Python中子类和父类的关系基础知识点。 基础知识点 在面向对象编程中,子类是继承父类的属性和方法的。父类也被称为基类或超类,子类也被称为派生类或衍生类。子类可以继承父类的所有属性和方法,并且还可以添加新的属性和方法,或者覆盖/修改父类中的属性和方法。 要定义一个子类,需要使用关键字class,然后在类名后面加上父类的名称,用圆括号括起来…

    other 2023年6月26日
    00
  • JavaScript之数组(Array)详解

    首先,让我们来了解一下”JavaScript之数组(Array)详解”这个主题的详细攻略: JavaScript之数组(Array)详解 什么是数组? 在JavaScript中,数组是一种数据类型,用于存储一组数据。数组中可以存储任何类型的数据,包括数字、字符串、对象等。 创建一个数组 在JavaScript中,可以使用以下两种方式来创建一个数组: 直接声明…

    other 2023年6月25日
    00
  • sqlserver将数据库的数据导成excel文档方法

    概述 在SQL Server中,可以将数据库的数据导出为Excel文档,以便于数据的备份和共享。本文将为您提供一份完整攻略,介绍如何将SQL Server数据库的数据导出为Excel文档。 导出SQL Server数据库数据为Excel文档 步骤1:连接SQL Server数据库 使用SQL Server Management Studio连接SQL Ser…

    other 2023年5月5日
    00
  • 详解用Tomcat服务器配置https双向认证过程实战

    详解用Tomcat服务器配置https双向认证过程实战 本文将详细讲解如何使用Tomcat服务器来配置HTTPS双向认证过程,主要分为以下几个步骤: 生成服务器端证书和私钥 生成客户端证书 配置Tomcat服务器 配置客户端 下面将分别详细说明每个步骤的具体操作。 1. 生成服务器端证书和私钥 首先,我们需要使用OpenSSL或者Java Keytool工具…

    other 2023年6月27日
    00
  • C语言 操作符#与##使用方法详解

    操作符与 ## 操作符是 C 语言预处理器中的两个重要操作符,其中 # 操作符用于将一个宏参数转换为对应的字符串,## 操作符则用于将两个宏参数合并成一个单独的标识符。下面将详细介绍它们的使用方法。 操作符的使用方法 以定义一个通用的结构体打印宏为例,该宏不仅可以输出结构体变量的值,还能输出该变量的类型。代码如下: #define print_struct(…

    other 2023年6月27日
    00
  • node.js-如何让npm使用缓存

    以下是关于“node.js-如何让npm使用缓存”的完整攻略,包括如何配置npm缓存、如何使用npm缓存以及两个示例。 如何配置npm缓存 npm缓存是一个本地缓存,用于存储已安装的npm包。可以通过以下步骤配置npm缓存: 打开终端或命令行窗口。 输入以下命令:npm config set cache <path-to-cache-directory…

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