最近看了一道「如何給阿里兩萬多名員工按照年齡排序」的面試題後,很想記錄下來本身的解題思路,下面:
綜合考慮到基數較大和穩定性,咱們採起歸併排序的算法;
歸併算法分爲兩個兩個靈魂步驟,即:拆分=>歸併;
咱們先把兩萬多名員工的基數縮小至六名員工的基數,他們的年齡數組未排序前爲[25,18,17,31,25,30],咱們實現第一個靈魂操做,拆分:
歸併算法的拆分思想是將一個數組一分爲二,而後將分出來的數組繼續一分爲二,直至出現單個數組的長度爲1,不可再分爲止; 面試
如上圖,一個長度爲6的數組按照左右結構一直拆分至6個長度爲1的數組,拆分就完畢了,這時咱們由下往上回溯,將數組歸併,圖解:算法
六個長度爲一的數組歸併以後又變成了一個長度爲6的數組,可是排序發生了改變,這就是歸併算法,下面是代碼實現:
咱們一步一步來,第一步先來實現拆分的部分:數組
// 拆分 function mergeSort(arr){ console.log(`arr=${arr}`) if(arr.length==1){//若是數組長度爲1則返回數組 return arr } var mid=Math.floor(arr.length/2);//將數組一拆分爲二 var left=arr.slice(0,mid); var right=arr.slice(mid); mergeSort(left);//若是數組長度不爲1,則繼續遞歸拆分,(由控制檯能夠看出遞歸會先將left執行完後再去執行right) mergeSort(right) } console.log(mergeSort([25,18,17,31,25,30]))
控制檯打印出結果:
這個時候咱們能夠看到,咱們已經採用遞歸的方式將數組拆分爲六個長度爲一的數組了,接下來走第二步的合併,合併的思想是左右兩個數組的第一個元素比較大小,而後將大的數(或者小的數)提取出來存放在一個第三方數組,直接上代碼:函數
// 合併 function merge(left,right){ var arr=new Array;//新建一個第三方數組 if(left[0]<=right[0]){//比較left的第一位和right的第一位誰小,小的提取出來push進第三方數組 arr.push(left.shift()) }else{ arr.push(right.shift()) } return arr.concat(left).concat(right)//將提取出來的數組和原數組歸併成一個數組 }; console.log(merge([25],[30]))//代碼到這一步只是展現了合併的原理和思路,並不完整,咱們不急,先用簡單的單元素數組進行排序合併,這也是合併的第一層合併
控制檯打印出[25,30],說明咱們的歸併和排序都是成功的,下面咱們將升級兩個函數,使其可以正式地操做複雜的歸併排序:spa
// 合併 function merge(left,right){ var arr=new Array;//新建一個第三方數組 while(left.length>0&&right.length>0){////比較left的第一位和right的第一位誰小,小的提取出來push進第三方數組 if(left[0]<=right[0]){ arr.push(left.shift()) }else{ arr.push(right.shift()) } }; return arr.concat(left).concat(right)//將提取出來的數組和原數組歸併成一個數組 }; // 拆分 function mergeSort(arr){ console.log(`arr=${arr}`) if(arr.length==1){//若是數組長度爲1則返回數組 return arr }; var mid=Math.floor(arr.length/2);//將數組一拆分爲二 var left=arr.slice(0,mid); var right=arr.slice(mid); return merge(mergeSort(left),mergeSort(right)) }; console.log(mergeSort([25,18,17,31,25,30]))
控住臺打印:
至此,咱們的歸併排序成功!
歡迎各位大小神同行予以指正和探討code