Java 数据结构与算法系列精讲之排序算法

Java 数据结构与算法系列精讲之排序算法攻略

1. 序言

排序算法是计算机程序设计中常见的一类算法,主要用于将一组数据按照一定的顺序重新排列。在实际工作和面试中,排序算法是计算机程序员必须掌握的基本算法之一。本文将重点讲解 Java 数据结构与算法系列中的排序算法,其中包括冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序和堆排序。

2. 冒泡排序

冒泡排序是一种较为简单的排序方式,其基本思想是从头到尾比较相邻两元素的大小,并交换位置。在一次完整的冒泡过程中,将会把数字序列中最大的数“冒泡”到最后面。最好情况下时间复杂度为 O(n),最坏情况和平均情况时间复杂度均为 O(n²)。

示例:

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

3. 选择排序

选择排序和冒泡排序一样,都是简单的排序算法。它的基本思想是从未排序的序列中选择一个最小的元素存放到已排序序列的末尾,然后再从未排序序列中选择最小元素。最好情况、最坏情况和平均情况下时间复杂度均为 O(n²)。

示例:

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

4. 插入排序

插入排序方面,插入排序的基本思想是将一个记录插入到有序的序列中,从而得到一个新的序列。在插入排序过程中,记录从前往后依次插入,未排序的序列每次从前面取出一个元素,并插入到有序序列的相应位置中。最好情况时间复杂度为 O(n),最坏情况和平均情况时间复杂度均为 O(n²)。

示例:

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

5. 希尔排序

希尔排序是插入排序的一种优化版本。它通过缩小增量(增量序列的选择也有影响)来改变待排序序列中各元素的相对位置,从而达到排序的目的。希尔排序是非稳定排序,它的时间复杂度依据所选取的增量序列不同而不同,通常情况下它的时间复杂度都是 O(n log n) 级别的。

示例:

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 temp = arr[i];
            int j;
            for (j = i; j >= gap && temp < arr[j - gap]; j -= gap) {
                arr[j] = arr[j - gap];
            }
            arr[j] = temp;
        }
    }
}

6. 归并排序

归并排序采用先拆分再合并的递归方法,将序列分成若干个长度为1的子序列,然后再将它们两两合并,直接合并完成为止。归并排序是稳定排序,在排序过程中需要开辟一个与原数组大小相等的数组来辅助排序。时间复杂度是 O(n log n)。

示例:

public static void mergeSort(int[] arr, int l, int r) {
    if (l < r) {
        int m = (l + r) / 2;
        mergeSort(arr, l, m);
        mergeSort(arr, m + 1, r);
        merge(arr, l, m, r);
    }
}

public static void merge(int[] arr, int l, int m, int r) {
    int[] temp = new int[arr.length];
    int i = l, j = m + 1, k = l;
    while (i <= m && j <= r) {
        if (arr[i] < arr[j]) {
            temp[k++] = arr[i++];
        } else {
            temp[k++] = arr[j++];
        }
    }
    while (i <= m) {
        temp[k++] = arr[i++];
    }
    while (j <= r) {
        temp[k++] = arr[j++];
    }
    for (int x = l; x <= r; x++) {
        arr[x] = temp[x];
    }
}

7. 快速排序

快速排序是一种快速的排序方法,采用分而治之的思想,利用递归实现。它的基本思想就是选择一个基准元素,然后将序列分成两部分,分别对这两部分再进行快速排序,直到整个序列有序为止。快速排序是不稳定的排序方法,其时间复杂度平均情况下为 O(n log n)。

示例:

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

public static int partition(int[] arr, int low, int high) {
    int pivot = arr[low];
    while (low < high) {
        while (low < high && arr[high] >= pivot) {
            high--;
        }
        arr[low] = arr[high];
        while (low < high && arr[low] <= pivot) {
            low++;
        }
        arr[high] = arr[low];
    }
    arr[low] = pivot;
    return low;
}

8. 堆排序

堆排序是一种树形选择排序方法,其基本思想是将待排序的序列构建成一个大根堆或小根堆,依次取出最大或最小元素放到根节点中,再对剩余的元素重新构造堆,直到整个序列有序为止。堆排序是一种不稳定的排序方法,其平均时间复杂度为 O(n log n),空间复杂度为 O(1)。

示例:

public static void heapSort(int[] arr) {
    int n = arr.length;
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapify(arr, n, i);
    }
    for (int i = n - 1; i >= 0; i--) {
        int temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;
        heapify(arr, i, 0);
    }
}

public static void heapify(int[] arr, int n, int i) {
    int largest = i;
    int l = 2 * i + 1;
    int r = 2 * i + 2;
    if (l < n && arr[l] > arr[largest]) {
        largest = l;
    }
    if (r < n && arr[r] > arr[largest]) {
        largest = r;
    }
    if (largest != i) {
        int temp = arr[i];
        arr[i] = arr[largest];
        arr[largest] = temp;
        heapify(arr, n, largest);
    }
}

