排序算法全景:从基础到高级的Java实现

🌟 前言

欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍

  • 🤖 洛可可白:个人主页

  • 🔥 个人专栏:✅前端技术 ✅后端技术

  • 🏠 个人博客:洛可可白博客

  • 🐱 代码获取:bestwishes0203

  • 📷 封面壁纸:洛可可白wallpaper

在这里插入图片描述

文章目录

  • 排序算法全景:从基础到高级的Java实现
    • 插入排序:理解排序的核心思想
      • 什么是插入排序?
      • 插入排序的Java实现
      • 程序的执行
      • 插入排序的核心思想
      • 结语
    • 希尔排序:一种高效的改进版插入排序
      • 希尔排序简介
      • Java实现希尔排序
      • 测试希尔排序
      • 希尔排序的核心思想
      • 结语
    • 归并排序:优雅的分而治之艺术
      • 归并排序的基本概念
      • Java实现归并排序
      • 测试归并排序
      • 归并排序的核心思想
      • 结语
    • 快速排序:分而治之的高效排序算法
      • 快速排序的基本概念
      • Java实现快速排序
      • 快速排序的核心思想
      • 快速排序的性能
      • 结语
    • 选择排序:简单而直观的排序算法入门
      • 选择排序的工作原理
      • Java实现选择排序
      • 选择排序的特点
      • 结语
    • 生成测试数据和输出测试数据的类

排序算法全景:从基础到高级的Java实现

排序算法是计算机科学中的一个基础概念,它在数据处理和信息检索中扮演着至关重要的角色。本文将通过几个简单的Java程序,带你了解几种常见的排序算法:插入排序、希尔排序、归并排序、快速排序和选择排序,以及一个用于生成和打印测试数据的工具类。

插入排序:理解排序的核心思想

什么是插入排序?

插入排序(Insertion Sort)算法是一种直观且易于理解的排序方法。插入排序的工作原理类似于我们整理扑克牌的方式。想象一下,你手中有一堆未排序的扑克牌,你将它们一张张插入到已经排序好的牌堆中。插入排序算法正是基于这样的思想:它将数组分为已排序和未排序两部分,然后逐个将未排序部分的元素插入到已排序部分的适当位置。

插入排序的Java实现

让我们通过一个Java程序来具体看看插入排序是如何工作的。这个程序定义了一个名为 _01_InsertionSort 的类,其中包含了排序方法和一些辅助函数。

public class _01_InsertionSort {
    public static void sort(Comparable[] arr) {
        int n = arr.length;
        for (int i = 0; i < n; i++) {
            // 寻找元素arr[i]合适的插入位置
            for (int j = i; j > 0; j--) {
                if (arr[j].compareTo(arr[j - 1]) < 0) {
                    swap(arr, j, j - 1);
                } else {
                    break;
                }
            }
        }
    }

    private static void swap(Object[] arr, int i, int j) {
        Object t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
}

在这个类中,sort 方法接受一个可比较的对象数组 arr 作为参数。方法的核心是一个双重循环:外层循环遍历数组的每个元素,内层循环则负责将当前元素与已排序部分的元素进行比较,并在必要时进行交换。

swap 方法是一个辅助函数,用于交换数组中的两个元素。这是在内层循环中,当我们发现需要将一个元素插入到它之前的位置时调用的。

程序的执行

程序的 main 方法首先生成了一个包含20000个随机整数的数组,然后调用 sort 方法对数组进行排序,最后打印出排序后的数组。

public static void main(String[] args) {
    int N = 20000;
    Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000);
    _01_InsertionSort.sort(arr);
    for (int i = 0; i < arr.length; i++) {
        System.out.print(arr[i]);
        System.out.print(' ');
    }
}

插入排序的核心思想

插入排序的核心思想是分而治之。它将排序问题分解为更小的部分,然后逐个解决。这种方法在数据量较小或者数据基本有序的情况下非常有效,因为它可以减少不必要的比较和交换操作。

结语

通过这个简单的Java程序,我们不仅学习了插入排序算法的实现,还理解了排序算法的一般思想。虽然插入排序在处理大数据集时可能不是最高效的选择,但它的简单性和直观性使其成为理解排序概念的一个良好起点。随着你对算法的深入学习,你将能够掌握更多高级的排序技术,以应对更复杂的数据处理挑战。

希尔排序:一种高效的改进版插入排序

希尔排序(Shell Sort)是一种对传统插入排序的改进,它通过引入间隔(gap)的概念来提高排序的效率。

