Java数据结构之排序---冒泡排序
冒泡排序的基本思想:
通过对待排序序列从前到后(从下标小的元素开始),依次比较相邻位置的元素的值,若发现与给定的次序冲突,则交换位置(假设数值大的数放在序列的后面),使数值较大的元素逐渐从前移动到后部,就像冒泡一样。
对于冒泡排序,我们可以对它进行一定的优化:
在排序的过程中,每个元素都不断的接近自己的位置,当在一次排序中,我们发现,使用冒泡排序之后,该序列的任何两个个元素都没有进行交换,这个时候说明该序列已经有序,我们就不需要继续进行排序算法了,此时我们推出该排序算法。如果要执行这个优化,我们需要在排序的过程中加入一个标志变量flag用来判断是否这个序列中的元素在一次排序算法的过程中进行了交换。如果一趟排序下来f'lag = true,那么就说明,该序列进行了交换,我们就继续执行排序算法,如果flag=false,就说明该序列没有交换,那么我们直接break即可。
冒泡排序的例子:
从以上的例子中,我们可以得出结论:
(1).在整个排序的过程中,我们一共进行了arr.length-1趟排序。
(2).每一趟排序的数字的个数都在减少,每次减1,这个我们就可以理解成,随着躺数的增加(i的增加),我们待排序的数目每次都会减i。
(3).如果在我们的排序中,有一次没有进行交换,那么我们可以提前结束这个排序(优化)。
接下来我会用代码详细介绍冒泡排序的算法,该代码主要分三部:
(1).根据每趟的结果讲解每趟的执行过程。
(2)将(1)部的代码整合,形成冒泡排序的算法。
(3)冒泡排序的优化
具体的说明我会在代码的注释中详细表述。
(1).根据每趟的结果讲解每趟的执行过程。
public static void main(String[] args) { int[] arr = {3,9,-1,10,-2}; // int[] arr = {1,2,3,6,5}; System.out.println("冒泡排序之前的序列:"); System.out.println(Arrays.toString(arr)); //数组的方法,将数组转换成字符串 System.out.println("排序后的序列:"); //分步骤的排序算法 System.out.println("第一躺排序:"); int temp = 0;//中间变量 //j<arr.length-1的原因是因为,我们需要将第一个数跟第二个数比较,如果不减一,我们会一直循环到最后一个数,因为最后一个数没有下一个数,会导致数组越界 for(int j=0;j<arr.length-1;j++){//这个地方实际上是j<arr.length-1-0,0代表了执行的第一趟序列 if(arr[j]>arr[j+1]){ //交换两个数,通过中间变量来交换 temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } System.out.println(Arrays.toString(arr)); System.out.println("第二躺排序:"); for(int j=0;j<arr.length-1-1;j++){ //1代表了执行的第二趟序列 if(arr[j]>arr[j+1]){ temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } System.out.println(Arrays.toString(arr)); System.out.println("第三躺排序:"); for(int j=0;j<arr.length-1-2;j++){//2代表了执行的第三趟序列 if(arr[j]>arr[j+1]){ temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } System.out.println(Arrays.toString(arr)); System.out.println("第四躺排序:"); for(int j=0;j<arr.length-1-3;j++){//3代表了执行的第四趟序列 if(arr[j]>arr[j+1]){ temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } System.out.println(Arrays.toString(arr)); }
上图我们得到的结果如下:
由此可见跟我们之前的例子上的答案相同,只不过是分步执行。
(2)将(1)部的代码整合,形成冒泡排序的算法。
public static void main(String[] args) { int[] arr = {3,9,-1,10,-2}; // int[] arr = {1,2,3,6,5}; System.out.println("冒泡排序之前的序列:"); System.out.println(Arrays.toString(arr)); //数组的方法,将数组转换成字符串 System.out.println("排序后的序列:"); // //冒泡排序算法 int temp = 0; //根据(1)中的代码,我们知道了,我们一共执行了arr.length-1趟的排序,并且,在我们的小循环中,每次执行排序的元素的个数是arr.length-1-i //这样我们就可以把两者结合,得到如下的冒泡排序的算法 for(int i=0;i<arr.length-1;i++){ for(int j=0;j<arr.length-1-i;j++){ if(arr[j]>arr[j+1]){ temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } System.out.println(Arrays.toString(arr)); } }
我们得到的结果如下:
由此可见,与上述的方法得到的结果一致。
(3)冒泡排序的优化
public static void main(String[] args) { // int[] arr = {3,9,-1,10,-2}; int[] arr = {1,2,3,6,5}; //序列变成这个 System.out.println("冒泡排序之前的序列:"); System.out.println(Arrays.toString(arr)); //数组的方法,将数组转换成字符串 System.out.println("排序后的序列:"); // ////冒泡排序优化算法 int temp = 0; boolean flag = false; //定义了一个标志变量来判断是否一次排序算法过后元素发生了改变,如果改变了则继续执行,否则说明该算法现在已经有序,退出排序算法。 for(int i=0;i<arr.length-1;i++){ for(int j=0;j<arr.length-1-i;j++){ if(arr[j]>arr[j+1]){ flag = true; //如果进行到这步了,那么一定说明进行交换了,将flag置为true. temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } if(flag){ System.out.println(Arrays.toString(arr)); //如果交换了,直接打印出来 flag = false;//这个地方很重要!!!!因为我们要继续判断下一次是否进行了交换,因此我们需要将flag重置为false. }else{ break;//说明已经有序,直接退出。 } } }
上述代码得到的结果如下:
只执行了一趟,发现有序,退出循环,从而做到了对冒泡排序的优化。
在接下来的几天,我会将排序的8大算法都做成文档进行讲解。
同是小白,互相帮助~