冒泡排序
基本思想:依次比较相邻的两个数,将小数放在前面,大数放在后面。由于在排序过程中(以升序为例)总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。主要通过两层循环来实现,是稳定的排序方法。
代码实例:
public int[] bubbleSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 1; j < arr.length - i; j++) {
if (arr[j] > arr[j - 1]) {
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
return arr;
}
插入排序
基本思想:插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,是不稳定的排序方法。
代码实例:
public int[] insertSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = i; j > 0 && arr[j - 1] > arr[j]; j--) {
int tmp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = tmp;
}
}
return arr;
}
两种排序方法的区别
假设有这样一个数组为 int[] arr=new int[]{1,2,3,4}, 我们要对其进行升序排序(很显然 这里已经是符合要求的升序排列).
现在 假若我们用冒泡排序 大概流程会是这样:
1.先将1,2进行比较 无须替换 然后2,3比较 无须替换 然后3,4比较 无须替换 完成第一轮冒泡 比较次数为3次
2.将2,3进行比较 无须替换 然后3,4进行比较 无须替换 完成第二轮冒泡 比较次数为2次
3.将3,4进行比较 无须替换 完成第三轮冒泡 比较次数为1次
很显然 我们没有移动一次数字 但是却比较了6次
再来看看插入排序如何实现 其详细步骤为:
1.先设定1为有序区间 将2和1比较 无须移动 比较一次
2.此时1,2均为有序区间 将3和2进行比较 无须移动 直接跳出第二层for循环 比较一次
3.此时1,2,3均为有序区间 将4和3进行比较 无须移动 直接跳出第二层for循环 比较一次
很显然 我们也没有移动数字 但是只比较了3次
总结
- 可以这么理解,插入排序是从正向有序的,而冒泡排序是从逆向有序的,冒泡排序是每次最后的一个值都为最大(针对升序)。
- 冒泡排序循环一次,就确定了剩下数据的一位最大值(针对升序); 而插入排序循环一次,则将有序区间增加一位。
- 因此针对部分有序的集合来说(这里说的有序 是指与我们想得到的顺序一致),插入排序效率优于冒泡排序。其中jdk中Arrays.sort就是应用插入排序经典的例子(先插入排序,INSERTIONSORT_THRESHOLD >= 7 再归并排序)。
优化冒泡排序
但是我们可以针对冒泡排序进行优化,当我们循环某一次,发现没有任何数字移动的时候,我们就已经知道集合已经排序完成,而无须再进行循环.
示例代码:
public int[] bubbleSort(int[] arr) {
//集合中数字是否移动过
boolean flag = true;
for (int i = 0; i < arr.length; i++) {
if (flag) {
for (int j = 1; j < arr.length - i; j++) {
flag = false;
if (arr[j] > arr[j - 1]) {
flag = true;
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
} else {
break;
}
}
return arr;
}
此时的冒泡排序 循环次数和插入排序一样 均为3次