算法有很多种,有的是用时间换空间有的是用空间换时间,在用空间换时间的算法中,分治思想是很重要的一种算法思想,是先将一个大问题分成若干个小问题,然后逐一解决小问题,最后将小问题的解合并成原来大问题的解,其中快速排序和归并排序是很典型的两种算法。
快速排序
把一个list用分治的思想分为一个大的序列和一个小的序列,然后递归的对两个子序列进行排序
步骤
选择一个基准元素,将序列分为两个子序列
对列表重新排序,将所有小于基准的元素放在基准值的前面,将所有大于基准值的元素放在基准值的后面
分别对较小元素的子序列和较大元素的子序列重复步骤1和2
function quikSort(arr){ /* 递归终止条件 */ if(arr.length<1){ return arr } // step 1: 获取第一个元素作为基准点,此处一定要截取,否则会陷入死循环 let pivot = arr.splice(0,1)[0]; // step 2: let left = [] // 保存比基准小的元素 let right = [] // 保存比基准大的元素 // 对数组进行循环,并按基准对数组进行拆分 for(let i= 0;i if(arr[i]>pivot){ right.push(arr[i]) } else { left.push(arr[i]) } } // step 3: 对较大对数组和较小的数组进行递归直到不能拆分为止 return quikSort(left).concat([pivot],quikSort(right))}
浏览器运行结果,对一百万个随机数进行排序:0.609s
归并排序
一张图就能解释清楚什么是归并排序:
// 合并函数 function merge(left,right){ let result = [] // 循环left和right对比数组的首元素,把较小的元素放进归并数组(result) while(left.length>0 && right.length>0){ if(left[0] < right[0]) { result.push(left.shift()) } else { result.push(right.shift()) } } // 此处的concat是为了把最后剩下的一个元素,也放进数组 return result.concat(left,right) }// 分解函数function mergeSort(arr){ if(arr.length===1){ return arr } // step 1:取到中间的索引,并按索引把函数分为两部分 let middleIndex = Math.floor(arr.length/2) let left = arr.slice(0,middleIndex) let right = arr.slice(middleIndex) // 如果函数长度不为1,继续分解 return merge(mergeSort(left),mergeSort(right))}
浏览器运行结果,对一百万个随机数进行排序:73.548s
对比冒泡排序,浏览器运行结果,对一百万个随机数进行排序:1561.877s
function bubbleSort(arr) { for(let i=0;i-1;i++){ /*这里要根据外层for循环的 i,逐渐减少内层 for循环的次数, 当第一次,找到最大数,放到最后,那么下一次,遍历的时候, 是不是就不能把最后一个数算上了呢? 因为他就是最大的了,不会出现,前一个数比后一个数大, 要交换位置的情况,所以内层 for 循环的次数,改成 i < arr.length - 1 -i */ for(let j=0;j-1-i;j++){ if(arr[j]>arr[j+1]){ let temp = arr[j] arr[j] = arr[j+1] arr[j+1] = temp } } }}