• 排序算法-冒泡排序


    基本思路

    遍历给定的数组,从左往右,两两比较,小的放在左边,大的放在右边,遍历完成,数组有序。

    先来看一个冒泡排序的过程:

    给定数组:[5,3,2,1,4]

    排序结果:[1,2,3,4,5]

    拆解步骤

    1.第一轮从左往右循环,遍历前5个数:

    (1) 来到5和3,5大于3  ==>  5和3交换 

     

    (2) 来到5和2,5大于2 ==> 5和2交换

     (3) 来到5和1,5大于1 ==> 5和1交换

     (4) 来到5和4,5大于4 ==> 5和4交换

     第一轮遍历结束,最右侧的5是数组中最大的,不用动了。

     

    2.第二轮从左往右循环,遍历前4个数

     (1) 来到3和2,3大于2 ==> 3和2交换

    (2) 来到3和1,3大于1 ==> 3和1做交换 

     

     (3) 来到3和4,3小于4 ==> 不用交换

    第二轮遍历结束,最右侧的4已经是待排序数中最大的,不用动。

    ……略

    得出规律

    依次类推,得出规律:

    1.每一次遍历的都是左侧待排序的数,遍历完成后会将最大的数放到最右边。

    2.一共需要数组长度次数的遍历,比如数组长度是5,就需要5次遍历。

    代码实现

    1. public class BubbleSort {
    2. public static void main(String[] args) {
    3. int[] arr = {5, 3, 2, 1, 4};
    4. for (int i : arr) {
    5. System.out.print(i);
    6. System.out.print(" ");
    7. }
    8. System.out.println();
    9. bubbleSort(arr);
    10. System.out.println("冒泡排序后 ---->");
    11. for (int i : arr) {
    12. System.out.print(i);
    13. System.out.print(" ");
    14. }
    15. }
    16. /**
    17. * 冒泡排序
    18. *
    19. * @param arr 待排序的数组
    20. */
    21. public static void bubbleSort(int[] arr) {
    22. if (arr == null || arr.length < 2) {
    23. return;
    24. }
    25. for (int i = 0; i < arr.length; i++) { // 数组长度是多少,就需要遍历多少次数组
    26. for (int j = 0; j < arr.length - i - 1; j++) { // 每次遍历的范围是 0 ~ len-i-1
    27. if (arr[j] > arr[j + 1]) {
    28. swap(arr, j, j + 1);
    29. }
    30. }
    31. }
    32. }
    33. /**
    34. * 数组交换
    35. *
    36. * @param arr 数组
    37. * @param index1 下标1
    38. * @param index2 下标2
    39. */
    40. public static void swap(int[] arr, int index1, int index2) {
    41. arr[index1] = arr[index1] + arr[index2];
    42. arr[index2] = arr[index1] - arr[index2];
    43. arr[index1] = arr[index1] - arr[index2];
    44. }
    45. }

    对数器验证

    1. import cn.hutool.core.util.RandomUtil;
    2. import java.util.Arrays;
    3. public class BubbleSortTest {
    4. public static void main(String[] args) {
    5. int[] arr1 = new int[1000];
    6. for (int i = 0; i < arr1.length; i++) {
    7. arr1[i] = RandomUtil.randomInt(0, 10000);
    8. }
    9. final int[] arr2 = Arrays.copyOf(arr1, arr1.length);
    10. System.out.println("拷贝的数组arr2是否等于arr1:" + equals(arr1, arr2));
    11. print(arr1);
    12. Arrays.sort(arr1);
    13. System.out.println("使用系统的排序算法排序后的数组 ------->");
    14. print(arr1);
    15. BubbleSort.bubbleSort(arr2);
    16. System.out.println("使用冒泡排序算法排序后的数组 ------->");
    17. print(arr2);
    18. System.out.println("冒泡排序算法结果与系统内置排序算法结果是否一致:" + equals(arr1, arr2));
    19. }
    20. public static void print(int[] arr){
    21. for (int i : arr) {
    22. System.out.print(i);
    23. System.out.print(" ");
    24. }
    25. System.out.println();
    26. }
    27. public static boolean equals(int[] arr1, int[] arr2){
    28. if(arr1 == null && arr2 == null){
    29. return true;
    30. }
    31. if(arr1 == null || arr2 == null){
    32. return false;
    33. }
    34. if(arr1.length != arr2.length){
    35. return false;
    36. }
    37. for (int i = 0; i < arr1.length; i++) {
    38. if(arr1[i] != arr2[i]){
    39. return false;
    40. }
    41. }
    42. return true;
    43. }
    44. }

     优化

    思路:如果在一次遍历中,发现所有的元素都不需要交换,那么说明这个数组已经是有序数组了。

    比如一个数组:[1,2,3,4,5],其冒泡排序过程如下:

     

     对于这种有序数组,其实只需要遍历一次就可以了。我们可以在每次循环的时候记录当前循环是否发生了交换操作,如果没有发生,就提前结束排序操作,因为数组已经是有序了。

    需要优化的核心代码:

    1. /**
    2. * 冒泡排序
    3. *
    4. * @param arr 待排序的数组
    5. */
    6. public static void bubbleSort(int[] arr) {
    7. if (arr == null || arr.length < 2) {
    8. return;
    9. }
    10. for (int i = 0; i < arr.length; i++) { // 数组长度是多少,就需要遍历多少次数组
    11. boolean swaped = false; // 用来记录是否交换的变量
    12. for (int j = 0; j < arr.length - i - 1; j++) { // 每次遍历的范围是 0 ~ len-i-1
    13. if (arr[j] > arr[j + 1]) {
    14. swaped = true; // 如果发生了交换,就记为true
    15. swap(arr, j, j + 1);
    16. }
    17. }
    18. if(!swaped){
    19. // 如果一次交换都没有发生,就是数组已经有序了
    20. return;
    21. }
    22. }
    23. }

    其他定论

    1.冒泡排序在排序期间没有申请其他的内存空间,它的空间复杂度是O(1),所以是原地排序算法

    2.冒泡排序对于相同数值的元素来说,每次排序后所在的位置不变,因此冒泡排序是稳定的排序算法

    3.冒泡排序的时间复杂度是O(n^2)

  • 相关阅读:
    Postgresql中,计算两个日期月份差值,实现ORACLE中MONTHS_BETWEEN的效果
    ​力扣解法汇总907. 子数组的最小值之和
    设计模式详解(十七)——迭代子模式
    系列八、四大垃圾算法pk
    C#教师考勤管理系统asp.net+sqlserver
    FineReport安装教程
    电脑dll修复工具下载安装,专门解决(win系统)MSVCP100/110/120/140.dll丢失问题
    【STL】vector
    jvm-sandbox-repeater源码解析-配置管理
    QT屏幕自适应自动布局,拖动窗口自动变大变小(一)
  • 原文地址:https://blog.csdn.net/weixin_42425970/article/details/128062304