算法第四版读书笔记
写好博客,记住点滴;写明是什么,为什么
目录
选择排序
计算模型
书中同样采用了一般大众的方法:即计算 比较与交换 的数量;对于不交换元素的算法,则计算访问数组的次数 ;
什么是选择排序(大白话说一下,没有图o(╥﹏╥)o)
对于一个随机乱序的数组,我们先设置一个索引,指向数组的第一个元素,然后选择其中最小的那个元素,跟数组的第一个元素交换,如果第一个元素是最小的,则跟其自身进行交换;这样一次选择、比较完毕,数组的第一个元素,就可以确定是最小的元素了;接着,将索引往后移动一个,指向数组的第二个元素,再剩下的不确定的元素中,继续选择,把该次选择到的最小的元素,与该次参与选择的数组的第一位进行交换,也就是当前索引指向的数组元素;然后,再次后移索引,继续着前面的操作;当索引移动到数组的最后一个元素时,数组完成排序;
java代码实现
代码中的Example类的具体实现,请看博客中的Example类
// 待排序的数组
Integer[] a = {12, 2, 5, 6, 77, 6, 7, 4, 87, 23};
int N = a.length;
for (int i = 0; i < N; i++) {
// 假设当前索引指向的元素是最小值
int min = i;
// 用当前假设的最小元素和右边的元素作比较
for (int j = i + 1; j < N; j++) {
// 如果比假设的最小元素小,则将其记录为最小的,
if (Example.less(a[j], a[min])) {
min = j;
}
}
// 交换元素,之前只是记录下脚标
Example.exch(a, i, min);
}
// 打印数组
Example.show(a);
分析
选择排序,是将第 i 的元素,放到数组的第 [i] 位,数组的第 i 元素左边的元素是已经排序完毕的,并且它们的位置不再改变;
复杂度
交换次数
从代码中我们可以看出,每一趟选择的时候,即使最小的元素,就是我们最初假设的元素,最后依然,会进行一次交换,自身与自身的交换;那么使整个数组有序,我们一共需要交换 N(数组的长度)次;因为每一个元素,要放到它应该放的位置上的时候,都要与该位置上原来的元素,进行一次交换,有N个元素,那么就交换N次;
比较次数
从代码中,我们会发现,我们用于比较的 if 语句,每次都会被执行;
外层 for 循环 第 一 次执行的时候,执行了(n-1)次 if 语句;
外层 for 循环 第 二 次执行的时候,执行了(n-2)次 if 语句;
外层 for 循环 第 三 次执行的时候,执行了(n-3)次 if 语句;
….
….
….
外层 for 循环 第 N 次执行的时候,执行了 1 次 if 语句;
因此,一共比较了 (n-1)+(n-2)+(n-3)+….+2+1 次 ;这显然是个等差数列,求和公式套一下,结果是 (n^2)/2 -1/2,取大O阶,就是 n^2, 因此可以看出选择排序是一个复杂度为 N的平方级 算法
特点
数据移动的次数是最少的
与我后面将要学到的那些算法(插入、希尔、归并、堆、快排等排序算法)作比较,选择排序是数据移动最少的,仅仅移动了N次
运行时间,也就是复杂度和输入没有任何关系
这样是很不好的,就是说,我们每次选择当前这趟的最小元素,并不会为下一趟排序,做出任何贡献;也就是说,无论我们的输入是什么,都恒定的比较一样多的次数,最好与最坏的结果是一样的;