递归
上一篇blog里,用js实现了quicksort算法,quicksort算法是一个递归调用过程。
递归是一种非常强大的编程思想,它广泛的的存在于各种语言当中,尤其lisp的各种方言中,大量的使用递归来实现循环操作。
还有一本小书叫《The litter schemer》,就是让编程的人递归的思考问题(thinking recursively)。
本篇呈接上篇,是对递归思想的实践——在学习常见的算法的同时,运用递归思想。
理解了递归思想,以前觉得挺难的算法也觉得不是想象的那么难了。
mergsort in javascript
- 最简单的情况是对两个元素的数组排序;
- 如果两个数组已经排序好了,那么,再将这两个数组合并为一个有序的数组是比较容易的;
- 一个混乱的数组,总能将其分成两部分,再将分成的两部分再分为两部分,直到有一个部分只包含两个元素,那么就回到第1步的情况,对两个元素的数组进行排序;
- 这是一个递归过程
function first(l){ return l[0]; } function rest(l){ return l.slice(1); } /** 实现2 * l1 l2 是已经从小到大排序好的数组 * 返回一个l1 l2合并后的,从小到大排序好的数组 * */ function mergelist(l1,l2){ var ret if(l1.length == 0){ ret = l2; }else if(l2.length == 0){ ret = l1; }else if(first(l1)>first(l2)){//将小的放前面 ret = [].concat(first(l2), mergelist(l1,rest(l2))) }else{ ret = [].concat(first(l1),//将小的元素放前面 mergelist(l2,rest(l1))) } return ret; } // console.log(mergelist([2,3],[1,4,5])); // console.log(mergelist([1,4,5],[2,3])); // --> [ 1, 2, 3, 4, 5 ] // 下面这个操作是对一组数数组排序的最小单位排序操作——因为 // 一个包含任意元素的数组的排序最终都能逐渐的递归细分为比较两个元素的大小 // 切分操作由下面的divide函数来完成 // console.log(mergelist([5],[2])); // --> [ 2, 5 ] // 实现3中的拆分 // 将一个数组分为两部分 function divide(l){ var len = l.length , mid = Math.floor(len/2); return [l.slice(0,mid),l.slice(mid,len)] } // console.log(divide([1,4,5,2,3])); //--> [ [ 1, 4 ], [ 5, 2, 3 ] ] // 整体实现 function mergesort(l1){ var ab = divide(l1) , a = ab[0] , b = ab[1]; if(a.length == 0){ return b; }else if(b.length == 0){ return a; }else if(a.length == 1){ return [].concat(mergelist(a,mergesort(b))); }else if(b.length == 1){ return [].concat(mergelist(b,mergesort(a))); }else{ return [].concat(mergelist(mergesort(a), mergesort(b))); } } console.log(mergesort([5,2,3,4])); console.log(mergesort([5,3,4])); // console.log(mergesort([1,4,5,2,3])); // 注意[].concat方法的运用 // [].concat(1,[2,3]) -> [1,2,3] // [].concat([1],[2,3]) -> [1,2,3] // [].concat(1,2,3) -> [1,2,3]