zoukankan      html  css  js  c++  java
  • 冒泡排序之优化

    冒泡排序之优化

      冒泡排序属于一种典型的交换排序。

      交换排序顾名思义就是通过元素的两两比较,判断是否符合要求,如过不符合就交换位置来达到排序的目的。冒泡排序名字的由来就是因为在交换过程中,类似水冒泡,小(大)的元素经过不断的交换由水底慢慢的浮到水的顶端。

      冒泡排序的思想就是利用的比较交换,利用循环将第 i 小或者大的元素归位,归位操作利用的是对 n 个元素中相邻的两个进行比较,如果顺序正确就不交换,如果顺序错误就进行位置的交换。通过重复的循环访问数组,直到没有可以交换的元素,那么整个排序就已经完成了。

    	**常用的场景是数组排序:即遍历数组,对数组相邻元素进行对比,若想得到升序序列,则将大的元素放后边,小的放前边。若想得到降序数组则反过来**
    

    图文讲解:

    冒泡排序:从第一个数据开始,一次比较相邻元素的大小。如果前者大于后者,则进行交换操作。把大的元素往后交换。通过多轮迭代,直到没有交换操作为止。冒泡排序就像是在一个水池中处理数据一样,每次会把最大的那个数据传递到最后。

    算法实现:

     @Test
        public void sortTest(){
            int[] arr = {4,1,3,2,6,7,8,9,10,11,13,15};
    
            int temp = -1;
            int count = 0;
    		
            //需要进行arr.length-1次排序遍历
            for (int i=0; i<arr.length; i ++){
    			//每次遍历,需要把所有无序的元素遍历完
                for (int j=0 ; j<arr.length-1-i; j++){
    				//如果后边的元素比前边小则交换,反之则不变
                    if (arr[j+1] < arr[j]){
                        temp = arr[j+1];
                        arr[j+1] = arr[j];
                        arr[j] = temp;
                    }
                    //记录循环执行的次数
                    count ++;
                }
            }
            System.out.println("执行了" + count + "次");
            System.out.println("----------------------------");
            for (int i : arr) {
                System.out.print(i + "	");
            }
        }
    

    结果

    执行了66次
    ----------------------------
    1	2	3	4	6	7	8	9	10	11	13	15	
    

    优化一:

    通过上面的图片,我们可以发现。在第三次排序的时候,数组其实已经是一个有序数组了。但循环依然在继续,这就白白的浪费了资源。如果我们能判断出数组是有序的,然后跳出循环,那就节省了一部分空间。

     @Test
        public void sortTest1(){
            int[] arr = {4,1,3,2,6,7,8,9,10,11,13,15};
    
            int temp = -1;
            int count = 0;
            
            for (int i=0; i<arr.length; i ++){
    			//设置一个布尔值,默认为true
                boolean flag = true;
    
                for (int j=0 ; j<arr.length-1-i; j++){
    
                    if (arr[j+1] < arr[j]){
                        temp = arr[j+1];
                        arr[j+1] = arr[j];
                        arr[j] = temp;
                        //如果进行了交换,则把布尔值改为false
                        flag = false;
                    }
    
                    count ++;
    
                } 
                //如果进行一次遍历,发现布尔值仍是true,则说明没有发生元素交换,
                //即数组为有序数组,跳出循环即可
                if (flag ){
                    break;
                }
            }
    
            System.out.println("执行了" + count + "次");
            System.out.println("----------------------------");
            for (int i : arr) {
                System.out.print(i + "	");
            }
        }
    
    

    结果:

    执行了30次
    ----------------------------
    1	2	3	4	6	7	8	9	10	11	13	15	
    

    在以上优化的基础上,还存在一个问题,例如我们的初始数组如下:

    int[] arr = {4,1,3,2,6,7,8,9,10,11,13,15};

    我们发现arr在6之后的元素是有序的,根本不需要进行遍历和交换。然而,我们每次遍历是从0开始遍历到arr.length-i-1的。这就有可能包括了部分有序数组。

    因此,如果我们能把无序数列和有序数组的边界标出来,每次遍历和交换的时候,只遍历到无序数组则也能省下部分空间。

      @Test
        public void sortTest2(){
            int[] arr = {4,1,3,2,6,7,8,9,10,11,13,15};
    
            int temp = -1;
            int count = 0;
            //定义最后一次交换位置时的索引
            int lastChangeIndex = 0;
            //初始化,第一次遍历数组时,需要遍历的长度
            int sortBorder = arr.length-1;
            for (int i=0; i<arr.length; i ++){
    
                boolean flag = true;
    
                for (int j=0 ; j< sortBorder; j++){
    
                    if (arr[j+1] < arr[j]){
                        temp = arr[j+1];
                        arr[j+1] = arr[j];
                        arr[j] = temp;
                        //记录最后一次交换位置时的索引
                        lastChangeIndex = j;
                        flag = false;
                    }
    
    
                    count ++;
    
                }
                //将最后一次记录的索引,赋值给无序数列的边界,这就是下一次要遍历的数组边界
                sortBorder = lastChangeIndex;
                if (flag ){
                    break;
                }
            }
    
            System.out.println("执行了" + count + "次");
            System.out.println("----------------------------");
            for (int i : arr) {
                System.out.print(i + "	");
            }
        }
    
    执行了14次
    ----------------------------
    1	2	3	4	6	7	8	9	10	11	13	15	
    

    总结:

    ​ 冒泡排序的思想其实很简单,就是相邻元素两两对比,判断是否需要交换顺序。但经过细心的考虑,有些特殊的情况,则可以提前确实数组局部有序,则不需再进行重复遍历。优化也就是把这些重复遍历的步骤给去除,最终得到高性能的冒泡排序算法。

  • 相关阅读:
    BeautifulSoup的基本用法
    打印实例
    webservice和一般处理程序
    C# 后台调用存储过程
    表格增加删除
    asp.net C# 获得配置文件AppSettings 的值
    深入浅出zookeeper(一)
    resource下的excel文件下载被损害
    csdn添加目录
    spring面试题,求求你别问我spring了!
  • 原文地址:https://www.cnblogs.com/cugb/p/13267331.html
Copyright © 2011-2022 走看看