本系列全部文章:
第一篇文章:學習數據結構與算法之棧與隊列
第二篇文章:學習數據結構與算法之鏈表
第三篇文章:學習數據結構與算法之集合
第四篇文章:學習數據結構與算法之字典和散列表
第五篇文章:學習數據結構與算法之二叉搜索樹javascript
最近要準備校招,打開某網站準備開始刷題,發現算法題根本沒法動手,因而以爲這塊須要惡補。(⊙v⊙)嗯,至少得先知道概念吧。因而翻出了機房裏的這本《學習JavaScript數據結構與算法》開始學習程序員的基礎知識。這本書用了我最熟悉的JS來實現各類數據結構和算法,並且書很薄,能夠說是一本不錯的入門教程。雖然我是個前端,可是計算機基礎不能丟下。前端
棧能夠理解爲一種特殊的數組。遵循後進先出(LIFO)的原則,元素在棧頂添加和刪除。生活中經常使用來比做棧的例子主要是一疊盤子或一堆書,可是我以爲不夠形象,由於盤子或書能夠從中間被抽走。因此我通常把棧當作彈匣,想象一會兒彈被一個個推動彈匣中,好比下圖:java
(圖片來自谷歌搜索,侵刪)git
聲明一個構造函數:程序員
function Stack () { // 使用數組來保存棧元素 var items = [] }
爲棧聲明一些方法:github
用數組的push方法向數組末尾添加新元素,實現元素入棧算法
// 棧頂添加 this.push = function (element) { items.push(element) }
用數組的pop方法在數組末尾刪除一個元素,並返回刪除元素,實現元素出棧segmentfault
// 棧頂刪除並返回刪除元素 this.pop = function () { return items.pop() }
棧頂就是數組最後一個元素,使用Array[Array.length - 1]得到數組
// 返回棧頂元素 this.peek = function () { return items[items.length - 1] }
隊列裏面也用了這些方法,爲避免重複,就先單獨拿出來了。數據結構
// 棧是否爲空 this.isEmpty = function () { return items.length === 0 } // 返回棧裏的元素個數 this.size = function () { return items.length } // 清空棧 this.clear = function () { items = [] } // 打印棧 this.print = function () { console.log(items.toString()) }
書上的例子有將十進制轉二進制,這裏我把後面那個十進制轉任意進制的代碼貼出來。
十進制轉二進制原理很簡單:把十進制數不斷除以2直到爲0,而後把每次的餘數拼接到一塊兒就是二進制數。
轉其餘進制也是相似的方法,只不過是把除以2換成其餘數而已。代碼以下:
// 把十進制轉成任何進制 function BaseConverter (decNumber, base) { var remStack = new Stack(), rem, binaryString = '', digits = '0123456789ABCDEF' // 判斷十進制數是否爲0,把餘數推入棧中 while (decNumber > 0) { rem = Math.floor(decNumber % base) remStack.push(rem) decNumber = Math.floor(decNumber / base) } // 把棧中的元素拼接打印出來 while (!remStack.isEmpty()) { binaryString += digits[remStack.pop()] } // 返回轉換的二進制數 return binaryString }
這裏的decNumber是要轉換的十進制數,base是要轉換的進制,remStack是上面Stack的實例,在remStack中操做棧的方法。這裏的digits是對打印出來的數作一個處理,好比十六進制的數餘數會大於9,那麼就要用A、B、C、D、E、sF來表示10~15。
棧的學習暫時就這樣了,這裏貼上代碼地址,有興趣的能夠看看:
和棧很相似,只是原則不一樣,隊列是先進先出(FIFO),又稱先來先服務。隊列在頭部刪除元素,尾部添加元素。生活中隊列的例子就是排隊了,這也很容易理解。
一樣聲明構造函數:
function Queue () { var items = [] }
隊列的方法:
其餘的和棧同樣。
用push方法推入元素
// 向隊列尾部添加元素 this.enqueue = function (element) { items.push(element) }
用shift方法刪除第一個數組元素,並返回刪除的元素
// 刪除隊列頭部的元素並返回刪除元素 this.dequeue = function () { return items.shift() }
直接返回第一個數組元素
// 返回隊列頭部的元素 this.front = function () { return items[0] }
書上有講優先隊列和循環隊列的應用,這裏就簡單講一下優先隊列的原理:
要實現優先隊列有兩種思路:一是將元素按正確的位置添加到隊列中,而後元素正常在隊列頭部被刪除;二是元素在隊列尾部不按優先級正常入列,而後按優先級刪除對應元素。
書上是按第一種思路實現的優先隊列,這裏限於篇幅就貼上代碼地址:
接下來談談循環隊列的應用——擊鼓傳花遊戲
function hotPotato (nameList, num) { var queue = new Queue() // 參與者的名字入列 for (var i = 0; i < nameList.length; i++) { queue.enqueue(nameList[i]) } var eliminated = '' // 隊列中的最後一我的爲勝者 while (queue.size() > 1) { // 按設定的擊鼓次數,每一個人都從隊列頭部出列轉到隊列尾部(模擬傳花) for (var i = 0; i < num; i++) { queue.enqueue(queue.dequeue()) } // 到了規定次數後,在隊列頭部的人(至關於拿到花)被淘汰 eliminated = queue.dequeue() console.log(eliminated + '在擊鼓傳花遊戲中被淘汰') } // 勝者出列並被返回 return queue.dequeue() }
其中nameList是參與遊戲的名字列表,num是擊鼓次數。
隊列學習就暫時到這裏,明天繼續學習鏈表。