数据结构第19节 排序算法(1)

冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

冒泡排序步骤详解

假设我们有以下数组:

复制代码
int[] arr = {64, 34, 25, 12, 22, 11, 90};

第一轮冒泡排序

初始数组 比较 结果
64 64 > 34 34, 64
34 64 > 25 34, 25, 64
25 64 > 12 34, 25, 12, 64
12 64 > 22 34, 25, 12, 22, 64
22 64 > 11 34, 25, 12, 22, 11, 64
11 64 > 90 (不变)
最后,64 和 90 比较 34, 25, 12, 22, 11, 64, 90

第一轮结束后,最大的元素90已经到达了正确的位置。

第二轮冒泡排序

初始数组 比较 结果
34 34 > 25 25, 34
25 34 > 12 25, 12, 34
12 34 > 22 25, 12, 22, 34
22 34 > 11 25, 12, 22, 11, 34
11 (不变)
最后,34 和 90 不需要比较,因为90已经在正确的位置

第二轮结束后,次大的元素64已经到达了正确的位置。

在冒泡排序的过程中,每一轮都会把当前未排序部分的最大值"浮"到正确的位置。在前两轮之后,我们已经有了最大值90和次大值64在正确的位置。接下来,我们展示第三轮冒泡排序的详细过程。

假设我们有以下数组:

复制代码
int[] arr = {34, 25, 12, 22, 11, 64, 90};

第三轮冒泡排序

初始数组 比较 结果
34 34 > 25 25, 34
25 34 > 12 25, 12, 34
12 34 > 22 25, 12, 22, 34
22 34 > 11 25, 12, 22, 11, 34
11 (不变)
最后,34 和 64 不需要比较,因为64已经在正确的位置

在这一轮结束时,数组的状态如下:

复制代码
arr = {25, 12, 22, 11, 34, 64, 90};

可以看到,经过第三轮的冒泡,数组中的第三大的值34已经移动到了它的正确位置,即数组的倒数第三位。

第四轮冒泡排序

初始数组 比较 结果
25 25 > 12 12, 25
12 25 > 22 12, 22, 25
22 25 > 11 12, 22, 11, 25
11 (不变)

在这一轮结束时,数组的状态如下:

复制代码
arr = {12, 22, 11, 25, 34, 64, 90};

第五轮冒泡排序

初始数组 比较 结果
12 12 > 11 11, 12
11 (不变)

在这一轮结束时,数组的状态如下:

复制代码
arr = {11, 12, 22, 25, 34, 64, 90};

此时,数组已经完全排序,所有元素都在它们应该在的位置上。

需要注意的是,冒泡排序的优化版本会在一轮遍历中如果没有发生任何交换则停止排序,这意味着数组已经是有序的。在这个例子中,第五轮排序完成后,数组已经是升序排列,所以后续的遍历将不会发生任何变化。

最终的排序结果应该是:

复制代码
arr = {11, 12, 22, 25, 34, 64, 90};

冒泡排序的Java代码实现

下面是使用Java实现冒泡排序的代码:

java 复制代码
public class BubbleSortExample {
    public static void main(String[] args) {
        int[] arr = {64, 34, 25, 12, 22, 11, 90};

        bubbleSort(arr);

        System.out.println("Sorted array : ");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }

    static void bubbleSort(int[] arr) {
        int n = arr.length;
        boolean swapped;
        for (int i = 0; i < n - 1; i++) {
            swapped = false;
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    // Swap arr[j+1] and arr[j]
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    swapped = true;
                }
            }
            // 如果在某次遍历中没有发生任何交换,说明数组已经排序完成
            if (!swapped)
                break;
        }
    }
}

在这段代码中,我们使用了两层循环。外层循环控制排序的轮数,内层循环负责比较和交换相邻的元素。如果在某次遍历中没有发生任何交换,说明数组已经排序完成,此时可以提前终止排序,以节省不必要的比较。这是冒泡排序的一个优化点。

选择排序(Selection Sort)是一种简单直观的比较排序算法。它的工作原理是遍历数组,每次从未排序的部分找出最小(或最大)的元素,存放到排序序列的起始位置,直到所有元素均排序完毕。

选择排序步骤详解

假设我们有以下数组:

复制代码
int[] arr = {64, 34, 25, 12, 22, 11, 90};

第一轮选择排序

步骤 描述
初始 遍历整个数组寻找最小值
比较 64 vs 34 vs 25 vs 12 vs 22 vs 11 vs 90
结果 发现 11 是最小值
交换 将 11 与第一个元素 64 交换位置

第二轮选择排序

