java冒泡排序

最近一直有在看java相关的资料更深入的学习进步,但是越往深处里面学习,越觉得自己缺少的东西还是有点多,要想搞好编程,数据结构和算法的功力是必不可少的,所以还是哪里不会写哪里,开整:

研究一下 冒泡排序:Bubble Sort

原理:比较两个相邻的元素,将数值大的元素交换至右端

思路: 依次比较相邻的两个数,将小数放在前面,大数放在后面。第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。重复第一趟步骤,直至全部排序完成。

第一趟比较完成后,最后一个数一定是数组中最大的一个数,所以第二趟比较的时候最后一个数不必参与比较

第二趟比较完成后,倒数第二个数也一定是数组中第二大的数,所以第三趟比较的时候最后两个数不参与比较

依次类推,每一趟比较次数-1;

举例: 排序数组:int[] arr ={7,3,2,5,4,1}

第一趟排序:

    第一次排序:7和3比较,7大于3,交换位置:3,7,2,5,4,1

    第二次排序:7和2比较,7大于2,交换位置:3,2,7,5,4,1

    第三次排序:7和5比较,7大于5,交换位置:3,2,5,7,4,1

    第四次排序:7和4比较,7大于4,交换位置:3,2,5,4,7,1

    第五次排序:7和1比较,7大于1,交换位置:3,2,5,4,1,7

第二趟排序:

    第一次排序:3和2比较,3大于2,交换位置:2,3,5,4,1,7

    第二次排序:3和5比较,3小于5,不交换位置:2,3,5,4,1,7

    第三次排序:5和4比较,5大于4,交换位置:2,3,4,5,1,7

    第四次排序:5和1比较,5大于1,交换位置:2,3,4,1,5,7

第三趟排序:

    第一次排序:2和3比较,2小于3,不交换位置:2,3,4,1,5,7

    第二次排序:3和4比较,3小于4,不交换位置:2,3,4,1,5,7

    第三次排序:4和1比较,4大于1,交换位置:2,3,1,4,5,7

第四趟排序:

    第一次排序:2和3比较,2小于3,不交换位置:2,3,1,4,5,7

    第二次排序:3和1比较,3大于1,交换位置:2,1,3,4,5,7

第五趟排序:

	第一次排序:2和1比较,2大于1,交换位置:1,2,3,4,5,7

至此排序完成 :1, 2, 3, 4, 5, 7

总结: N个数字要排序完成,总共进行N-1趟排序,每 i 趟 排序比较(N-i) 比较,故用双重循环语句控制,外层控制 趟数,内层循环控制每趟比较的次数


// 控制排序的趟数
for(int i=1;i<arr.length;i++) {   
 // 控制 每趟 比较的次数
  for(int j=0;j<arr.length-i;j++) { 
      // 交换位置
  }
}

冒泡排序:每进行一趟排序都会找到最大的数,放在最后的位置,每进行一趟就可以少比较一次。

第一趟排序完成之后,最后一个数,必定是最大的值

第二趟排序完成之后,倒数第二个数,就是倒数第二大的数,最后一个数不参与比较排序

第三趟排序… 倒数最后两个不参与比较排序,也就是说每一趟少比较一次,一定程度上减少了算法比较的次数

时间复杂度:

若我们的数据是正序,只需要一趟即可完成排序,所需要比较的次数C和记录移动次数M均为最小值即

Cmin=n-1 = O(n)
Mmin=0
所以冒泡排序最好的时间复杂度为O(n)
[添加标志位,flag = true 在程序中则可以有最小Cmin]

若数据为倒序,需要进行n-1趟排序。每趟排序需要进行n-i 次比较(1≤i≤n-1),且每次比较都必须移动数据三次(每次交换位置需要三次移动记录)来达到数据的位置。此种情况下,比较和移动的次数均达到最大值

Cmax=n(n-1)/2 =O(n²)
Mmax=3*n(n-1)/2=O(n²)

所以冒泡排序最坏的时间复杂度为O(n²)

综上:冒泡排序的平均时间复杂度为: O(n²)

空间复杂度:
空间复杂度主要看在交换元素时那个临时变量所占的内存空间,

最优的空间复杂度就是开始元素顺序已经排好了,则空间复杂度为:0;
最差的空间复杂度就是开始元素逆序排序了,则空间复杂度为:O(n);
平均的空间复杂度为:O(1);

排序代码实现:

public class BubbleSort {    
    static int[] arry = {8, 5, 3, 2, 1, 7, 10, 9, 4, 13, 11};
    public static void main(String[] args) {
       for (int i = 1; i < arry.length; i++) { //外层循环控制排序趟数
            // 内层循环 控制比较次数
          for (int j = 0; j < arry.length-i; j++) {
                if(arry[j]>arry[j+1]) {
                    int temp = arry[j];
                    arry[j] = arry[j+1];
                    arry[j+1] = temp;
                }
            }
        }
        System.out.println("排序后");
        for (int i : arry) {
            System.out.print(i + ",");
        }
    }
}
// 输出结果:
  排序后
  1,2,3,4,5,7,8,9,10,11,13,

