一.希尔排序
shell sort
也称缩小增量排序,是对插入排序算法的改进,其工作原理是定义一个间隔序列来表示排序过程中进行比较的元素之间有多远的间隔,每次将具有相同间隔的数分为一组,进行插入排序,大部分场景中,间隔是可以提前定义好的,也可以动态生成。在较大的数据集上,希尔排序对于插排的优化效果是非常明显的。
./** * 希尔排序示例代码 */function shellSort(gaps, arr) { for(let g = 0; g < gaps.length; g++){ let h = gaps[g]; for(let i = gaps[h]; i < arr.length ; i++){ for(let j = i; j >= h; j = j - h){ if (arr[j] < arr[j-h]) { swap(arr, j, j-h); } } } } }function swap(arr, a, b) { let temp; temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; }
如果觉得算法理解起来比较抽象,可以参考下面的动图感受一下希尔排序的过程:
二.归并排序
merge sort
的基本思想是分治法,假设我们拥有两个已经排好序的集合,规模为T(n/2),现在要将这两个集合合并为一个有序集合,合并的方法如下:
function merge(set1, set2) { let result = []; let p1 = 0; let p2 = 0; let index = p1; while (p1 < set1.length && p2 < set2.length){ if (set1[p1] < set2[p2]) { result.push(set1[p1++]); } else { result.push(set2[p2++]); } } if(p1 === set1.length){ result = result.concat(set2.slice(p2,set2.length)) } else { result = result.concat(set1.slice(p1, set1.length)); } return result; }
也就是每次比较两个已排序序列的第一个元素,把较小的拿出来放进结果数组里,当一个序列中的元素全部被取出后,把另一个序列剩下的元素一次性取出加入结果数组,也就是说通过一个线性阶的算法(也就是时间复杂度为O(n))将两个排好序的集合合并了。
分治思想是指将一个问题分解为若干规模更小但本质解法相同的问题,例如上面的例子中,对一个拥有n个元素的集合排序,可以拆分为对两个n/2规模的集合排序,然后在使用上面的算法将其合并,而每个规模为n/2的问题又可以被拆分为两个规模为n/4的问题来求解,当拆分至集合中只有一个元素时,将不需要进行集合内排序,仅进行自底向上的合并即可。
归并排序的主逻辑代码如下:
function mergeSort(Arr) { let left; let right; let pos; let result; if (Arr.length === 1) { return Arr; } else { pos = Math.floor(Arr.length / 2); left = Arr.slice(0, pos); right = Arr.slice(pos, Arr.length); result = merge(mergeSort(left), mergeSort(right)); console.log('merge step:',result); return result; } }//使用数组进行测试unSortArr = [5,2,4,16,7,23,28,56,12,19];console.log(mergeSort(unSortArr));
结果如下:
三.快速排序
quick sort
是处理大数据集最快的排序算法之一(需要注意的是在处理小数据集时排序性能反而可能下降),它也采用了分治法的思想。merge sort
是先按照物理规模减半,在合并时进行排序,quick sort
的基本过程是选择一个元素作为基准值pivot,然后将比它大的和比它小的分别拆分为两组,也就是说快排算法拆分得到的子序列并不一定是等规模的。快排的过程可以直观地想象为复现一棵二叉搜索树。
./** * 快速排序示例代码 */function quickSort(arr) { if (arr.length <= 1) { return arr; } let pivot = arr[0]; let left = []; let right = []; for(let i = 1; i < arr.length; i++){ if (arr[i] >= pivot) { right.push(arr[i]); } else { left.push(arr[i]); } } return quickSort(left).concat(pivot).concat(quickSort(right)); }let arr = [72,54,58,30,31,78,2,77,82,72];console.log(quickSort(arr));