java冒泡排序和双向冒泡排序算法

java实现冒泡排序

一、冒泡排序:

利用冒泡排序对数组进行排序

二、基本概念:

依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。

三、实现思路:

用二重循环实现,外循环变量设为i,内循环变量设为j。假如有n个数需要进行排序,则外循环重复n-1次,内循环依次重复n-1,n-2,…,1次。每次进行比较的两个元素都是与内循环j有关的,它们可以分别用a[j]和a[j+1]标识,i的值依次为1,2,…,n-1,对于每一个i,j的值依次为0,1,2,…n-i 。

设数组长度为N:
1.比较相邻的前后二个数据,如果前面数据大于后面的数据,就将二个数据交换。
2.这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。
3.N=N-1,如果N不为0就重复前面二步,否则排序完成。

package 冒泡排序;

import java.util.Arrays;
/**
 * 冒泡排序
 * @author zy
 *
 */
public class BubbleSort {
    public static void BubbleSort(int[] arr) {
        int temp;//定义一个临时变量
        for(int i=0;i<arr.length-1;i++){//冒泡趟数
            for(int j=0;j<arr.length-i-1;j++){
                if(arr[j+1]<arr[j]){
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
    public static void main(String[] args) {
        int arr[] = new int[]{1,6,2,2,5};
        BubbleSort.BubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

五、性能分析:

若记录序列的初始状态为"正序",则冒泡排序过程只需进行一趟排序,在排序过程中只需进行n-1次比较,且不移动记录;反之,若记录序列的初始状态为"逆序",则需进行n(n-1)/2次比较和记录移动。因此冒泡排序总的时间复杂度为O(n*n)。

六、算法优化:

冒泡排序法存在的不足及改进方法:
第一,在排序过程中,执行完最后的排序后,虽然数据已全部排序完备,但程序无法判断是否完成排序,为了解决这一不足,可设置一个标志位flag,将其初始值设置为非0,表示被排序的表是一个无序的表,每一次排序开始前设置flag值为0,在进行数据交换时,修改flag为非0。在新一轮排序开始时,检查此标志,若此标志为0,表示上一次没有做过交换数据,则结束排序;否则进行排序;

package 冒泡排序;
import java.util.Arrays;
/**
 * 冒泡排序改进版
 * @author zy
 *
 */
public class BubbleSort1 {
    public static void BubbleSort(int[] arr) {
        boolean flag = true;
        while(flag){
            int temp;//定义一个临时变量
            for(int i=0;i<arr.length-1;i++){//冒泡趟数,n-1趟
                for(int j=0;j<arr.length-i-1;j++){
                    if(arr[j+1]<arr[j]){
                        temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                        flag = true;
                    }
                }
                if(!flag){
                    break;//若果没有发生交换,则退出循环
                }
            }
        }
    }
    public static void main(String[] args) {
        int arr[] = new int[]{1,6,2,2,5};
        BubbleSort.BubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

第二、在冒泡排序中,一趟扫描有可能无数据交换,也有可能有一次或多次数据交换,在传统的冒泡排序算法及近年来的一些改进的算法中,只记录一趟扫描有无数据交换的信息,对数据交换发生的位置信息则不予处理。为了充分利用这一信息,可以在一趟全局扫描中,对每一反序数据对进行局部冒泡排序处理,称之为局部冒泡排序。局部冒泡排序与冒泡排序算法具有相同的时间复杂度,并且在正序和逆序的情况下,所需的关键字的比较次数和移动次数完全相同。由于局部冒泡排序和冒泡排序的数据移动次数总是相同的,而局部冒泡排序所需关键字的比较次数常少于冒泡排序,这意味着局部冒泡排序很可能在平均比较次数上对冒泡排序有所改进,当比较次数较少的优点不足以抵消其程序复杂度所带来的额外开销,而当数据量较大时,局部冒泡排序的时间性能则明显优于冒泡排序。对于N个无序数据,我们在进行一趟冒泡排序时,如果第k个数据和第k+1个数据逆序,那么对第k+1个数据进行一趟向前的冒泡排序,使其移动到合适的位置,也就是说让前面k+1个数据调节为正序。因为这种冒泡法只对前k+1个数据冒泡处理,所以我们称它为——局部冒泡

Java 实现双向冒泡排序

冒泡排序_鸡尾酒排序

就是双向冒泡排序

此算法与冒泡排序的不同处在于排序时是以双向在序列中进行排序,外层比较左右边界l<r,

内层一个循环从左向右比,取高值置后;一个循环从右向左,取低值置前;

效率上,O(N^2), 不比普通的冒泡快

public class Bubble_CocktailSort {
	public static void main(String[] args) {
		int len = 10;
		int[] ary = new int[len];
		Random random = new Random();
		for (int j = 0; j < len; j++) {
			ary[j] = random.nextInt(1000);
		}
		/*
		 * 交换次数最小也是1次,最大也是(n^2-n)/2次
		 */
//		ary=new int[]{10,9,8,7,6,5,4,3,2,1}; //测试交换次数
//		ary=new int[]{1,2,3,4,5,6,7,8,10,9}; //测试交换次数
		System.out.println("-------排序前------");
		for (int j = 0; j < ary.length; j++) {
			System.out.print(ary[j] + " ");
		}
		
		orderAsc1(ary);
//		orderAsc2(ary);
		
		//降序,只需要把判断大小于 置换一下
		
	}
	
	static void orderAsc1(int[] ary) {
		int compareCount = 0;//比较次数
		int changeCount = 0;//交换次数
		int len = ary.length;
		int left = 0, right = len -1, tl, tr;
		while (left < right) {//外层固定循环次数
			tl = left + 1;
			tr = right - 1;
			for (int k = left; k < right; k++) {//内层从多到少递减比较次数, 从左向右
				if (ary[k] > ary[k + 1]) {//前大于后, 置换
					ary[k] = ary[k + 1] + (ary[k + 1] = ary[k]) * 0;//一步交换
					changeCount++;
					tr = k; //一轮中最后一比较的时候,将k所在索引赋给tr,  tr表示以后比较的结束索引值,  从左向右比后,k表示左边的索引
				} 
				compareCount++;
			}
			right = tr;
			for (int k = right; k > left; k--) {//内层从多到少递减比较次数, 从右向左
				if (ary[k] < ary[k - 1]) {//后小于前 置换
					ary[k] = ary[k - 1] + (ary[k - 1] = ary[k]) * 0;//一步交换
					changeCount++;
					tl = k; //一轮中最后一比较的时候,将k所在索引赋给tl,  tl表示以后比较的开始索引值, 从向右向左比后,k表示右边的索引
				} 
				compareCount++;
			}
			left = tl;
		}
		System.out.println("\n-----orderAsc1升序排序后------比较次数:" + compareCount + ", 交换次数:" + changeCount);
		for (int j = 0; j < len; j++) {
			System.out.print(ary[j] + " ");
		}
	}
	
	//跟orderAsc1的思路没有区别
	static void orderAsc2(int[] ary) {
		int compareCount = 0;//比较次数
		int changeCount = 0;//交换次数
		int len = ary.length;
		int l = 0, r = len -1, tl, tr;
		for (; l < r; ) {//外层固定循环次数
			tl = l + 1;
			tr = r - 1;
			/*
			 * 从左向右比,将大的移到后面
			 */
			for (int k = l; k < r; k++) {
				if (ary[k] > ary[k + 1]) {
					int temp = ary[k] + ary[k + 1];
					ary[k + 1] = temp - ary[k + 1];
					ary[k] = temp - ary[k + 1];
					changeCount++;
					tr = k;
				}
				compareCount++;
			}
			r = tr;
			/*
			 * 从右向左比,将小的移到前面
			 */
			for (int k = r; k > l; k--) {
				if (ary[k] < ary[k - 1]) {
					int temp = ary[k] + ary[k - 1];
					ary[k - 1] = temp - ary[k - 1];
					ary[k] = temp - ary[k - 1];
					changeCount++;
					tl = k;
				}
				compareCount++;
			}
			l = tl;
		}
		System.out.println("\n-----orderAsc2升序排序后------比较次数:" + compareCount + ", 交换次数:" + changeCount);
		for (int j = 0; j < len; j++) {
			System.out.print(ary[j] + " ");
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值