冒泡排序口诀:两两比较,两两交换。
操作对象:乱序数组
操作方式:双循环以及内层循环中条件的判断
操作结果:升序或降序数组
举例:
给定一个数组:int[] arr = new int[]{99,33,21,14,65,11,9,45,22,10};
对此数组进行升序排列。
分析:越大的数越要下沉,最大的数沉底;越小的数越要上浮,最小的数浮顶。上面数组中一共有10个数,实现这10个数的升序排列一共分两方面:
第一方面:一轮一轮(或者说一趟一趟)地从左往右遍历数组,每一轮操作之后产生一个最大数放到数组最右侧,但不能超过上一轮的最大值。对于数组arr,第一轮操作后,99放在arr[9];第二轮操作后,65放在arr[8];第三轮操作后,45放在arr[7];……一共要操作九轮。数组中有10个数,要操作九轮。因为操作到第九轮的时候,产生第九个最大数,那第九个最大数应该放在arr[1]的位置,第十个最大数即最小数已经没有与之比较的对象因此对于十个数的升序排列是操作九轮。那么对于n个数的排列,推理一下当然是操作n-1轮。由此得出轮数与数组长度的关系:总轮数==数组长度-1。那么中间还有一个问题:在每一轮的操作中,大数如何一步步地沉底呢?在每一轮操作中,一共需要比较多少次呢?每轮比较的次数与轮数是什么样的关系?请看第二方面的说明:
第二方面:
开始 {99,33,21,14,65,11,9,45,22,10} 比较次数:0
第一轮:99>33? true {33,99,21,14,65,11,9,45,22,10} 比较次数:1
99>21? true {33,21,99,14,65,11,9,45,22,10} 比较次数:2
99>14? true {33,21,14,99,65,11,9,45,22,10} 比较次数:3
99>65? true {33,21,14,65,99,11,9,45,22,10} 比较次数:4
99>11? true {33,21,14,65,11,99,9,45,22,10} 比较次数:5
99>9? true {33,21,14,65,11,9,99,45,22,10} 比较次数:6
99>45? true {33,21,14,65,11,9,45,99,22,10} 比较次数:7
99>22? true {33,21,14,65,11,9,45,22,99,10} 比较次数:8
99>10? true {33,21,14,65,11,9,45,22,10,99} 比较次数:9
第二轮: 33>21? true {21,33,14,65,11,9,45,22,10,99}
33>14? true {21,14,33,65,11,9,45,22,10,99}
33>65? false {21,14,33,65,11,9,45,22,10,99}
...
...
...
33>65? false {21,14,33,11,9,45,22,10,65,99} 比较次数:8
第三轮:比较次数:7
第四轮:比较次数:6
...
第九轮:比较次数:1
于是得出如下关系:该轮次数 = 数组长度-该轮轮数
又根据第一方面推理:总轮数 = 数组长度-1
注意到结合数组下标从arr[0]开始的原理,设计出的双循环如下:
for(int i=0; i<arr.length-1; i++){ //外循环控制轮数 for(int j=0; j<arr.length-i-1;j++){ //内循环控制该轮次数 if(arr[j]>arr[j+1]){ //两两比较 int temp = arr[j]; //1 arr[j] = arr[j+1]; //2 arr[j+1] = temp; //3 1、2、3代码实现两两交换 } } }