一、实现插入排序
插入排序很重要,是高级排序的基础,如希尔排序、快排等等;
选择排序的核心:局部有序,标记并取出一个元素,其左边部分是局部有序,然后从排好队的元素序列中从后向前比较,比标记元素大的,向后移动一个位置,比标记元素小,则标记元素插入其后面;这里就不用for循环了,因为你不知道要循环多少次,我们使用while循环;
比如这是一个要排序的无规则数组:
let arr = [4, 8, 1, 9, 6, 7];
第一次循环时,第一个元素可以看成是局部有序,那么标记元素为8(index=1),8比4大,则标记元素插入其后:
let arr = [4, 8, 1, 9, 6, 7];
第二次循环时,标记元素移到上一个标记元素的下一位也就是1(index=2),依次对有序序列从后向前比较,1比8小,8向后移动一位:
let arr = [4, 8, 8, 9, 6, 7]; //1已经被取出了
(可能有点抽象,就是在标记1的同时,我们会用一个变量将其保存,而8向后移动一位,在代码上的表现就是array【index+1】=array【index】)
继续比较,1比4小,4向后移动一位:
let arr = [4, 4, 8, 9, 6, 7]; //1已经被取出了
已经没有可以比较的了,1就是最小的,所以1会占据4原来的位置:
let arr = [1, 4, 8, 9, 6, 7];
就是这样重复标记然后排序移位的过程,因为是局部有序,所以最坏的情况就是从后面一直比较到最前面,时间复杂度位O(n**2),但是从平均来说,是比较一半,所以插入排序是的效率比冒泡和选择都要强;
二、完整代码
function swap(array, m, n) {
let temp = array[m];
array[m] = array[n];
array[n] = temp;
}
function selectionSort(array) {
let length = array.length;
for (let i = 0; i < length - 1; i++) {
// 用于标记最小的元素
let index = i;
for (let j = i + 1; j < length; j++) {
if (array[index] > array[j]) {
index = j;
}
}
if (i != index) swap(array, i, index);
}
return array;
}
swap函数是对交换位置的逻辑的一个抽取,方便其他排序算法使用;
内层for循环的为什么j的起始值是 i+1呢?因为自己和自己比较干嘛,肯定和下一位置比较嘛;
为什么最后要加个 if (i != index) ?因为当标记最小元素的索引等于i时,说明i位置所在的元素就是剩下元素里面最小的,故,不用交换;
二、完整代码
function insertionSort(array) {
let length = array.length;
for (let i = 1; i < length; i++) {
// 取出标记元素
let index = i;
let temp = array[i];
while (temp < array[index - 1] && index > 0) {
// 向后移动一位(往覆盖一位)
array[index] = array[index - 1];
index--;
}
array[index] = temp;
}
return array;
}
代码量虽少,但还是要好好理解一下的;
标记位为index,比较元素为index-1;
标记元素比比较元素小,就移动位置(index--),相当于指针指向了移动位置之前的元素的所在位置;
标记元素比比较元素大,就没有移动位置的话就没有(index--),那退出while后index就是比较元素index-1的后一位;