希尔排序简介

希尔排序是由Donald Shell在1959年提出的一种排序算法。它基于插入排序,通过将原始数据集分割成若干个子序列来排序,这些子序列的元素间隔逐渐减小,最后合并为一个有序的序列。

Java实现希尔排序

让我们通过一个简单的Java程序来实现希尔排序。

public class _02_ShellSort {
    public static void sort(Comparable[] arr) {
        // 初始化间隔
        int gap = arr.length / 2;
        // 当间隔大于0时,执行排序
        while (gap > 0) {
            // 遍历数组,间隔为gap
            for (int i = gap; i < arr.length; i++) {
                // 临时存储当前元素
                Comparable tmp = arr[i];
                // 对于每个间隔内的元素,进行插入排序
                for (int j = i; j >= gap && tmp.compareTo(arr[j - gap]) < 0; j -= gap) {
                    // 将较大的元素向后移动
                    arr[j] = arr[j - gap];
                }
                // 将当前元素放到正确的位置
                arr[j] = tmp;
            }
            // 缩小间隔,进行下一轮排序
            gap /= 2;
        }
    }
}

在这个实现中,我们首先计算一个初始间隔 gap,然后通过一个循环来逐渐减小这个间隔。在每次循环中,我们对间隔为 gap 的元素进行插入排序。随着间隔的减小,排序的粒度逐渐变细,最终整个数组变得有序。

测试希尔排序

为了测试我们的希尔排序算法,我们在 main 方法中生成了一个包含2000个随机整数的数组,并对其进行排序。

public static void main(String[] args) {
    int N = 2000;
    Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 10);
    _02_ShellSort.sort(arr);
    // 打印排序后的数组
    for (int i = 0; i < arr.length; i++) {
        System.out.print(arr[i]);
        System.out.print(' ');
    }
}

希尔排序的核心思想

希尔排序的核心在于分而治之的策略。它不是一次性对整个数组进行排序,而是先对数组的子序列进行排序,然后逐步缩小子序列的范围,直到整个数组有序。这种方法在处理部分有序的数据时特别有效,因为它可以减少不必要的比较和交换操作。

结语

通过这个Java程序,我们不仅学习了希尔排序的实现,还理解了其背后的算法思想。希尔排序是一种简单且高效的排序方法,它在某些情况下比传统的插入排序要快得多。

归并排序:优雅的分而治之艺术

归并排序(Merge Sort)是一种优雅且高效的排序方法。归并排序通过分而治之的策略,将数据集一分为二,然后递归地对这两部分进行排序,最后将它们合并成一个有序的整体。

归并排序的基本概念

归并排序的核心在于“分而治之”。这个策略涉及将一个大问题分解成小问题,解决这些小问题,然后将它们的解决方案合并。在排序的上下文中,这意味着将一个未排序的数组分成两半,分别对这两半进行排序,然后将它们合并成一个有序数组。

Java实现归并排序

让我们通过一个Java程序来实现归并排序。

public class _03_MergeSort {
    // 将arr[l...mid]和arr[mid+1...r]两部分进行归并
    private static void merge(Comparable[] arr, int l, int mid, int r) {
        Comparable[] aux = Arrays.copyOfRange(arr, l, r + 1);
        // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1
        int i = l, j = mid + 1;
        for (int k = l; k <= r; k++) {

            if (i > mid) {  // 如果左半部分元素已经全部处理完毕
                arr[k] = aux[j - l];
                j++;
            } else if (j > r) {   // 如果右半部分元素已经全部处理完毕
                arr[k] = aux[i - l];
                i++;
            } else if (aux[i - l].compareTo(aux[j - l]) < 0) {  // 左半部分所指元素 < 右半部分所指元素
                arr[k] = aux[i - l];
                i++;
            } else {  // 左半部分所指元素 >= 右半部分所指元素
                arr[k] = aux[j - l];
                j++;
            }
        }
    }
    // 递归使用归并排序,对arr[l...r]的范围进行排序
    private static void sort(Comparable[] arr, int l, int r) {
        if (l >= r) {
            return;
        }
        int mid = (l + r) / 2;
        sort(arr, l, mid);
        sort(arr, mid + 1, r);
        // 对于arr[mid] <= arr[mid+1]的情况,不进行merge
        // 对于近乎有序的数组非常有效,但是对于一般情况,有一定的性能损失
        if (arr[mid].compareTo(arr[mid + 1]) > 0)
            merge(arr, l, mid, r);
    }
    public static void sort(Comparable[] arr) {
        int n = arr.length;
        sort(arr, 0, n - 1);
    }
}

