冒泡排序看这篇就够了(附Java代码实现)

冒泡排序是我们使用最多的排序方式之一,原因是简单易实现,且原理易懂。顾名思义,冒泡排序,它的排序过程就像水中的气泡一样,一个一个上浮到水面。为了方便大家理解上图:

排序算法是《数据结构与算法》中最基本的算法之一。

排序算法可以分为内部排序外部排序

内部排序是数据记录在内存中进行排序。

而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。

常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。

用一张图概括:

  1.  

冒泡排序

 算法步骤

  • 比较相邻的元素。如果第一个比第二个大,就交换他们两个。

  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

  • 针对所有的元素重复以上的步骤,除了最后一个。

  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

再次动画演示:小鱼冒泡

一、冒泡排序原理:

比较两个相邻的元素,将值大的元素交换至右端。

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

代码如下:


/**
 * TODO Document BubbleSort
 * <p>
 * @version 1.0.0,2017-4-17
 * @author White Clothing
 * @author 白衣染霜陈
 * @since 1.0.0
 * 
 * 冒泡排序
 * 比较相邻的元素。如果第一个比第二个大,就交换他们两个。  
 * 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。  
 * 针对所有的元素重复以上的步骤,除了最后一个。
 * 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

版权声明:本文为优快云博主「白衣染霜陈」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/singit/article/details/70306816

package com.cn.sortStudy;

import java.util.Arrays;

public class BubbleSort {
	
	static int[] arr = {2,4,5,3,8,}; //首先声明一个int[]数组
	
	public static void Bubst(int[] a) 
	{
		
		for(int i=0;i<a.length-1;i++) //外层循环,是需要进行比较的轮数,一共进行5次即可
		{
			
			for(int j =0;j<a.length-1;j++)  //内存循环,是每一轮中进行的两两比较
			{
				if(a[j] > a[j+1])
				{
					int temp =	a[j];
					a[j]	 = 	a[j+1];
					a[j+1] 	 =	temp;
				}
			}
			System.out.println("第"+(i+1)+"轮排序后的数组为: "+Arrays.toString(a));
			
		 }
	}
	public static void main(String[] args) {
		Bubst(arr);
	 }
}
输出结果:第1轮排序后的数组为: [4, 2, 3, 0, 1, 5, 6]
第2轮排序后的数组为: [2, 3, 0, 1, 4, 5, 6]
第3轮排序后的数组为: [2, 0, 1, 3, 4, 5, 6]
第4轮排序后的数组为: [0, 1, 2, 3, 4, 5, 6]
第5轮排序后的数组为: [0, 1, 2, 3, 4, 5, 6]
第6轮排序后的数组为: [0, 1, 2, 3, 4, 5, 6]


6轮这里记一下。

 

 

二、冒泡排序的优化

1 .观察上述代码和运行结果,我们发现,当第一轮结束后,最后一个数字一定是数组中最大的元素,那么我们在进行第二趟的两两比较时,实际上是没有必要再对第5个和第6个进行比较的。

其实我们就已经得到了排好序的数组,但是程序并不知道,仍然进行了后续的无用工作。那么,我们如何来让程序知道已经完成好排序了呢?

这里可以想到,当某一轮的两两比较中,如果都没有发生数组元素的互换,那么其实排序工作已经完成了,所以我们可以考虑在程序中加入一个flag,默认为false,含义是该轮比较中是否发生了元素互换,当程序中执行到元素互换时,将该flag置为true,当该轮比较结束时,若flag为flase,则说明该轮比较未发生元素互换,那么排序完成,若flag为true,说明本轮比较仍然有元素互换,需要继续进行下轮排序。优化后代码实现如下:

package com.cn.sortStudy;

import java.util.Arrays;
/**
 * 冒泡排序
 * @author White Clothing
 * @author 白衣染霜陈
 */
public class BubbleSort {
	
	static int[] arr = {5,4,2,3,0,1,6}; //首先声明一个int[]数组
	
	public static void Bubst(int[] a) 
	{
		
		for(int i=0;i<a.length-1;i++) //外层循环,是需要进行比较的轮数,一共进行5次即可
		{
			boolean flag = false;
			for(int j =0;j<a.length-1-i;j++)  //内存循环,是每一轮中进行的两两比较
			{
				if(a[j] > a[j+1])
				{
					int temp =	a[j];
					a[j]	 = 	a[j+1];
					a[j+1] 	 =	temp;
					flag = true; //冒泡排序代码优化 
				}
			}
			System.out.println("第"+(i+1)+"轮排序后的数组为: "+Arrays.toString(a));
			 if(flag == false)
	            {
	                System.out.println("本轮中的两两比较未发生元素互换,排序已经完成啦");
	                return;
	            }
		 }
	}
	public static void main(String[] args) {
		Bubst(arr);
	 }
}

输出结果:

第1轮排序后的数组为: [4, 2, 3, 0, 1, 5, 6]
第2轮排序后的数组为: [2, 3, 0, 1, 4, 5, 6]
第3轮排序后的数组为: [2, 0, 1, 3, 4, 5, 6]
第4轮排序后的数组为: [0, 1, 2, 3, 4, 5, 6]
第5轮排序后的数组为: [0, 1, 2, 3, 4, 5, 6]

5轮结束。
本轮中的两两比较未发生元素互换,排序已经完成啦。是不是节约了一次资源。
 

三.冒泡排序的时间复杂度、空间复杂度

冒泡排序是一种用时间换空间的排序方法,最坏情况是把顺序的排列变成逆序,或者把逆序的数列变成顺序。在这种情况下,每一次比较都需要进行交换运算。举个例子来说,一个数列 5 4 3 2 1 进行冒泡升序排列

第一轮的两两比较,需要比较4次;得到 4 3 2 1 5
第二轮的两两比较,需要比较3次;得到 3 2 1 4 5
第三轮的两两比较,需要比较2次;得到 2 1 3 4 5
第四轮的两两比较,需要比较1次;得到 1 2 3 4 5

所以总的比较次数为 4 + 3 + 2 + 1 = 10次
对于n位的数列则有比较次数为 (n-1) + (n-2) + ... + 1 = n * (n - 1) / 2,这就得到了最大的比较次数。
而O(N^2)表示的是复杂度的数量级。举个例子来说,如果n = 10000,那么 n(n-1)/2 = (n^2 - n) / 2 = (100000000 - 10000) / 2,相对10^8来说,10000小的可以忽略不计了,所以总计算次数约为0.5 * N^2。用O(N^2)就表示了其数量级(忽略前面系数0.5)。

综上所述,冒泡排序的时间复杂度为:O(n²) 。

 

关于时间复杂度:

  1. 平方阶 (O(n2)) 排序 各类简单排序:直接插入、直接选择和冒泡排序。

  2. 线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序;

  3. O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 希尔排序

  4. 线性阶 (O(n)) 排序 基数排序,此外还有桶、箱排序。

关于稳定性:

  1. 稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。

  2. 不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值