排序算法——冒泡排序
基本思想:
每次比较两个相邻的元素,如果它们顺序错误就把它们的位置交换,如下图:

规律:
每轮能且只能将一个数字归位。
假设对10个数进行排序(以升序排序为例,降序同理):
第一轮将最末位的数(最大数)归位,
第二轮将次末位的数(次大数)归位,
第三轮将倒数第三位的数(第三大的数)归位,
......
第九轮将倒数第九位上的数(第九大的数)归位,
此时剩下的1个数自然就在正确的位置上了。
至此排序完成。
也就是说,对n个数排序,只需进行n-1轮操作。
而每一轮要从第1个数开始进行相邻两数的比较、交换,然后往后移一位进行相邻两数比较,交换,重复次步骤直到最后一个未归位的数为止,结束本轮,进行下一轮操作。
Java代码实现:
1 /**
2 * 用冒泡排序算法对整型数组进行升序排序
3 *
4 * @param arr:待排序数组
5 */
6 private static void bubbleSortAsc(int[] arr) {
7 if (arr == null || arr.length <= 1)
8 return;
9 //n个数排序,只需进行n-1轮操作
10 for (int i = 0; i < arr.length - 1; i++) {
11 //每轮从第1个数开始,到最后一个未归位的数为止
12 for (int j = 0; j < arr.length - 1 - i; j++) {
13 //比较、交换
14 if (arr[j] > arr[j + 1]) {
15 int temp = arr[j];
16 arr[j] = arr[j + 1];
17 arr[j + 1] = temp;
18 }
19 }
20 }
21 }
特点:
1. 从以上代码可以看出,算法的核心是双层嵌套循环,因此其时间复杂度为O(N2),这是一个非常高的时间复杂度。
2. 不对称性问题。例如,当需要进行升序排序时,较大的数字聚集在数组尾部,那么此时需要进行交换的次数会减小;相反,如果大部分较小的数聚集在数组尾部,那么交换的次数则会增多。
优化:
针对不对称性问,可以用双向冒泡排序的方式来进行优化。
即每进行完一轮操作,同时从左边和右边进行冒泡,第一轮操作完成后,两端的数字已归位,如此类推。这使操作轮数减少一半。
此方法能一定程度上提高冒泡排序的性能(取决于待排序数组的排列情况),但其平均时间复杂度仍然为O(N2)。
1 /**
2 * 用双向冒泡排序算法对整型数组进行升序排序
3 *
4 * @param arr:待排序数组
5 */
6 private static void towWayBubbleSortAsc(int[] arr) {
7 if (arr == null || arr.length <= 1)
8 return;
9 for (int i = 0; i < arr.length / 2; i++) { //若数组长度为奇数,最后剩下的那个数就刚好在中间
10 for (int j = 0; j < arr.length - 1 - i; j++) {
11 //正向冒泡
12 if (arr[j] > arr[j + 1]) {
13 int temp = arr[j];
14 arr[j] = arr[j + 1];
15 arr[j + 1] = temp;
16 }
17 //反向冒泡
18 if (arr[arr.length - 1 - j] < arr[arr.length - 2 - j]) {
19 int temp = arr[arr.length - 1 - j];
20 arr[arr.length - 1 - j] = arr[arr.length - 2 - j];
21 arr[arr.length - 2 - j] = temp;
22 }
23 }
24 }
25 }
此外,有时并不需要完成全部轮次操作,数组就已经排序完成,所以可用标记进一步优化上面的算法。
1 /**
2 * 用双向冒泡排序算法对整型数组进行升序排序
3 *
4 * @param arr:待排序数组
5 */
6 private static void towWayBubbleSortAsc(int[] arr) {
7 if (arr == null || arr.length <= 1)
8 return;
9 boolean flag;//声明标记
10 for (int i = 0; i < arr.length / 2; i++) {
11 flag = false;
12 for (int j = 0; j < arr.length - 1 - i; j++) {
13 //正向冒泡
14 if (arr[j] > arr[j + 1]) {
15 int temp = arr[j];
16 arr[j] = arr[j + 1];
17 arr[j + 1] = temp;
18 flag = true;
19 }
20 //反向冒泡
21 if (arr[arr.length - 1 - j] < arr[arr.length - 2 - j]) {
22 int temp = arr[arr.length - 1 - j];
23 arr[arr.length - 1 - j] = arr[arr.length - 2 - j];
24 arr[arr.length - 2 - j] = temp;
25 flag = true;
26 }
27 }
28 //flag的值为false说明数组已正确排序,直接退出
29 if (!flag)
30 break;
31 }
32 }

浙公网安备 33010602011771号