在这个类中,merge 方法负责合并两个已经排序的子数组。sort 方法是递归的核心,它将数组分成两半,然后递归地调用自身来排序这两半。最后,sort 方法提供了一个公共接口来开始排序过程。

测试归并排序

为了测试归并排序的性能,我们在 main 方法中生成了一个包含1000个随机整数的数组,并对其进行排序。

public static void main(String[] args) {
    int N = 1000;
    Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000);
    _03_MergeSort.sort(arr);
    SortTestHelper.printArray(arr);
}

归并排序的核心思想

归并排序的核心在于递归和合并。递归地将数组分成更小的部分,直到每个部分只有一个元素(或没有元素),这时数组自然是有序的。然后,通过合并相邻的有序子数组,逐步构建更大的有序数组,最终得到完全有序的原始数组。

结语

归并排序是一种非常优雅的排序算法,它不仅在理论上具有优雅的数学美感,而且在实际应用中也非常高效。它的时间复杂度在最好、最坏和平均情况下都是O(n log n),这使得它在处理大型数据集时特别有用。尽管归并排序需要额外的存储空间来创建辅助数组,但它的稳定性和效率使其成为许多排序场景下的首选算法。

快速排序:分而治之的高效排序算法

快速排序(Quick Sort)是一种分而治之策略的高效排序方法。快速排序以其平均时间复杂度为O(n log n)而闻名,它在大多数情况下都能提供出色的性能。

快速排序的基本概念

快速排序的核心在于“分而治之”。这个策略涉及将一个大问题分解成小问题,解决这些小问题,然后将它们的解决方案合并。在排序的上下文中,这意味着将一个未排序的数组分成两半,然后递归地对这两半进行排序,最后将它们合并成一个有序的整体。

Java实现快速排序

让我们通过一个Java程序来实现快速排序。

public class _04_QuickSort {
    // 对arr[l...r]部分进行partition操作
    // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
    private static int partition(Comparable[] arr, int l, int r){
        // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
        swap( arr, l , (int)(Math.random()*(r-l+1))+l );
        Comparable v = arr[l];
        // arr[l+1...j] < v ; arr[j+1...i) > v
        int j = l;
        for( int i = l + 1 ; i <= r ; i ++ )
            if( arr[i].compareTo(v) < 0 ){
                j ++;
                swap(arr, j, i);
            }
        swap(arr, l, j);
        return j;
    }
    // 递归使用快速排序,对arr[l...r]的范围进行排序
    private static void sort(Comparable[] arr, int l, int r){
        if (l >= r) {
            return;
        }
        int p = partition(arr, l, r);
        sort(arr, l, p-1 );
        sort(arr, p+1, r);
    }
    public static void sort(Comparable[] arr){
        int n = arr.length;
        sort(arr, 0, n-1);
    }
    private static void swap(Object[] arr, int i, int j) {
        Object t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
    // 测试 QuickSort
    public static void main(String[] args) {
        // Quick Sort也是一个O(nlogn)复杂度的算法
        // 可以在1秒之内轻松处理100万数量级的数据
        int N = 1000000;
        Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000);
        sort(arr);
        SortTestHelper.printArray(arr);
    }
}

在这个类中,partition 方法负责将数组分成两部分,sort 方法是递归排序的核心,它将数组分成两半,然后递归地对这两半进行排序。swap 方法是一个辅助函数,用于交换数组中的两个元素。

快速排序的核心思想

快速排序的核心在于选择一个基准值(pivot),然后将数组分成两部分:一部分包含所有小于基准值的元素,另一部分包含所有大于基准值的元素。这个过程称为分区(partitioning)。分区操作完成后,基准值就处于其最终排序位置。然后,我们递归地对基准值左边和右边的子数组进行同样的操作,直到整个数组变得有序。

快速排序的性能

快速排序的平均时间复杂度为O(n log n),这使得它在处理大型数据集时非常高效。尽管在最坏情况下,快速排序的时间复杂度会下降到O(n^2),但通过随机选择基准值,可以大大降低这种最坏情况发生的概率。

结语

通过学习快速排序,我们不仅掌握了一种高效的排序技术,还理解了分而治之这一强大的问题解决策略。这种策略在计算机科学中有着广泛的应用,不仅仅是在排序算法中。快速排序的优雅和效率使其成为了许多排序场景下的首选算法。