9. 总结

通过本文对 Java 数据结构与算法系列中的排序算法的讲解,我们可以了解到不同的排序算法的原理、时间复杂度和空间复杂度等方面的知识。其中包括了冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序和堆排序等七种基本排序算法,希望这篇文章能为你理解和掌握排序算法提供帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java 数据结构与算法系列精讲之排序算法 - Python技术站

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

相关文章

  • Java中父类Object的常用方法总结

    Java中父类Object的常用方法总结 在Java中,所有类都直接或间接继承自Object类。因此,Object类中的方法可以在所有Java类中使用。Object类中提供的方法包括: toString方法 toString方法是将对象转换成字符串的方法,在Java当中可以非常方便地输出一个对象的信息。当我们打印一个对象时,实际上是调用了该对象的toStri…

    other 2023年6月27日
    00
  • 详解Python函数作用域的LEGB顺序

    详解Python函数作用域的LEGB顺序 在Python中,函数作用域是指变量的可见性和访问性。Python使用LEGB规则来确定变量的作用域,即Local(局部)、Enclosing(嵌套)、Global(全局)和Built-in(内置)的顺序。下面将详细解释每个作用域的含义和查找顺序。 Local(局部)作用域 局部作用域是指在函数内部定义的变量。这些变…

    other 2023年8月19日
    00
  • ora-00942:表或视图不存在’的原因和解决方法[转]

    ‘ORA-00942:表或视图不存在’的原因和解决方法 在使用Oracle数据库时,我们经常会遇到这样的提示信息:“ORA-00942:表或视图不存在”。那么,这个错误信息出现的原因是什么?应该如何解决呢?下面,本文将为大家详细介绍。 错误信息原因解析 产生ORA-00942错误的原因,是因为SQL语句中引用了一个不存在的表名或视图名。也就是说,要么表或视图…

    其他 2023年3月28日
    00
  • 教你如何保持UC浏览器版本始终最新并删除臃肿的文件

    教你如何保持UC浏览器版本始终最新并删除臃肿的文件攻略 UC浏览器是一款广受欢迎的移动浏览器,为了保持其性能和安全性,我们需要经常更新版本并删除不必要的文件。下面是一份详细的攻略,教你如何保持UC浏览器版本始终最新并删除臃肿的文件。 步骤一:检查UC浏览器版本 首先,我们需要检查当前安装的UC浏览器版本是否是最新的。请按照以下步骤进行操作: 打开UC浏览器。…

    other 2023年8月5日
    00
  • R语言数据类型深入详解

    R语言数据类型深入详解 介绍 本篇文章旨在深入探讨 R 语言中的数据类型,为读者提供对 R 语言数据类型的更深刻的认识。本文将分别介绍 R 语言中的基本数据类型、数据结构类型、向量类型、矩阵类型、数组类型、列表类型、数据框类型以及因子类型等数据类型。同时,我们也将结合代码示例,让读者更好地理解和掌握这些数据类型。 基本数据类型 数值型 在 R 语言中,数值型…

    other 2023年6月27日
    00
  • oppok9x怎么进入开发模式 进入开发模式的教程

    接下来我将详细讲解如何进入oppok9x的开发模式,并提供两个示例说明: 一、进入开发模式的步骤 在oppok9x手机上,打开“设置”应用程序; 在设置页面中,向下滑动并点击“关于手机”选项; 在关于手机页面中,找到“版本号”一项,接着迅速点击8-10次,直到弹出“开发者选项已启用”的提示; 此时,在“设置”应用程序中会出现“开发者选项”选项,其中包含了一些…

    other 2023年6月26日
    00
  • SQL 判断字段类型语句

    SQL(Structured Query Language,结构化查询语言)是一种用于管理关系数据库管理系统的语言。在SQL中,判断字段类型的语句主要是通过使用数据字典中的表来查询字段信息,并获取字段类型的相关信息。 下面是使用SQL语句判断字段类型的完整攻略: 查看表信息获取字段信息 首先可以查看数据字典中的information_schema数据库,该数…

    other 2023年6月25日
    00
  • win10正式版怎么激活?win10正式版激活工具下载地址

    Win10正式版激活攻略 激活Windows 10正式版是确保您的操作系统合法使用的重要步骤。以下是一个详细的攻略,包括两个示例说明,以帮助您完成激活过程。 步骤1:使用产品密钥激活 首先,您需要获得一个有效的Windows 10产品密钥。您可以在购买Windows 10时获得密钥,或者如果您已经购买了Windows 10,可以在产品包装盒或电子邮件中找到密…

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