前端 排序算法总结(二)
laizimo opened this issue · 0 comments
laizimo commented
前言
继续上一篇的话题,我们来看看算法复杂度在O(n*log2n)的算法。
正文
这篇开头我们就来分析一下最受欢迎的快速排序
快速排序
快速排序,从它的名字就应该知道它很快,时间复杂度很低,性能很好。它将排序算法的时间复杂度降低到O(nlogn)
思路:
首先,我们需要找到一个基数,然后将比基数小的值放在基数的左边,将比基数大的值放在基数的右边,之后进行递归那两组已经归类好的数组。
图例:
原图片太大,放一张小图,并且附上原图片地址,有兴趣的可以看一下:
代码实现:
const arr = [30, 32, 6, 24, 37, 32, 45, 21, 38, 23, 47];
function quickSort(arr){
if(arr.length <= 1){
return arr;
}
let temp = arr[0];
const left = [];
const right = [];
for(var i = 1; i < arr.length; i++){
if(arr[i] > temp){
right.push(arr[i]);
}else{
left.push(arr[i]);
}
}
return quickSort(left).concat([temp], quickSort(right));
}
console.log(quickSort(arr));
性能:
- 时间复杂度:平均时间复杂度O(nlogn),只有在特殊情况下会是O(n^2),不过这种情况非常少
- 空间复杂度:辅助空间是logn,所以空间复杂度为O(logn)
归并排序
归并排序,即将数组分成不同部分,然后注意排序之后,进行合并
思路:
首先,将相邻的两个数进行排序,形成n/2对,然后在每两对进行合并,不断重复,直至排序完。
图例:
代码实现:
//迭代版本
const arr = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
function mergeSort(arr){
const len = arr.length;
for(let seg = 1; seg < len; seg += seg){
let arrB = [];
for(let start = 0; start < len; start += 2*seg){
let row = start, mid = Math.min(start+seg, len), heig = Math.min(start + 2*seg, len);
let start1 = start, end1 = mid;
let start2 = mid, end2 = heig;
while(start1 < end1 && start2 < end2){
arr[start1] < arr[start2] ? arrB.push(arr[start1++]) : arrB.push(arr[start2++]);
}
while(start1 < end1){
arrB.push(arr[start1++]);
}
while(start2 < end2){
arrB.push(arr[start2++]);
}
}
arr = arrB;
}
return arr;
}
console.log(mergeSort(arr));
//递归版
const arr = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
function mergeSort(arr, seg = 1){
const len = arr.length;
if(seg > len){
return arr;
}
const arrB = [];
for(var start = 0; start < len; start += 2*seg){
let low = start, mid = Math.min(start+seg, len), heig = Math.min(start+2*seg, len);
let start1 = low, end1 = mid;
let start2 = mid, end2 = heig;
while(start1 < end1 && start2 < end2){
arr[start1] < arr[start2] ? arrB.push(arr[start1++]) : arrB.push(arr[start2++]);
}
while(start1 < end1){
arrB.push(arr[start1++]);
}
while(start2 < end2){
arrB.push(arr[start2++]);
}
}
return mergeSort(arrB, seg * 2);
}
console.log(mergeSort(arr));
性能:
- 时间复杂度:平均时间复杂度是O(nlogn)
- 空间复杂度:辅助空间为n,空间复杂度为O(n)
基数排序
基数排序,就是将数的每一位进行一次排序,最终返回一个正常顺序的数组。
思路:
首先,比较个位的数字大小,将数组的顺序变成按个位依次递增的,之后再比较十位,再比较百位的,直至最后一位。
图例:
代码实现:
const arr = [3221, 1, 10, 9680, 577, 9420, 7, 5622, 4793, 2030, 3138, 82, 2599, 743, 4127, 10000];
function radixSort(arr){
let maxNum = Math.max(...arr);
let dis = 0;
const len = arr.length;
const count = new Array(10);
const tmp = new Array(len);
while(maxNum >=1){
maxNum /= 10;
dis++;
}
for(let i = 1, radix = 1; i <= dis; i++){
for(let j = 0; j < 10; j++){
count[j] = 0;
}
for(let j = 0; j < len; j++){
let k = parseInt(arr[j] / radix) % 10;
count[k]++;
}
for(let j = 1; j < 10; j++){
count[j] += count[j - 1];
}
for(let j = len - 1; j >= 0 ; j--){
let k = parseInt(arr[j] / radix) % 10;
tmp[count[k] - 1] = arr[j];
count[k]--;
}
for(let j = 0; j < len; j++){
arr[j] = tmp[j];
}
radix *= 10;
}
return arr;
}
console.log(radixSort(arr));
性能:
- 时间复杂度:平均时间复杂度O(k*n),最坏的情况是O(n^2)
总结
我们一共实现了6种排序算法,对于前端开发来说,熟悉前面4种是必须的。特别是快排,基本面试必考题。本篇的内容总结分为六部分:
- 冒泡排序
- 选择排序
- 插入排序
- 快速排序
- 归并排序
- 基数排序
排序算法,是算法的基础部分,需要明白它的原理,总结下来排序可以分为比较排序和统计排序两种方式,本篇前5种均为比较排序,基数排序属于统计排序的一种。希望看完的你,能够去动手敲敲代码,理解一下
如果你对我写的有疑问,可以评论,如我写的有错误,欢迎指正。你喜欢我的博客,请给我关注Star~呦。大家一起总结一起进步。欢迎关注我的github博客