选择排序:简单而直观的排序算法入门

选择排序(Selection Sort)算法是一种易于理解和实现的排序方法。选择排序的核心思想是在每一轮迭代中找到最小(或最大)的元素,并将其移动到正确的位置。

选择排序的工作原理

选择排序算法的工作原理可以概括为以下几个步骤:

  1. 假设第一个元素已经是排序好的。
  2. 在剩余的未排序元素中找到最小(或最大)的元素。
  3. 将找到的最小(或最大)元素与当前未排序的第一个元素交换位置。
  4. 重复步骤2和3,直到所有元素都被排序。

Java实现选择排序

下面是一个选择排序的Java实现示例:

public class _07_SelectionSort {
    public static void sort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n; i++) {
            // 初始化最小值索引为当前位置
            int minIndex = i;
            // 寻找[i, n)区间里的最小值的索引
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            // 交换当前位置和找到的最小值位置的元素
            swap(arr, i, minIndex);
        }
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void main(String[] args) {
        int N = 20000;
        Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000);
        _07_SelectionSort.sort(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
            System.out.print(' ');
        }
    }
}

在这个实现中,sort 方法负责执行排序过程。它首先遍历数组,然后在每次迭代中找到最小值的索引,并将其与当前位置的元素交换。swap 方法是一个辅助函数,用于交换数组中的两个元素。

选择排序的特点

选择排序的主要特点是简单。它不需要额外的存储空间(除了临时变量),并且实现起来非常直观。然而,选择排序的效率并不是最高的,它的平均和最坏情况时间复杂度都是O(n^2),这使得它在处理大型数据集时效率较低。

结语

选择排序虽然在效率上可能不如其他更高级的排序算法,但它的简单性和易于理解的特点使其成为初学者学习排序算法的良好起点。

生成测试数据和输出测试数据的类

//SortTestHelper
public class SortTestHelper {
    // SortTestHelper不允许产生任何实例
    private SortTestHelper(){}
    // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
    public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) {
        assert rangeL <= rangeR;
        Integer[] arr = new Integer[n];
        for (int i = 0; i < n; i++)
            arr[i] = new Integer((int)(Math.random() * (rangeR - rangeL + 1) + rangeL));
        return arr;
    }
    // 打印arr数组的所有内容
    public static void printArray(Object arr[]) {
        for (int i = 0; i < arr.length; i++){
            System.out.print( arr[i] );
            System.out.print( ' ' );
        }
        System.out.println();
        return;
    }
}

感谢你的访问,期待与你在技术的道路上相遇!👋🌟🚀
如果对你有帮助,点赞、收藏、关注是我更新的动力!👋🌟🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/446873.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(黑马出品_06)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式

&#xff08;黑马出品_06&#xff09;SpringCloudRabbitMQDockerRedis搜索分布式 微服务技术ES搜索和数据分析 今日目标1. 查询文档1.1.DSL查询分类1.2.全文检索查询1.2.1.使用场景1.2.2.基本语法1.2.3.示例 1.3.精准查询1.3.1.term查询1.3.2.ran…

【机器学习】包裹式特征选择之基于模型的特征选择法

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

解决Ubuntu 16.04/18.04 图形化界面异常、鼠标光标消失、鼠标变成叉叉等问题

bug场景&#xff1a; 一切从一次换源说起…叭叭叭 这篇文章解决的问题&#xff1a; 1.换源&#xff0c;默认源太慢&#xff0c;换成可用的阿里云的源 2.apt-get failed to …问题 3.图形化异常问题 4.get unmet dependence 问题 5. 鼠标光标消失和鼠标变成叉叉问题。 解决方…

指针篇章(3)-(指针之间的区别)

学习目录 ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————…

Windows和Linux(Ubuntu)双系统下,完全删除Ubuntu系统

彻底删除Windows和Linux&#xff08;Ubuntu&#xff09;双系统下的Ubuntu系统及其开机引导项 &#xff08;一&#xff09;删除Ubuntu系统占用的磁盘分区&#xff08;在Windows下操作&#xff09; 1.右键单击“此电脑”&#xff0c;点击“管理”&#xff1b; 2.点击左侧的“…

分布式之SpringCloud

一、SpringCloud 1、SpringCloud是什么 Spring Cloud是一系列框架的有序集合&#xff0c;这些框架为我们提供了分布式系统构建工具。 2、SpringCloud包含那些项目 项目项目名称服务注册于发现Alibaba Nacos、Netflix Eureka、Apache Zookper分布式配置中心Alibaba Nacos、S…

