冒泡法排序及性能优化

冒泡排序及其优化(java实现)

目录

一.原理及简单例子:

给定一个无序的int数组 R{13, 22, 19, 8, 1, 6},其长度为6,假使我们要需要使用冒泡法排序从小到大对数组进行排序
第一趟:1 13 22 19 8 6
第二趟:1 6 13 22 19 8
第三趟:1 6 8 13 22 19
第四趟:1 6 8 13 19 22
第五趟:1 6 8 13 19 22
过程分析:
  初始状态下整个数组无序
  第一趟:扫描范围[j-1,n-1]即[0,5]范围的数据,依次比较(R[n],R[n-1]),(R[n-1],R[n-2]),…,(R[2],R[1]),若每对中R[j] < R[j-1],交换两数的位置,即保证了数组中的第 1(下标为0) 个元素为最小的
  第二趟:扫描范围[j-1,n-1]即[1,5]范围的数据,做相同的操作即可保证数组中R[j-1]在[j-1,n-1]的范围是最小的
  ….
  第n-1趟时,可以保证数组中为R[n-1-1]在[n-1-1,n-1]中的数字是最小的
  此时数组中只剩下了R[n-1],且一定是最大的,同时也说明长度为n的数组,至少要经过(n-1)趟排序才能使数组有序

二.代码实例

给出一个用于检验数组是否有序及随机生成[rangeL,rangeR]范围内的任意长度的数组的工具类

package com.lancelot.csdn;

/**
 * 工具类用于判断数组是否有序及随机生成[n,m]范围内的任意长度的数组
 * @author Lancelot
 *
 */
public class SortTestHelper {
    //生成有 n个元素的随机数组,每个元素的随机范围为[rangeL,rangeR]
    public static int[] generateRandomArray(int n, int rangeL, int rangeR){
        assert rangeL <= rangeR;
        int[] arr = new int[n];
        for(int i = 0; i < n; i++){
            arr[i] = (int)(Math.random() * (rangeR - rangeL + 1) + rangeL);
        }
        return arr;
    }
    /**
     * 验证数组是否有序
     * @param arr
     * @return
     */
    public static boolean isSort(int[] arr){
        for (int i = 0; i < arr.length - 1; i++) {
            if(arr[i] > arr[i + 1])
                return false;
        }
        return true;
    }
    /**
     * @param arr
     */
    public static void printArray(int[] arr){
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
}

排序代码

package com.lancelot.csdn;
/**
 * 冒泡法排序
 * @author Lancelot
 *
 */
public class BubbleSort {

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

    public 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[] arr = SortTestHelper.generateRandomArray(10,1, 1000);
        sort(arr, arr.length);
        if(SortTestHelper.isSort(arr)){
            SortTestHelper.printArray(arr);
        }
    }

}

三.优化性能

3.1优化外层循环

  当我们在进行第 j趟排序时,此时(R[0]~R[j-1])一定是有序的,如果此时(R[j]~R[n-1])是有序的,那么在第j趟排序时,数组中不会发生交换行为,即如果(R[j]~R[n-1])是无序的,则一定会发生交换行为。我们可以设置flag来记录第j趟排序时数组是否发生数据交换行为,如果第j趟未发生交换,整个数组有序,提前结束程序

public static void sort2(int[] arr, int length){
        for(int i = 0; i < length -1; i++){
            //设置遍历是否发生交换的标志位
            boolean flag = true;
            for(int j = length - 1; j > i; j--){
                if(arr[j] < arr[j-1]){
                    swap(arr, j, j-1);
                    flag = false; //发生交换
                }
            }
            if(flag)
                return;
        }
    }
3.2优化内层循环

  当我们完成了第j趟排序时,数组中的(R[0]~R[j-1])一定是有序的,如果此时在(R[j]~R[n-1])中发现最后一次发生数据交换的位置为m(j < m < n-1),即(R[j]~R[m])时有序的,那么在第j+1趟时我们可以只对(R[m + 1]~R[n-1])进行排序,使用变量pos记录在每趟排序中最后发生数据交换的位置

/**
     * 优化内层循环
     * @param arr
     * @param length
     */
    public static void sort3(int[] arr, int length){
        int k = 0; //内层循环终结点
        int pos = 0; //记录最后一趟的循环位置
        for(int i = 0; i < length -1; i++){
            for(int j = length - 1; j > k; j--){
                if(arr[j] < arr[j-1]){
                    swap(arr, j, j-1);
                    pos = j;
                }
            }
            k = pos;
        }
    }

四.总结

  读者可以在阅读完后自己写程序测试算法的性能,
 1.在使用未优化算法时,当数量为1k、10k、100k…耗时的情况(很容易得出时间呈现n^2递增)
 2.在相同的数据量下,各种算法的时间复杂度耗时比较(笔者这里发现其实并没有随机生成的数据下,耗时并没有明显减少,反而耗时增加)
 3.读者可自行写个随机生成比较有序的数组的工具类,相同数据量下不同算法的耗时(在近乎有序的数组中,优化的算法耗时明显减少),在不同数据量下,优化后的算法性能得到明显提示(不再呈现n^2递增)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值