代码亲测,自己手动敲的,

至此,正常情况下不想在往里面深究下去的看到这里就OK了。。。--------------------------------------------------------------

然而,我个人还是想再接着往下探究 ---->

那么问题来了,
什么是时间复杂度呢? 是怎么计算出来的呢?什么是O(n²) 了?

所以,咱们继续剖析:

再次查资料:

百度百科: 算法的时间复杂度是一个函数,它定性描述该算法的运行时间,

时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况。

这里面写的比较专业,需要高等数学功底才可以看的懂,像是使用用极限求解的某一种函数吧,

时间复杂度:说下个人的肤浅理解吧,字面意思呢就是执行该段代码所需要的时间的长短吧,当然是复杂度越小,执行代码消耗的时间越短越好了

关于这个里面的对应的函数就需要用高等数学中的函数来构建了: 目前对应的函数就是用O(n²) 来表示的

第一趟 比较5次 第二趟比较4次…

[5,4,3,2,1] 总共比较了 ∑n=1~5 = n(n-1)/2 = 15

按上面的这个例子 N =6 个 数字 排序总共比较了 C=15次

交换位置移动了M = [5,3,1,1,1]3 = 3(5+3+1+1+1)= 33次

故而 上面的这个例子中执行的时间复杂度,

综合大致上先认为是C+M= 15+33 = 48 来描述吧

这只是一种比较普通的例子,

在极端情况下:

正序:{1,2,3,4,5,6}

Cmin=n-1 当 n=6 时 Cmin = 5 次

Mmin=0

用代码来验证:添加flag =true

public class BubbleSort {    
    // 比较的次数
    private static int compareCount = 0;
    // 交换位置移动的次数
    private static int sweepCount = 0;
    static int[] arry = {1,2,3,4,5,6};
    boolean flag = true;
    public static void main(String[] args) {
       for (int i = 1; i < arry.length; i++) { //外层循环控制排序趟数
            // 内层循环 控制比较次数
          for (int j = 0; j < arry.length-i; j++) {
               compareCount++; // 记录比较的次数
                if(arry[j]>arry[j+1]) {
                    int temp = arry[j];
                    arry[j] = arry[j+1];
                    arry[j+1] = temp;
                    flag = false;
                    sweepCount+=3; // 记录交换位置移动的次数
                }
            }
            if(flag) break;
        }
        System.out.println("比较的次数compareCount="+compareCount);
        System.out.println("交换位置移动的次数sweepCount="+sweepCount);
        System.out.println("排序后");
        for (int i : arry) {
            System.out.print(i + ",");
        }
    }
}
// 输出结果:
  比较的次数compareCount=5
  交换位置移动的次数sweepCount=0
  排序后
  1,2,3,4,5,6,

倒序:{6,5,4,3,2,1}

Cmax=n(n-1)/2 =O(n²)

Mmax=3*n(n-1)/2=O(n²)

Cmax=n(n-1)/2 当n=6 时 最大的比较次数 = 15,

Mmax=3*n(n-1)/2 当n=6时 最大的移动次数= 45

代码验证:

public class BubbleSort {    
    // 比较的次数
    private static int compareCount = 0;
    // 交换位置移动的次数
    private static int sweepCount = 0;
    static int[] arry = {6,5,4,3,2,1};
    public static void main(String[] args) {
       for (int i = 1; i < arry.length; i++) { //外层循环控制排序趟数
            // 内层循环 控制比较次数
          for (int j = 0; j < arry.length-i; j++) {
               compareCount++; // 记录比较的次数
                if(arry[j]>arry[j+1]) {
                    int temp = arry[j];
                    arry[j] = arry[j+1];
                    arry[j+1] = temp;
                    sweepCount+=3; // 记录交换位置移动的次数
                }
            }
        }
        System.out.println("比较的次数compareCount="+compareCount);
        System.out.println("交换位置移动的次数sweepCount="+sweepCount);
        System.out.println("排序后");
        for (int i : arry) {
            System.out.print(i + ",");
        }
    }
}
// 输出结果:
  比较的次数compareCount=15
  交换位置移动的次数sweepCount=45
  排序后
  1,2,3,4,5,6,

由以上可以看出,
冒泡排序,在n相同的情况下,比较的次数
Cmin=n-1 = O(n)
Cmax=n(n-1)/2 = O(n²)

最终还是到了数学的函数公式上,函数 O(n²) 对应高等数学中的
至此剖析到了数学的函数上了。。。看来编程最底层的还是要看数学功底呀。。不说了,我也去学数学了。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值