SpringBoot项目如何部署到服务器

文章目录 准备&#xff1a;方式一&#xff1a;Jar包方式&#xff08;推荐&#xff09;部署步骤&#xff1a; 方式二&#xff1a;War包方式部署步骤&#xff1a; 总结 准备&#xff1a; 云服务器&#xff08;阿里云、腾讯云等&#xff09;Linux系统以及运行所需的环境 方式一&a…

GIS在地质灾害危险性评估与灾后重建中的应用

地质灾害是指全球地壳自然地质演化过程中&#xff0c;由于地球内动力、外动力或者人为地质动力作用下导致的自然地质和人类的自然灾害突发事件。由于降水、地震等自然作用下&#xff0c;地质灾害在世界范围内频繁发生。我国除滑坡灾害外&#xff0c;还包括崩塌、泥石流、地面沉…

【牛客】VL68 同步FIFO

描述 请设计带有空满信号的同步FIFO&#xff0c;FIFO的深度和宽度可配置。双口RAM的参考代码和接口信号已给出&#xff0c;请在答案中添加并例化此部分代码。 电路的接口如下图所示。端口说明如下表。 接口电路图如下&#xff1a; 双口RAM端口说明&#xff1a; 端口名I/O描述…

【JAVA】CSS3伸缩盒案例、响应式布局、BFC

1.CSS3伸缩盒案例 效果&#xff1a;用伸缩盒模型 <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title>&…

深入理解Java多线程与线程池:提升程序性能的利器

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 一、实现多线程 1.1. 继承Thread类 1.2. 实现Runnab…

Biomedical knowledge graph-enhanced prompt generation for large language models

1. 生物医学知识图谱增强大语言模型提示生成 论文地址&#xff1a;[2311.17330] Biomedical knowledge graph-enhanced prompt generation for large language models (arxiv.org) 源码地址&#xff1a;https://github.com/BaranziniLab/KG_RAG 2. 摘要 大语言模型&#xff0…

Linux:非常实用的Linux命令

非常实用的Linux命令 系统服务管理 systemctl systemctl命令是Systemd系统和服务管理器的一部分&#xff0c;用于控制systemd系统和服务管理器。Systemd是大多数最新的Linux发行版使用的初始化系统和服务管理器&#xff0c;它用于启动守护进程并管理它们的运行。systemctl提…

基于Java+springboot+VUE+redis实现的前后端分类版网上商城项目

基于Java springbootVUEredis实现的前后端分类版网上商城项目 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言…

C++类和对象(六):初始化列表

再谈构造函数 初始化列表 问题描述&#xff1a;虽然之前调用构造函数后&#xff0c;对象中的成员变量已经有了初始值&#xff0c;但是这仍然不能称之为对对象中成员变量的初始化&#xff0c;只能叫做赋初值&#xff0c;因为成员变量只能被初始化一次&#xff0c;而之前的构造…

Java 基于微信小程序的快递柜小程序

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

P8680 [蓝桥杯 2019 省 B] 特别数的和:做题笔记

目录 思路 代码 题目链接&#xff1a; P8680 [蓝桥杯 2019 省 B] 特别数的和 思路 最开始我思路主要是从数字转字符串上想的。因为我们需要判断每一位是否是特殊数&#xff0c;字符串很容易做到这一点&#xff0c;只是在数字相加这一步不好实现。 需要用到字符串与数字的…

新IDEA电脑环境设置

1.设置UTF-8 2.Maven 3.JRE选对

FPGA - 科学设计复位信号(XILINX)

1&#xff0c;同步复位与异步复位 简单来说&#xff1a;复位信号与时钟同步&#xff0c;称之为同步复位。 复位信号与时钟不同步&#xff0c;称之为异步复位。 2、xilinx 的复位策略 ① 同步高复位 ② 计数器和状态机必须复位 ③ 能不使用复位尽量不使用复位&#xff0c;比如中…

使用Spring的AOP

使用Spring的AOP 一、AOP 的常用注解1.切面类Aspect2.Pointcut3.前置通知Before4.后置通知AfterReturning5.环绕通知Around6.异常通知AfterThrowing7.最终通知After8.切面顺序Order9.启用自动代理EnableAspectJAutoProxy 二、AOP注解方式开发三、AOP 全注解开发四、基于XML配置…