说到排序,首先想到的就是冒泡排序了吧。

冒泡排序是最简单的一种排序方式。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。
重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。


算法描述


  1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  3. 针对所有的元素重复以上的步骤,除了最后一个;
  4. 重复步骤1~3,直到排序完成。

核心代码:


1 for (int i = 0, len = list.length; i < len - 1; i++) {
2 for (int j = i + 1; j < len - i; j++) {
3 if (list[i].compareTo(list[j]) > 0) {
4 T temp = list[i];
5 list[i] = list[j];
6 list[j] = temp;
7 }
8 }
9 }


冒泡排序⼏乎是个程序员都写得出来,但是⾯试的时候如何写⼀个逼格⾼的冒泡排序却不是每个⼈都能做到。

首先我们做一个接口,用来定义排序的方法,这样无论有多少排序类,我们都可以很好的进行扩展了。


 1 package xyz.yanglei.sort;
2
3 import java.util.Comparator;
4
5 /**
6 * 排序器接口
7 * (策略模式: 将算法封装到具有共同接口的独立的类中使得它们可以相互替换)
8 *
9 * @author yanglei
10 *
11 */
12 public interface Sorter {
13 /**
14 * 排序
15 *
16 * @param list 待排序的数组
17 */
18 public <T extends Comparable<T>> void sort(T[] list);
19
20 /**
21 * 排序
22 *
23 * @param list 待排序的数组
24 * @param comp ⽐比较两个对象的⽐比较器器
25 */
26 public <T> void sort(T[] list, Comparator<T> comp);
27 }


接下来我们来写一个冒泡排序的工具类吧,实现Sorter的接口。



 1 package xyz.yanglei.sort;
2
3 import java.util.Comparator;
4
5 /**
6 * <strong>冒泡排序</strong>
7 * 冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。
8 * 走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。 这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
9 *
10 * <strong>算法描述</strong> 1.比较相邻的元素。如果第一个比第二个大,就交换它们两个;
11 * 2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数; 3.针对所有的元素重复以上的步骤,除了最后一个;
12 * 4.重复步骤1~3,直到排序完成。
13 *
14 * @author yanglei
15 *
16 */
17 public class BubbleSorter implements Sorter {
18
19 @Override
20 public <T extends Comparable<T>> void sort(T[] list) {
21 //由于双层循环,外层循环不需要遍历到最后一个元素,因此循环结束条件为i < len - 1。
22 for (int i = 0, len = list.length; i < len - 1; i++) {
23 //内层循环,第一个索引从i+1开始即可,因为前面的字段都是已经排序好的。
24 for (int j = i + 1; j < len; j++) {
25 //从小到大排序,如果第i个元素>第j个元素,则交换位置,否则进入下次循环
26 if (list[i].compareTo(list[j]) > 0) {
27 //交换位置
28 T temp = list[i];
29 list[i] = list[j];
30 list[j] = temp;
31 }
32 }
33 }
34 }
35
36
37 @Override
38 public <T> void sort(T[] list, Comparator<T> comp) {
39 for (int i = 0, len = list.length; i < len - 1; i++) {
40 for (int j = i + 1; j < len - i; j++) {
41 if (comp.compare(list[i], list[j]) > 0) {
42 T temp = list[i];
43 list[i] = list[j];
44 list[j] = temp;
45 }
46 }
47 }
48 }
49 }



OK,我们来个测试类吧,测试一下代码有没有错,首先为了方便测试,我们搞一个基类,做一些通用方法:


 1 package xyz.yanglei.sort.test;
2
3 import java.util.Random;
4
5 import xyz.yanglei.sort.Sorter;
6
7 /**
8 * 基础测试类,提供常用基础方法
9 *
10 * @author yanglei
11 *
12 */
13 public class SorterTest {
14 /**
15 * 测试用的数组长度
16 */
17 protected static Integer arrayLength = 10;
18
19 /**
20 * 测试方法
21 *
22 * @param sorter 排序方式
23 */
24 public static void test(Sorter sorter) {
25 Integer[] array = createArray();
26
27 System.out.println("排序前");
28 printArray(array);
29
30 long begin = System.nanoTime();
31 sorter.sort(array);
32 long time = System.nanoTime() - begin;
33
34 System.out.println("排序后");
35 printArray(array);
36
37 System.out.println("用时:" + formatNanoTime(time));
38 }
39
40 /**
41 * 创建一个随机的数组
42 *
43 * @return Integer类型数组
44 */
45 protected static Integer[] createArray() {
46 int maxNumber = arrayLength * 10 - 1;
47 Random random = new Random();
48 Integer[] array = new Integer[arrayLength];
49 for (int i = 0; i < arrayLength; i++) {
50 array[i] = random.nextInt(maxNumber);
51 }
52 return array;
53 }
54
55 /**
56 * 打印数组
57 *
58 * @param array 要打印的数组
59 */
60 protected static void printArray(Integer[] array) {
61 for (Integer item : array) {
62 System.out.print(item + ",");
63 }
64 System.out.println();
65 }
66
67 /**
68 * 格式化时间
69 *
70 * @param nanoTime 纳秒
71 * @return 格式化后字符串
72 */
73 protected static String formatNanoTime(Long nanoTime) {
74 StringBuffer sb = new StringBuffer();
75 long time = nanoTime;
76 long s = 0;// 秒
77 long ms = 0;// 毫秒
78 long μs = 0;// 微秒
79 long ns = 0;// 纳秒
80
81 ns = time % 1000;// 计算纳秒
82 time = time / 1000;// 换成微秒
83 μs = time % 1000;// 计算微秒
84 time = time / 1000;// 换成毫秒
85 ms = time % 1000;// 计算毫秒
86 time = time / 1000;// 换成妙
87 s = time % 1000;// 计算秒
88
89 sb.append(s).append("秒").append(ms).append("毫秒").append(μs).append("微秒").append(ns).append("纳秒");
90
91 return sb.toString();
92 }
93 }


然后我们创建冒泡排序的测试类来正式测试吧:


package xyz.yanglei.sort.test;

import xyz.yanglei.sort.BubbleSorter;
import xyz.yanglei.sort.Sorter;

/**
* 测试冒牌排序
*
* @author yanglei
*
*/
public class BubbleSorterTest extends SorterTest {

public static void main(String[] args) {
// arrayLength = 10000;
Sorter sorter = new BubbleSorter();
test(sorter);
}

}


运行结果:

02、如何写一个优雅的冒泡排序_测试类

我们可以修改测试类中的arrayLength来覆盖父类中的默认值,比如我们改成排序1000个数字。