标准的冒泡排序写法
/** * 冒泡排序 * 原理:遍历数组,相邻两个,较小的往前排,较大的往后排,就像烧开水时,冒气泡一样。 * 1、先准备一个无序数组a,长度为10; * 2、准备遍历数组(for循环,i=0开始), * 再次遍历数组(嵌套for循环,j=i+1开始),如果a[i]>a[j],交换位置, * 第一轮儿循环下来,a[0]最小了, * 第二轮儿,a[1]老二, * 第十轮儿下来,循环完毕,顺序完成 */ private void sort() { int[] a = new int[]{5, 4, 3, 6, 8, 9, 14, 15, 21, 21}; int n = a.length; int counts = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (a[i] > a[j]) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } counts++;//时间复杂度计算 } } System.out.println(Arrays.toString(a)); System.out.println(counts); }
时间复杂程度
嵌套循环结束之后,循环了100次。时间复杂程度:n^2级别。平方级别的增长,数据大时,肯定是不可取的。
我们把这个复杂程度比作一个函数,y=n^2。这是一个上开口的抛物线,写到这里,想到了动画轨迹,可以试着用两个for循环实现。
算法优化
ROUND 1:上面的排序,内部循环,每次都j=0开始,导致重复比较(自己和自己比较、已经排好顺序的位置比较),所以j=i+1开始。
private void sort() { int[] a = new int[]{5, 4, 3, 6, 8, 9, 14, 15, 21, 21}; int n = a.length; int counts = 0; for (int i = 0; i < n; i++) { for (int j = i+1; j < n; j++) { if (a[i] > a[j]) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } counts++;//时间复杂度计算 } } System.out.println(Arrays.toString(a)); System.out.println(counts); }
ROUND 2:ROUND 1的排序,优化了内层循环,这次优化,从外层循环下手。
10个无序的,外层要循环10次,假如只有3个数是无序的呢?显然外层循环3次才合理。我们通过内层循环来判断外层是否继续循环
/** * 冒泡排序 * 原理:遍历数组,相邻两个,较小的往前排,较大的往后排,就像烧开水时,冒气泡一样。 * 1、先准备一个无序数组a,长度为10,准备一个变量i=0,准备一个flag=true; * 2、while(flag),进入方法体后,马上修改flag=false, * 遍历数组(for循环,j=1开始),如果a[j-1]>a[j],交换位置,flag=true * 每次将最大值排到末尾,然后n--,继续排序 * 直到flag = false,排序结束。 */ private void sort2() { int[] a = new int[]{1, 4, 3, 11, 8, 9, 14, 15, 21, 21}; int n = a.length; int counts = 0; boolean isSort = true;//true:继续循环 false:停止循环 while (isSort) { isSort = false; for (int j = 1; j < n; j++) { if (a[j-1] > a[j]) {//交换位置 int temp = a[j-1]; a[j-1] = a[j]; a[j] = temp; isSort = true; } counts++;//时间复杂度计算 } n--; } System.out.println(Arrays.toString(a)); System.out.println(counts); }
总结
冒泡排序,复杂程度很高,N大时,不要选择这个算法。另外,冒泡是通过交换位置排序的,数组不稳定。