之前不寫技術博客,但寫文章,寫段子,深入體會過「寫」的妙處。 寫博客,不止是分享的過程,更不是單純的記錄,它還有個特殊功效,就是產生更多細緻具體的思考。思惟在腦海中是徹底自由的,但落筆時,它受到約束,你必須讓本身有理有據。因此不少思惟上的小漏洞,會在寫出來時暴露,而新的想法,也可能會在落筆的時候促生。這是妙處。前端
所以,開個小系列,寫技術博客。這是原因。git
這個小系列,主要練習一些基礎算法,從排序、查找開始,中後期會有一些數圖,最短路徑都常見算法。本人是前端程序員,因此目的旨在掌握常見算法,更多的高能,暫時不打算深刻,由於時間有限,還要騰出時間去了解學習前端龐大繁雜的生態。程序員
至於身爲前端爲何搞算法?github
首先基礎算法掌握一下,是CS畢業生對本身的基本要求。面試
再者算法玩起來,會對本身有個提醒,作程序員,必定要玩出腦力工做,而不是溫馨地保持在體力工做。算法用做鍛鍊邏輯思惟。算法
再功利一點,面試的時候,會派上用場,多少前端高手摺在了手寫二分上面?遺憾。typescript
本系列的代碼,除了會摘取關鍵部分貼到博文中以外,全部代碼均會放在一個倉庫內,託管到github。算法部分以用typescript進行編寫,正好同時學習ts,用karam + mocha + chai 編寫測試,(如今還沒建好,地址多是git@github.com:qixman/An-algorithm-a-day
)。有興趣的,能夠clone下來,也歡迎把意見、建議,以issue形式提出。也歡迎拍磚,雷霆雨露,俱是君恩。編程
快速排序,它的主要邏輯是,把待排序的序列,以某個元素爲基準K(具體是哪一個?無所謂,但通常會選擇第一個元素),將序列分紅兩個部分,A部分所有大於這個基準,B部分所有小於這個基準。若是你把A,B部分都做爲一個總體,那麼如今你獲得的就是一個有序序列。A < K < B。性能
不過暫時還沒結束,由於A,B內部,尚未獲得排序。怎麼辦?對A,B再進行上述操做。學習
沒錯,這裏就是要用一個遞歸。
遞歸是一個很是有趣的概念。我記得在我剛剛學習編程時,深深地爲這種思惟模式的能力吸引,由於相比於一步一步推算公式得出結果,這種方式充滿了智能和自動化。
這裏不講遞歸定義, 它大概的樣子,其實就是一個調用它自身的方式,來處理問題。由此能夠看出,它很是適合那種在處理數據時,有循環邏輯的狀況。好比上述的快排,它的循環操做就是,不斷將一個序列,分化成 A < K < B 的模式(若是是降序,則 A > K > B)。而這個循環操做就是遞歸的主體部分。
不斷調用自身,會陷入死循環。所以只有主體是不夠的,遞歸的另外一個部分,就是終止條件,這個很關鍵。仍是以快排爲例。主體操做是將一個序列處理成 A < K < B, 但若是接受到的是一個只有1個元素的序列,或空序列,那麼繼續下去就毫無心義。此時就是遞歸在當前分支
終止的最佳時機。請注意,這裏點亮了當前分支
,由於遞歸極可能沿着多條路徑遞歸,好比本次快排,子節點會像二叉樹同樣向外發散(這也是遞歸會產生性能問題的緣由,時間複雜度會上升到指數級別)。所以當終止條件結束遞歸的時候,它可能只是終止了當前分支的遞歸,而總體部分,仍在繼續運轉。
這裏對遞歸進行了科普,你們也能發現,在科普遞歸的時候,實際上快速排序的思路,已經很全面的進行了分析。那麼代碼就比較容易了。
最終代碼以下:
export default function quickSort(arr: number[], isAscending: boolean): number[] { if (1 === arr.length) return arr; if (0 === arr.length) return []; let small: number[] = []; let big: number[] = []; let equal: number[] = []; let key = arr[0]; for (let i: number = 0; i < arr.length; i++) { if (arr[i] < key) { small.push(arr[i]); } else if (arr[i] > key) { big.push(arr[i]); } else { equal.push(arr[i]); } } if (isAscending) { return [].concat(quickSort(small, isAscending), equal, quickSort(big, isAscending)); } return [].concat(quickSort(big, isAscending), equal, quickSort(small, isAscending)); }
測試用例以下
var quickSort = require('../dist/quicksort.js').default; var assert = require('chai').assert; describe('quickSort', () => { it("should return sorted array.", () => { assert.deepEqual(quickSort([3, 4, 2, 1, 5], true), [1, 2, 3, 4, 5]); }); it("has only one number", () => { assert.deepEqual(quickSort([1], true), [1]); }); it("has no number", () => { assert.deepEqual(quickSort([], true), []); }); it("should repeating number", () => { assert.deepEqual(quickSort([3,1,2,2,2], true), [1,2,2,2,3]); }); });