排序篇
前言
在数据结构与算法中,排序是面试笔试中最常被问到和提及的知识点,虽然在工作中很少用到相关的基础知识,但是对于基础的系统性学习却是必不可少的,通过学习和理解可以培养锻炼我们写代码的思维逻辑。多考虑性能,少制造垃圾代码。
此书介绍得比较详细易懂,并且使用Java语言所以用到了很多相关的标准类库或模板,学习比较容易上手。同时还有另一本Java基础的书籍推荐《Introdution to Java Programming》(作者:Y. Daniel Liang),书中同样介绍了基础的数据结构与算法,并且图文并茂通俗易懂。
重点
排序成本模型:在研究排序算法时,需要计算比较和交换的数量,对于不交换元素的算法,会计算访问数组的次数
看法
从2.1.5节的介绍,个人认为这几点是比较排序之间优缺点的精髓:
- 实现并调试
- 分析它们的基本性质
- 对它们的相对性能作出猜想
- 实验验证猜想
选择排序
分析
理解上来说,就是两个for循环嵌套后,每一趟分别将数组中的每一个元素进行比较然后选出最小的那个移动到最左(顺序递增),最外层遍历N - 1趟,内层遍历N - 1 - i (i为外层index值),所以显然选择排序中元素交换和数组的长度是线性关系的。字面上解释就是,找出最小的那个元素,将其放到最左边。既然需要找出最小的元素,没有逐一比较怎么知道谁最小呢,所以比较次数必然较多。
- 比较次数:(N - 1) + (N - 2) + … + 2 + 1 = (N - 1) / 2 * (1 + (N - 1)) ~ N² / 2
- 交换次数:N
代码
public class SelectionSort {
public static void sort(Comparable[] array) {
int N = array.length();
for (int i = 0; i < N; i++) {
int min = i;
for (int j = i + 1; j < N; j++) {
if (array[j] < array[min]) {
min = j;
}
}
// 把选择出来的当前最小的元素放到最左边
if (min != i) {
int temp = array[i];
array[i] = array[min];
array[min] = temp;
}
}
}
}
插入排序
分析
首先要知道插入排序的特点:
- 索引左侧的元素都是有序的;
- 插入N次意味着会少比较N次;
- 插入一个元素前需要将所有元素都向右移动一位留出插入的位置;
条件 | 比较次数 | 交换次数 |
---|---|---|
平均情况 | ~ N² / 2 | ~ N² / 2 |
最糟情况 | ~ N² / 4 | ~ N² / 4 |
最好情况 | N - 1 | 0 |
适用场景
- 数组中每个元素离它的位置都不远;
- 一个有序的大数组接一个小数组;
- 数组中只有几个元素位置不正确,大部分元素都是有序的;
代码
public class InsertionSort {
public static void sort(Comparabale[] array) {
int N = array.length();
for (int i = 0; i < N ; i++) {
for (int j = i; j > 0 && less(array[j], array[j - 1]); j-- ) {
exchange(array, j, j - 1);
}
}
}
public static boolean less(int a, int b) {
return (a - b < 0) ? true : false;
}
public static void exchange(Comparabale[] array, int i, j){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}