八大排序算法--冒泡排序及其三种优化

讲给自己听

无论是迷宫游戏、扫雷游戏,还是常用的搜索引擎,甚至高端AI人机博弈等都需要算法来更好的实现。

算法是软件方面提升计算机效率的利器。

算法与数据结构分不开,用代码实现算法,至少会涉及到一种数据结构,数据结构通常有:

  • 线性结构
  • 树形结构

算法就要分别对应不同数据结构去排序。

当一个算法思想提出后,往往还需要更多时间去思考这个算法的优化。不断挖掘算法的潜力。

算法分类:

  • 分治算法:归并排序、快速排序
  • 贪心算法:最小生成树
  • 动态规划:最短路径
  • 递归搜索:树形结构

学习算法先从时间复杂度为O(n^2)学起,因为他们实现最简单,在并不复杂时,简单易用。高效率的算法往往实现也更复杂。

那就首先从算法从八大基本排序算的 冒泡排序法学起吧。

本文以升序排序为例。

冒泡排序定义及实现

冒泡排序,类似生活中于水中往上冒的气泡,越往上的气泡越大,故此得名。在冒泡排序中,每次比较前后两个数据,如果前一个比后一个大,则他们交换位置,这样从头到尾执行一次,则最大的数,就会被交换到最后一个位置,因为它比其他数都要打。进行第二轮排序,则次大的数会被交互到倒数第二位,以此类推。

首先来看一个基础的冒泡排序java代码实现:

public static void bubble(int[] arr) {
	if(arr == null) {
		return;
	}
	int len = arr.length;
	for(int i=0; i< len-1; i++) {
		for(int j=0; j<len-1; j++) {
			if(arr[j] > arr[j+1]) {
				swap(arr, j, j+1);
			}
		}
	}
}

private static void swap(int[] arr, int i, int j) {
	int temp = arr[j];
	arr[j] = arr[i];
	arr[i] = temp;
}

从这里可以看到,因为有两次for循环每个循环最大会进行n次,所以时间复杂度为O(n^2).

优化一

优化1:在全部数据中,一旦前面有一个数比后面的大,就一定会发生交换,把大的数换到后面去。 所以我们可以加一个标记,如果某一趟排序没任何交换,则说明整组数据已经全部有序了,此时就可以中断循环,不用再比较,实现如下:

public static void bubble1(int[] arr) {
	if(arr == null) {
		return;
	}
	int len = arr.length;
	boolean flag;
	for(int i=0; i< len-1; i++) {
		flag = true;
		for(int j=0; j<len-1; j++) {
			if(arr[j] > arr[j+1]) {
				swap(arr, j, j+1);
				flag = false;
			}
		}
		if(flag) {
			break;
		}
	}
	//排序完成后,进行一次打印,检查数据
	System.out.println(Arrays.toString(arr));
}

优化二

如前面定义中讲到,第一次循环会把最大的值交换到最后一个位置,第二次循环会把次大的值交换到倒数第二位,以此类推。随着循环的进行,靠后的部分都变为有序的区域,那么,靠后部分我们不必在进行比较:

public static void bubble2(int[] arr) {
	if(arr == null) {
		return;
	}
	int len = arr.length;
	boolean flag;
	for(int i=0; i< len-1; i++) {
		flag = true;
		for(int j=0; j<len-1-i; j++) {//这里len - 1 -i, i表示前面的i次循环已经把大的数移动到后部分了, 所以后部分i个数不需要再比较
			if(arr[j] > arr[j+1]) {
				swap(arr, j, j+1);
				flag = false;
			}
		}
		if(flag) {
			break;
		}
	}
	//排序完成后,进行一次打印,检查数据
	System.out.println(Arrays.toString(arr));
}

优化三

上面的循环中,每次对整个数据循环我们都只找出了最大值,并且放到了最后的位置,如果我们每次循环既寻找最大值又最小值,并把最大值放到最后,最小值放到最前的位置,就可以进一步优化了,代码实现如下:

public static void bubble3(int[] arr) {
	int len = arr.length;
	int borden_right = len -1; //右边界初始值
	int borden_left = 0;//左边界初始值为
	int lastPos = 0;//记录右边界的值
	int prePos = 0;//记录左边界的值
	boolean flag;
	for(int i=0; i<len-1; i++) {
		flag = true;
		//正向找出最大值
		for(int j=borden_left; j<borden_right; j++) {
			if(arr[j] > arr[j+1]) {
				swap(arr, j, j+1);
				flag = false;
				lastPos = j;
			}
		}
		//逆向找出最小值
		for(int j=borden_right; j>borden_left; j--) {
			if(arr[j] < arr[j-1]) {
				swap(arr, j, j-1);
				flag = false;
				prePos = j;
			}
		}
		if(flag) {
			break;
		}
		borden_right = lastPos;
		borden_left = prePos;
	}
	
	System.out.println("bubble4---- "+Arrays.toString(arr));		
}

附上自动生成测试数组的代码

public static int[] randomArray(int length) {
	int[] arr = new int[length];
	Random random = new Random();
	for(int i=0; i<length; i++) {
		arr[i] = random.nextInt(100);
	}
	//自动生成随机数组,先进行一次原始数据打印
	System.out.println(Arrays.toString(arr));
	return arr;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值