步骤 描述
初始 从第二个元素开始遍历寻找最小值
比较 64 vs 34 vs 25 vs 12 vs 22 vs 90
结果 发现 12 是最小值
交换 将 12 与第二个元素 64 交换位置

第三轮选择排序

步骤 描述
初始 从第三个元素开始遍历寻找最小值
比较 34 vs 25 vs 22 vs 90
结果 发现 22 是最小值
交换 将 22 与第三个元素 34 交换位置

依此类推,直到整个数组排序完成

选择排序的Java代码实现

下面是使用Java实现选择排序的代码:

java 复制代码
public class SelectionSortExample {
    public static void main(String[] args) {
        int[] arr = {64, 34, 25, 12, 22, 11, 90};
        
        selectionSort(arr);
        
        System.out.println("Sorted array : ");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }

    static void selectionSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            // Find the minimum element in unsorted array
            int minIndex = i;
            for (int j = i + 1; j < n; j++) {
                if (arr[minIndex] > arr[j]) {
                    minIndex = j;
                }
            }
            // Swap the found minimum element with the first element
            int temp = arr[minIndex];
            arr[minIndex] = arr[i];
            arr[i] = temp;
        }
    }
}

在这段代码中,我们使用了两层循环。外层循环迭代整个数组,而内层循环则用于找到剩余未排序部分的最小元素。一旦找到了最小元素,我们就将其与未排序部分的第一个元素交换。这样,每一次外层循环的迭代都会将未排序部分的最小元素放置到正确的位置上。

性能分析

选择排序的时间复杂度为O(n^2),无论在最好、最坏还是平均情况下都是如此。这是因为对于n个元素的数组,需要进行n次查找最小值的操作,每次查找都需要遍历剩下的元素,所以总的操作次数大约是n*(n-1)/2。尽管其实现简单,但在大数据量的情况下,选择排序的效率较低。

插入排序(Insertion Sort)是一种简单直观的排序算法,其工作原理类似于人们手动排序扑克牌的方式。在插入排序中,数组被分为已排序和未排序两部分。初始时,已排序部分只包含第一个元素,未排序部分包含剩余的所有元素。算法通过从未排序部分取出一个元素,并在已排序部分找到正确的位置将其插入,逐步扩大已排序部分的范围,直至整个数组排序完成。

插入排序步骤详解

假设我们有以下数组:

复制代码
int[] arr = {64, 34, 25, 12, 22, 11, 90};

第一轮插入排序

步骤 描述
初始 已排序部分:64,未排序部分:34, 25, 12, 22, 11, 90
插入 将 34 插入到已排序部分的适当位置
结果 已排序部分变为:34, 64

第二轮插入排序

步骤 描述
初始 已排序部分:34, 64,未排序部分:25, 12, 22, 11, 90
插入 将 25 插入到已排序部分的适当位置
结果 已排序部分变为:25, 34, 64

第三轮插入排序

步骤 描述
初始 已排序部分:25, 34, 64,未排序部分:12, 22, 11, 90
插入 将 12 插入到已排序部分的适当位置
结果 已排序部分变为:12, 25, 34, 64

依此类推,直到整个数组排序完成

插入排序的Java代码实现

下面是使用Java实现插入排序的代码:

java 复制代码
public class InsertionSortExample {
    public static void main(String[] args) {
        int[] arr = {64, 34, 25, 12, 22, 11, 90};
        
        insertionSort(arr);
        
        System.out.println("Sorted array : ");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }

    static void insertionSort(int[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; ++i) {
            int key = arr[i];
            int j = i - 1;
            
            /* Move elements of arr[0..i-1], that are greater than key,
               to one position ahead of their current position */
            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = key;
        }
    }
}

在这段代码中,我们使用了一个循环来迭代数组中的每个元素,除了第一个元素外(因为单个元素自动认为是已排序的)。对于每个元素,我们将其保存在一个变量key中,然后在已排序的部分中找到它的正确位置,并将所有比key大的元素向右移动一位,为key腾出空间,最后将key插入到正确的位置。

性能分析

插入排序的时间复杂度在最好情况(数组已经是排序的)下为O(n),在最坏情况(数组是逆序的)和平均情况下为O(n^2)。尽管对于大规模数据而言效率较低,但对于小规模数据或部分已排序的数据,插入排序的性能仍然相当不错。

相关推荐
小羊没烦恼!5 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
倒头就睡的小比特5 天前
算法竞赛C++常用的STL
c++·算法
俊昭喜喜里5 天前
java中的继承和多态的区别
java
小羊没烦恼!5 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕5 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码5 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖5 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时5 天前
01-06-A-JVM排查实战详解
java·jvm
猎头南楼5 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
vipxieliang5 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot