公共方法
// 判断 a 是否大于 b
function isBig(a, b) {
return a > b
}
// 交换data数组中的两个索引数据
function exch(data, i, j) {
const tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
基础的插入排序
- 以数组数字,升序为例:
思想:从索引为1开始,并以单位为1开始递进,循环比较当前元素与前一个元素的大小,跳出条件为不小于
。不小于,意味着,该元素的左侧,都是有序的(升序)。一下是一个简单的实现思路:
function insertSort(data) {
const { length: len } = data;
for(let i = 1; i < len - 1; i++) {
for(let j = i; j >= 0 && isBig(data[j - 1, data[j]); j--){
exch(data, j-1, j);
}
}
}
插入排序,对于其时间复杂度(N最大~平方)和空间复杂度,详细可见《算法4》第157的命题B,这里不再累述。
希尔排序
从上面的插入排序,可以分析出,对于较大的数组数据,其插入的速度很慢,因为它每次只比较与它相邻的元素。如果最小的元素,位于数组的最右端,那么他要比较N-1次。所以,所谓的希尔排序,便可以在此基础上,改进插入排序的比较次数。以优化插入排序的性能。
注:该希尔排序,是基于插入排序的思想,进行实现的,但略有不同
- 思想:
插入排序的主要思想,就是每次与相邻的元素进行比较,即其比较步长为1,这就是插入排序的可优化的地方。希尔排序,就是使数组中,任意间隔为h的元素,都是有序的,其最后完成排序的间隔h为1。本次样例,我们h取3的倍数:
function shellSort(data) {
const { length: len } = data;
let h = 1;
while(h < Math.floor(len / 3)) h = 3 * h + 1;
while(h >= 1) {
// 此处即为插入排序思想
for(let i = h; h < len; i++) {
// 此处与插入排序略微不同,其比较步长不再为1,即不再是相邻元素比较了
// 其比较步长,是当前的h,当h为1时,那么该数组便有序了
for(let j = i; j >= h && isBig(data[j - h], data[j]); j -= h) {
exch(data, j - h, j);
}
}
h = Math.floor( h / 3 );
}
}
希尔排序时间复杂度(N的3/2级别),略优于插入排序的时间复杂度(N的平方级别)。