简单学习->冒泡排序

交换排序

''交换'' 就是 : 在序列中 根据 两个元素"键值""的大小 来交换两个元素在序列中的位置; 而 "交换排序" 就是 让 "键值"大的 向序列的末尾移动 , "键值"小的 向序列的前面移动; 

(像是我们上体育课时排队, 排成一排 (序列) , 老师喊道:"高的往后站,低的往前" , 这时长得高的同学就往后站,低的同学就往前站 ; 在这里 "身高" 就是 "键值" , 我们按 身高来排序, 这时候如果有高的同学站前面,低的同学站后面,此时就交换这两个同学的位置 , 来让高的在后面,低的在前面);

常见的交换排序

1. 冒泡排序

2. 快速排序 

在学习快速排序之前,先学习冒泡排序,简单理解一下什么是"交换";

冒泡排序

冒泡排序比较简单易懂,像鱼吐泡泡一样,泡泡从小到大 ;

例如: 我们在按从低到高 排队 , 队伍里有一个高的同学 排在了前面 ;

(这个同学是20 , 应该排在最后面,不是排在第二)

用冒泡排序来排序:

1.用一个箭头,从第一个同学开始, 用箭头指向的同学和他右边的同学比较,如果箭头同学比右边同学 大,就和右边同学交换位置 , 如果箭头同学比右边同学小, 那么就不交换位置 ;

2.然后把箭头往后移动一位,继续比较箭头同学和右边同学的大小,大叫交换位置,小就不交换位置;

3.直到箭头移动到最后一个同学, 就代表这次的冒泡结束; 

(每次冒泡的作用就是把最大的,给冒泡到最后面去)

4.一个序列里有n个,那么需要进行n-1次冒泡; (像上图,把20冒泡到最后面了,那么让把箭头继续指向第一个同学,继续冒泡,这里有7个同学,那么需要重复进行6次冒泡);

冒泡原理

冒泡的原理: 就是每次冒泡,都把最大的数给移动到后面去, 为什么有n个元素就进行n-1次冒泡?

举个例子:   有一个数组 arr =  [7 , 6, 5 , 4 , 3 , 2 , 1] ; 我要让数组arr有序(从小到大排序) ;

用冒泡排序排序: 

第一次冒泡:  [ 6, 5 , 4 , 3 , 2 , 1 , 7 ] ;             (把最大的7给移动到最后面了)

第二次冒泡:  [ 5 , 4 , 3 , 2 , 1 , 6 , 7 ] ;             (把除了7,最大的6,给移动到后面了)

第三次冒泡:  [ 4 , 3 , 2 , 1 , 5 , 6 , 7 ] ;            (把除了6,7 , 最大的5 给移动到后面了)

第四次冒泡:  [ 3 , 2 , 1 ,4 ,  5 , 6 , 7 ] ;            (把除了5,6,7,  最大的4 给移动到后面了)

第五次冒泡:  [ 2 , 1 , 3 ,4 ,  5 , 6 , 7 ] ;             (把除了4,5,6,7,  最大的3 给移动到后面了)

第六次冒泡:  [ 1 , 2 , 3 , 4 ,  5 , 6 , 7 ] ;             (把除了3,4,5,6,7,  最大的2 给移动到后面了)

最后: 7个数 , 我们把前 6 个最大的数给冒泡了, 排序好了, 只剩下一个 1 , 就没有必要再进行冒泡了;

冒泡排序的复杂度

时间复杂度:  O(N^2) ,序列长 n , 就进行n-1次冒泡 , 每次要比较n-1次;结合起来就是(n-1)*(n-1);

空间复杂度:  O(1)  ,  因为是在原来的序列上进行操作, 没有什么额外申请空间 ;

稳定性: 稳定 ;

代码

import java.util.Arrays;
public class Test2 {
    public static void main(String[] args) {
        int[] array = {12 , 3, 50 , 33 , 21 , 20 , 17 , 15 , 9} ;   // 定义一个数组供我们排序 ;
        // 调用冒泡排序排序数组 ;
        bubbleSort(array);
        //打印数组查看数组里元素排序的怎么样了
        System.out.println(Arrays.toString(array));
    }
    //冒泡排序
    public static void bubbleSort(int[] array){
        //记录数组长度, 用来排序
        int len = array.length - 1 ;   // 因为我们要防止 指针 越界, 所有要-1;

        for (int i = 0; i < len; i++) {
            //这里的j就相当于箭头, 箭头元素 和 箭头右边的元素进行比较 ;
            for(int j = 0 ; j < len ; j ++){
                // 如果箭头元素,大于右边元素就交换两个元素的位置 ;
                if(array[j] > array[j+1]){
                  swap(array,j, j+1);
                }
            }
        }
    }
    //交换数组元素位置的方法
    private static void swap(int[] array , int x , int y){
        int tmp = array[x];
        array[x] = array[y];
        array[y] = tmp ;
    }
}

