冒泡排序
冒泡排序
摘要:冒泡排序是是最为经典,最为简单也是最为易懂的排序方法,通常来讲我们最早学习的排序算法就是冒泡排序了,经典铸就永恒,冒泡排序算法是每个学习排序算法的人都必须学习的一个排序算法。接下来我们来详细解研究冒泡排序。
1.冒泡排序的排序方式
冒泡排序之所以被称为冒泡排序,是因为他真的和冒泡的方式很像,冒泡排序的排序方式为:游标从0开始,往后推移,在每次推移之前,将游标当前所指数字和下一数字进行对比,如果游标所指的数字大于游标下一位所指的数字,那么二者发生交换。当游标推移到最后,标记为完成一趟,冒泡排序总共需要完成n趟,其中n是数组长度,在完成n趟排序后,这个数组会变得有序。
冒泡排序中,就是让数字两两对比,一旦发现前边的数字比后边的数字大,那么两个数字发生互换,然后游标向后移动一位,否则游标也向后移动一位,继续进行这种两两对比,这时,如果你具备相当的空间想想能力,就会发现,冒泡排序实际上进行的操作是不断地将最大的数字往后放,就像气泡上浮一样,它不断的将数组中最大的数字带到最后边,每一趟它都会将一个数字带到适合它的位置,也就是说第一次它会将最大的数字带到最后一位,第二次将第二大的数字带到倒数第二位,第三次将第三大的数字带到倒数第三位......以此类推,数组中有多少个数字,它就需要进行多少趟。如果你觉得不太好理解,我可以举个例子,当第一趟中,游标指向了某一个数字,这个数字恰巧是最大的数字,那么它肯定是大于它后边的数字,那么它会和后边的数字发生置换,然后游标向下移动一位,由于之前的数字已经和它后边的数字发生置换,那么游标便又获取到了它,这时冒泡排序又会检测,当然这时又会发生交换,以此类推,只要它是最大的数字,游标便总能获取到它,一直到将它放到最后一个位置,整个循环停止,至此,最大的数字达到了它的目的地,而第二大的数字也会发生类似的效果,直到第二大的数字达到了最大的数字前边,判断机制在进行检测的时候发现它不比后边的数字大,因而停止交换,之后游标会继续后移,直到达到最后一位后停止,第二趟至此完成。
可见冒泡排序就是不断地将数组中最大的数字带到它相应的位置的过程,被安置到自己相应位置的部分可以理解为已经拍好顺序的部分,而游标在后移的过程中会不断的指向不同的数字,当遇到更大的数字之后,它就会放弃原有的数字并带上更大的数字,直到它找到了当前无序部分中最大的数字,它便会将它带向当前无序部分的最后方。我们可以将冒泡排序理解成:不断地将无序部分中最大的数字带到数组的最后边,不断地从当前数组的最后边组成有序部分,直到整个数组变得有序的过程。如果你还是觉得这个概念太抽象,那么下面我们使用图示的方法来进行说明。
2.冒泡排序的图示
我们使用数组:5 7 1 4 2 9 6 3 来作为例子。
1.i = 0
这时游标i指向的数字为5,i+1指向的数字为7,二者进行比较,发现5小于7,这是符合前小后大的顺序的,因此二者不发生对换,i直接向后边移动一位,到下面的i=1。
2.i = 1
这时经过对比发现7是大于1的因此7要和1发生对换,并在之后游标后移一位,整体变为下面的i=2状态。
3.i = 2
由于7在游标后移之前和1发生了对换,也就是向后移动了一位,在游标i后移之后,i又指向了7,这里实际上就是冒泡排序的带动效果,知道当前的数字足够大,它就会被一直往后边带。接下来我们发现i指向7,i+1指向4,7仍然大于4,也就是说仍然需要进行交换,因此4和7交换,在交换之后,游标i向后移动一位。
4.i = 3
这时的数组状态如上图,7又被往后带了一步,之后我们发现i指向7,i+1指向了2,这时7仍然是比2大,因此仍要发生一次对换之后,游标再向下移动。因此变为下图。
5.i = 4
这时i指向7,i+1指向了9,这时根据检测,7小于9,因此二者符合先小后大的顺序,不再发生交换,i直接向后移动,这里实际上就是i找到了更大的数字,于是开始舍弃之前的数字,带更大的数字,在第一趟中,i迟早会遇到最大的数字并将其带到最后的,因为每一趟都会找到最大的数字。
6.i = 5
这时i开始带9,i指向了9,i+1指向了6,这是应该发生交换,变为如下所示。
7.i = 6
这时i指向9,i+1指向3,按照规则应该发生交换,之后i向后移动,如下图。
8.i = 7
这时有一个判断,发现i已经抵达数组末端,因此得知一趟冒泡已经结束,i将清零,开始新的一趟冒泡。这时我们发现数组中最大的数字已经被排到了最后边,之后的过程将重复和这个过程一样的过程,冒泡排序将不断地将大数往后代,比如之后的数字将是7,7被带到9之前之后会被卡住,因为9是最大的数字了,7在9之前一定是符合顺序的,而游标继续往后移动,也会发现两数之间都符合顺序,便会继续开始再下一趟冒泡......每趟冒泡都会重复这个过程并不断地将当前无序数组中的最大数带到最后边,进而在最后边不断地产生一个有序数组,最终在进行完n趟冒泡之后,这个数组排序完毕。
3.冒泡排序代码
1.Java代码
public static void bubblesort(int[] arr){//冒泡排序,最基本的排序方法,非常稳定,但缺点是非常耗时
//外层for循环用来控制轮数
for(int i = 0; i<arr.length; i++){
//内层for循环用来实现排序
for(int j = 0; j<arr.length - 1; j++){//注意j要小于数组长度减一,因为在这个循环中,存在一个j+1要指向j的下一位
if(arr[j] > arr[j+1]){
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
2.C语言代码
#include <stdio.h>
void bubbleSrot(int arr[20],int flag);
int main(void){
int arr[20] = {5,7,1,4,2,9,6,3};
bubbleSrot(arr,8);
return 0;
}
void bubbleSrot(int arr[20],int flag){
for(int i = 0;i<flag;i++){//i指针控制冒泡趟数,i从0开始,小于数组长度的话那就是循环数组长度次数
for(int j = 0;j<flag-1;j++){//j是冒泡指针,从0开始,当j指向数组中倒数第二个时停止,这是因为j+1要指向下一个,如果j要指向最后一个才停止的话,j+1就会越界,j指向当前数组中倒数第二个的时候停止,就可以完成算法了。
//当j指向数组中的倒数第二个时,如果不符合先小后大的规律,就会发生交换并将最大的数放置到最后一位,否则的话说明最大的数已经到达最后一位,无论如何,都可以完成数组最后一位的正确操作,因此不管是为了防止越界,还是从代码逻辑完成程度上来讲,j的最大上限都是数组长度-1
if(arr[j]>arr[j+1]){//如果不符合先小后大的规律的话,就要进行交换
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for(int i = 0;i<flag;i++){
printf("%d ",arr[i]);
}
}
代码运行结果:
冒泡排序比较简单,其中的逻辑我就在代码中进行解释了,关于排序算法的学习主要就是多练,争取每天打一边,熟能生巧。