排序算法1--冒泡排序

已知的排序算法有很多种,如果不考虑堆排序这种依赖于特定数据结构的算法,大致上可以分成两类——一类属于分解问题型的,也就是将问题拆分成更小的规模再解决,快排算法和归并排序都是分解问题的算法,大类上都属于分治算法。另一种不分解类型的,基本思路是每轮操作会向有序的结果走一小步,直到最终有序。冒泡排序,选择排序和希尔排序都属于这种类型。
下面以非降序为例介绍下冒泡算法:

算法步骤:

for i <-- 1 to length-1
	for j <-- 1 to length-i
		if a[j]>a[j+1]
			swap(a[j],a[j+1]);

这是算法课上介绍的第一个排序算法,但是刚开始学习的时候总觉得好像不能一眼看出这个算法是对的(不想选择排序和插入排序那么直观),于是想着证明一下:
(1)fact1:在外层循环里,我们在第i轮循环里将第i大的数字放到了length-i的位置上了。
可以用归纳法来证明
a.首先当i=1时,假设最大值是a[x],如果a[x]=a[x+1],j=x时不做改变,否则a[x]的值赋值给a[x+1],所以a[x+1]变成了最大值。
b.此时继续遍历数组,从这个过程可以看出,最大值不断会往后移动,直到移动到a[length]的位置。
c.现在最大值处于正确的位置了,我们将问题减小到下标为1~length-1的数组的排序,这也是内层循环不断减小的原因。
(2)我们的外层循环执行了length-1次,也就是length-1个数的位置是正确的,那么最终的排序结果就是正确的。

代码:

public void bupple2(int [] array){
		for(int i = 0;i<array.length;i++) {
			for(int j = 0;j<array.length-i-1;j++) {
				if(array[j]>array[j+1]) {
					int temp = array[j];
					array[j] = array[j+1];
					array[j+1] = temp;
				}
			}
		}
	}

时间复杂度分析:

显然两层循环,如果判断和swap操作算作基本操作,操作次数为
n − 1 + n − 2 + n − 3 + . . . + 1 = n ( n − 1 ) / 2 n-1+n-2+n-3+...+1=n(n-1)/2 n1+n2+n3+...+1=n(n1)/2
O ( n 2 ) O(n^2) O(n2)的时间复杂度

冒泡排序属于稳定排序,也就是大小相等的两个数的相对顺序,在排序结束后没有发生变化

对于冒泡排序,还有很多可以改进的地方,比如说某次外层循环如果没有交换,那么算法应该结束。而不是继续下一轮循环。如果这样判断程序是否停止,仔细观察到话,我们可以再改进一点。看下面这两个例子:

1 , 2 , 3 , 4 , 0 , 5 1,2,3,4,0,5 123405

如果按照冒泡排序的算法,排序过程中数组状态如下:
(1) 1 , 2 , 3 , 0 , 4 , 5 1,2,3,0,4,5 1,2,3,0,4,5
(2) 1 , 2 , 0 , 3 , 4 , 5 1,2,0,3,4,5 1,2,0,3,4,5
(3) 1 , 0 , 2 , 3 , 4 , 5 1,0,2,3,4,5 1,0,2,3,4,5
(4) 0 , 1 , 2 , 3 , 4 , 5 0,1,2,3,4,5 0,1,2,3,4,5
结束
在这个过程中,因为最小值0比骄靠后,但是每次只往前挪一点点,所以挪了4次才结束。加入我们从后往前执行冒泡排序,也就是将较小的数字往前放,过程如下:
(1) 1 , 2 , 3 , 0 , 4 , 5 1,2,3,0,4,5 1,2,3,0,4,5
(2) 0 , 1 , 2 , 3 , 4 , 5 0,1,2,3,4,5 0,1,2,3,4,5 最小值0在第一轮外层循环中就到了正确的位置
结束

鸡尾酒排序

基于冒泡排序的改进算法
(1)假如有一个较小的数字放在靠后的位置,正向冒泡排序在外层循环中,每次仅仅将其移动一个位置,效率较低(这里说效率低并不是指移动次数增加了,而是因为遍历中存在较多的无效遍历,即已经排好的数据因为整体数据排序没有完成还要不断地被遍历)。采用逆向冒泡的方式可以提高效率。
(2)类似的,假如有一个较大的数字处于靠前的位置,逆向冒泡排序效率反而比较低了,原因相同
(3)鸡尾酒排序是使用往返排序的策略,逆向正向交替进行

再有一点,鸡尾酒排序符合计算机的设计,因为它的局部性更高。在第一轮排序中装在进内存中的数据,在第二轮排序中马上可以再次利用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值