冒泡排序的小优化

1.减少比较次数

一个 数组 arr =  [17 , 26,  5 , 9 , 8 , 12 , 1] ;  对他进行一次冒泡 ;

arr =  [17 , 26,  5 , 9 , 8 , 12 , 1]  ;       一次冒泡后 ;

arr =  [17 ,  5 ,  9 ,  8 ,  12 ,  26]  ;         最大26被移动到了最后 ;

此时,继续对数组进行冒泡 ;

这时候,第6次冒泡里, 17 还有和 26 比较的 必要吗? 

没有必要了, 26是序列里最大的数,我们前面已经将26冒泡到最后面了, 17就没必要再和26比较了;

所以第6次比较可以省略了,不需要17 和 26 比较了 ;

将17冒泡后, 第3大的数是 12 , 这时候 , 12 还有 和 17 跟 26 比较的必要吗?  

后面的[17,26] 里已经是排序好的了, 没必要在对这些已经排序好的数进行比较了 ;

所以我们的优化是循环里的 j 进行优化, 让 j 不进入到 已经排序好的数; 这样就不对已经有序的数进行比较 , 减少比较次数 ;

              for(int j = 0 ; j < len - i ; j ++){       //  让 j < len - i , 就不会再和已经有序的数进行比较
                if(array[j] > array[j+1]){
                  swap(array,j, j+1);
                } 

2. 序列有序的优化 

除了上面的 减少比较次数 , 还有 一种 情况 -> "序列已经有序"" ;

如果序列里的元素已经有序了 , 那么还有必要对序列进行排序吗?  没必要了 ;

冒泡排序是通过两个数比较之后,进行交换或不交换,来让序列有序的 ;

如果序列里的数都是有序的, 那么就不会出现交换, 没有交换过,就代表序列里已经有序了,可以直接停止冒泡排序了 ;

定义一个: flg 变量 , 如果发生交换操作,就让 flg = true, 每次冒泡后判断一下flg, 如果flg == false , 

就返回,没必要继续冒泡下去了 ;

for (int i = 0; i < len; i++) {
     // 定义一个 flg , 如果 发生交换 , 那么就让flg =true;
       boolean flg = false ;
    for(int j = 0 ; j < len - i  ; j ++){
        if(array[j] > array[j+1]){
            flg = true ;          // 发生交换,让flg = true;
            swap(array,j, j+1);
        }
    }
    if(flg == false){      // 判断一下如果,没有发生交换, 就直接返回;
        return ;
    }
}

优化后的总代码

import java.util.Arrays;
public class Test2 {
    public static void main(String[] args) {
        int[] array = {12 , 3, 50 , 33 , 21 , 20 , 17 , 15 , 9} ;   // 定义一个数组供我们排序 ;
        // 调用冒泡排序排序数组 ;
        bubbleSort(array);
        //打印数组查看数组里元素排序的怎么样了
        System.out.println(Arrays.toString(array));
    }
    //冒泡排序
    public static void bubbleSort(int[] array){
        //记录数组长度, 用来排序
        int len = array.length - 1 ;   // 因为我们要防止 指针 越界, 所有要-1;

        for (int i = 0; i < len; i++) {
             // 定义一个 flg , 如果 发生交换 , 那么就让flg =true;
               boolean flg = false ;
            for(int j = 0 ; j < len - i  ; j ++){
                if(array[j] > array[j+1]){
                    flg = true ;          // 发生交换,让flg = true;
                    swap(array,j, j+1);
                }
            }
            if(flg == false){      // 判断一下如果,没有发生交换, 就直接返回;
                return ;
            }
        }
    }
    //交换数组元素位置的方法
    private static void swap(int[] array , int x , int y){
        int tmp = array[x];
        array[x] = array[y];
        array[y] = tmp ;
    }
}
  • 35
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值