隊列是一種列表,不一樣的是隊列只能在末尾插入元素,在隊首刪除元素。隊列用於存儲按順序排列的數據。先進先出。這點和棧不同,在棧中,最後入棧的元素反被優先處理。能夠將隊列想象成銀行排隊辦理業務的人,排隊在第一個的人先辦理業務,其它人只能排着,直到輪到他們爲止。javascript
隊列是一種先進先出(FIFO)的數據結構。隊列被用在不少地方。好比提交操做系統執行一系列進程。打印任務池等。一些仿真系統用來模擬銀行或雜貨店裏排隊的顧客。html
一,隊列的操做。java
隊列的兩種主要操做是:向隊列中插入新元素和刪除隊列中的元素。插入操做也叫作入隊。刪除元素也叫作出隊。入隊是在末尾插入新元素,出隊是刪除隊頭的元素。git
隊列的另一項操做是讀取隊頭的元素,這個操做叫peek()。該操做返回隊頭的元素,但不把它從隊列中刪除。除了讀取隊頭的元素,咱們想知道隊列中有多少元素,可使用length屬性知足要求;要想清空隊列中全部元素。可使用clear()方法來實現。算法
二,一個數組實現的隊列。編程
使用數組來實現隊列看起來瓜熟蒂落。javascript中的數組具備其它編程語言中沒有的優勢,數組的push()能夠在數組末尾加入元素,數組的shift()方法則能夠刪除數組的第一個元素。數組
push()方法將它的參數插入數組中第一個開放的位置,該位置總在數組的末尾,即便是個空數組也是如此。數據結構
names = []; names.push("Cny"); names.push("Jen"); console.log(names);//["Cny", "Jen"]
而後使用shift()方法刪除數組的第一個元素:dom
names.shift(); console.log(names);//["Jen"]
準備開始實現Queue類。先從構造函數開始:編程語言
function Queue() { this.dataStore = []; this.enqueue = enqueue; this.dequeue = dequeue; this.front = front; this.back = back; this.toString = toString; this.empty = empty; }
enqueue()方法向隊末尾添加一個元素:
function enqueue(element) { this.dataStore.push(element) }
dequeue方法刪除隊首的元素
function dequeue() { return this.dataStore.shift(); }
可使用如下方法讀取隊首和隊末的元素
function front() { return this.dataStore[0]; } function back() { return this.dataStore[this.dataStore.length - 1] }
還須要toString()方法顯示隊列內的全部元素
function toString() { var retStr = ""; for (var i = 0; i < this.dataStore.length; ++i ) { retStr += this.dataStore[i] + "\n"; } return retStr }
最後,須要一個方法判斷隊列是否爲空
function empty() { if (this.dataStore.length == 0) { return true; } else { return false; } }
Queue類的定義和測試
function Queue() { this.dataStore = []; this.enqueue = enqueue; this.dequeue = dequeue; this.front = front; this.back = back; this.toString = toString; this.empty = empty; } //向隊末尾添加一個元素 function enqueue(element) { this.dataStore.push(element) } //刪除隊首的元素 function dequeue() { return this.dataStore.shift(); } function front() { //讀取隊首和隊末的元素 return this.dataStore[0]; } function back() { ////讀取隊首和隊末的元素 return this.dataStore[this.dataStore.length - 1] } //顯示隊列內的全部元素 function toString() { var retStr = ""; for (var i = 0; i < this.dataStore.length; ++i ) { retStr += this.dataStore[i] + "\n"; } return retStr } //隊列是否爲空 function empty() { if (this.dataStore.length == 0) { return true; } else { return false; } } //測試程序 var q = new Queue(); q.enqueue("Me"); q.enqueue("Her"); q.enqueue("His"); console.log(q.toString()); q.dequeue(); console.log(q.toString()); console.log("第一個元素是: " + q.front()); console.log("最後一個元素是: " + q.back())
三,使用隊列,方塊舞和舞伴的分配問題
前面咱們提到過,常常用隊列模擬排隊的人。下面,咱們使用隊列來模擬跳方塊舞的人。當男男女女來到舞池,他們按照本身的性別排成兩隊。當舞池中有地方空出來的時候,兩個隊列中的第一我的組成舞伴。他們身後的人各自向前一位,組成新的隊首。當一對新的舞伴進入舞池時,主持人會大喊出他們的名字。當一對舞伴走出舞池,且兩隊隊伍任意一隊沒有人時,主持人會把這個狀況告訴你們。
爲了模擬這個狀況,咱們將男男女女姓名存儲在一個文本文件。
女 小李
男 福來
男 強子
男 李勇
女 小梅
男 來福
女 艾麗
男 張帆
男 文強
男 丁力
女 娜娜
每一個舞者的信息都被保存在一個Dancer對象中:
function Dancer(name, sex) { this.name = name; this.sex = sex; }
咱們須要一個函數,將舞者的信息讀到程序中來。
function getDancers(males, females) { //var names = _names.split("\n"); var names = _names.split("**"); for (var i = 0; i < names.length; ++i) { names[i] = names[i].trim(); } for (var i = 0; i < names.length; ++i) { var dancer = names[i].split(" "); var sex = dancer[0]; var name = dancer[1]; if (sex == "女") { females.enqueue(new Dancer(name, sex)); } else { males.enqueue(new Dancer(name, sex)) } } }
此函數將舞者按照性別分在不一樣的隊列中。
下一個函數將男性和女性組成舞伴,並宣佈配對結果:
function dance(males, females) { console.log("這組舞伴是:") while (!females.empty() && !males.empty()) { person = females.dequeue(); console.log("女舞者是" + person.name); person = males.dequeue(); console.log("男舞者是" + person.name); } }
咱們可能對該程序作修改,想顯示排隊時男性女性的數量,隊列中目前沒有顯示元素個數的方法。如今加入
function count(){ return this.dataStore.length; }
綜合測試:
function Queue() { this.dataStore = []; this.enqueue = enqueue; this.dequeue = dequeue; this.front = front; this.back = back; this.toString = toString; this.empty = empty; this.count = count; } //向隊末尾添加一個元素 function enqueue(element) { this.dataStore.push(element) } //刪除隊首的元素 function dequeue() { return this.dataStore.shift(); } function front() { //讀取隊首和隊末的元素 return this.dataStore[0]; } function back() { ////讀取隊首和隊末的元素 return this.dataStore[this.dataStore.length - 1] } //顯示隊列內的全部元素 function toString() { var retStr = ""; for (var i = 0; i < this.dataStore.length; ++i ) { retStr += this.dataStore[i] + "\n"; } return retStr } //隊列是否爲空 function empty() { if (this.dataStore.length == 0) { return true; } else { return false; } } //隊列個數 function count(){ return this.dataStore.length; } function Dancer(name, sex) { this.name = name; this.sex = sex; } function getDancers(males, females) { //var names = _names.split("\n"); var names = _names.split("**"); for (var i = 0; i < names.length; ++i) { names[i] = names[i].trim(); } for (var i = 0; i < names.length; ++i) { var dancer = names[i].split(" "); var sex = dancer[0]; var name = dancer[1]; if (sex == "女") { females.enqueue(new Dancer(name, sex)); } else { males.enqueue(new Dancer(name, sex)) } } } function dance(males, females) { console.log("這組舞伴是:") while (!females.empty() && !males.empty()) { person = females.dequeue(); console.log("女舞者是" + person.name); person = males.dequeue(); console.log("男舞者是" + person.name); } } //測試程序 var _names = "女 小李**男 福來**男 強子**男 李勇**女 小梅**男 來福**女 艾麗**男 張帆**男 文強**男 丁力**女 娜娜"; var names = _names.split("**"); //測試程序 var maleDancer = new Queue(); var femaleDancer = new Queue(); getDancers(maleDancer, femaleDancer); dance(maleDancer, femaleDancer) if (!femaleDancer.empty()) { console.log(femaleDancer.front().name + "正在等待跳舞") } if (!maleDancer.empty()) { console.log(maleDancer.front().name + "正在等待跳舞") } //顯示等待跳舞的人個數 var nanDancers = new Queue(); var nvDancers = new Queue(); getDancers(nanDancers, nvDancers) dance(nanDancers,nvDancers); if (nanDancers.count() > 0) { console.log("有" + nanDancers.count() + "男舞者等待") } if (nvDancers.count() > 0) { console.log("有" + mvDancers.count() + "女舞者等待") }
四:使用隊列對數據進行排序
隊列不只用於執行顯示生活中與排隊有關的操做,還能夠用於對數據進行排序。計算機剛出現時,程序是經過穿孔卡輸入主機的,每張卡包含一條程序語句。這些穿孔卡裝在一個盒子裏,通過一個繼續裝置進行排序。咱們可使用一組隊列來模擬這一過程。這種技術叫基數排序。它不是最快的排序算法,可是它展現了一些有趣的隊列使用方法。
對於0-99的數字,基數排序將數據掃描兩次。第一次按個位上的數字進行排序,第二次按照十位上的數字進行排序。每一個數字根據對於位上的數值被分在不一樣的盒子裏。假設有以下數字:
91,46,85,15,92,35,31,22
通過基數排序第一次掃描後,數字被分配到如下盒子裏
Bin 0 : Bin 1 : 91, 31 Bin 2 : 82, 22 Bin 3 : Bin 4 : Bin 5 : 85, 35 Bin 6 : 46 Bin 7 : Bin 8 : Bin 9 :
根據盒子的順序,對數字第一次排序的結果以下
91,31,92,22,85,15,25,46
根據十位上的數字,再次排序。
Bin 0 : Bin 1 : 15 Bin 2 : 22 Bin 3 : 31, 35 Bin 4 : 46 Bin 5 : Bin 6 : Bin 7 : Bin 8 : 85 Bin 9 : 91, 92
最後,將盒子中的數字去除,組成一個新的列表,該列表即爲排好序的數字:
15, 22, 31, 35, 46, 85, 91, 92
使用隊列表明盒子,能夠實現這個算法。咱們須要9個隊列,每個對應一個數字。全部隊列保存在一個數組中,使用取餘和除法操做決定個位和十位。算法的剩餘部分將數字加入相應隊列,根據個位數值對其重新排序,而後根據十位上的數值進行排序。結果即爲排列好的數字
下面是根據 相應位(個位或十位)上的數值,將數字分配到相應隊列的函數:
function distribute(nums, queues, n, digit) { //digit表示個位和十位上的值 for (var i = 0 ; i < n ; ++i) { if (digit == 1) { queues[nums[i]%10].enqueue(nums[i]); } else { queues[Math.floor(nums[i]/10).enqueue(nums[i])] } } }
下面是從隊列中收集數字的函數
function collect(queues, nums){ var i = 0; for (var digit = 0; digit < 10; ++digit) { while(!queues[digit].empty()){ nums[i++] = queues[digit].dequeue() } } }
附上測試代碼
function Queue() { this.dataStore = []; this.enqueue = enqueue; this.dequeue = dequeue; this.front = front; this.back = back; this.toString = toString; this.empty = empty; this.count = count; } //向隊末尾添加一個元素 function enqueue(element) { this.dataStore.push(element) } //刪除隊首的元素 function dequeue() { return this.dataStore.shift(); } function front() { //讀取隊首和隊末的元素 return this.dataStore[0]; } function back() { ////讀取隊首和隊末的元素 return this.dataStore[this.dataStore.length - 1] } //顯示隊列內的全部元素 function toString() { var retStr = ""; for (var i = 0; i < this.dataStore.length; ++i ) { retStr += this.dataStore[i] + "\n"; } return retStr } //隊列是否爲空 function empty() { if (this.dataStore.length == 0) { return true; } else { return false; } } //隊列個數 function count(){ return this.dataStore.length; } //基礎排序程序 function distribute(nums, queues, n, digit) { //digit表示個位和十位上的值 for (var i = 0 ; i < n ; ++i) { if (digit == 1) { queues[nums[i]%10].enqueue(nums[i]); } else { queues[Math.floor(nums[i] / 10)].enqueue(nums[i]) } } } function collect(queues, nums){ var i = 0; for (var digit = 0; digit < 10; ++digit) { while(!queues[digit].empty()){ nums[i++] = queues[digit].dequeue() } } } function dispArray(arr) { for (var i = 0; i < arr.length; ++i) { console.log(arr[i] + " ") } } //主程序 var queues = [] for (var i = 0; i < 10; ++i) { queues[i] = new Queue(); } var nums = [] for (var i = 0; i < 10; ++i){ nums[i] = Math.floor(Math.floor(Math.random() * 101)) } console.log("以前的基數:") dispArray(nums); distribute(nums, queues, 10, 1); collect(queues, nums); distribute(nums,queues, 10 ,10); collect(queues, nums); console.log("以後的基數:") dispArray(nums)
五:優先隊列方法
在通常的狀況下,從隊列中刪除的元素,必定是率先入隊的元素。可是也有一些使用隊列的應用 ,在刪除元素時沒必要遵照先進先出的約定。這周應用,須要使用一個叫優先隊列的數據結構來進行模擬。
從優先隊列中刪除元素時,須要考慮優先權的限制。好比醫院急診科的候診室,就是一個採用優先隊列的例子。當病人進入候診室,分診會評估病情的嚴重程度,而後給一個優先級代碼。高優先級的患者優先於低優先級者就醫,一樣優先級的患者按照優先來服務的順序就醫。
先來定義存儲隊列元素的對象,而後再構建咱們的優先隊列系統。
function Patient(name, code){ this.name = name; this.code = code; }
變量code是一個整數,表示優先級
如今須要重新定義dequeue()方法。使其刪除隊列中優先級最高級的元素。咱們規定:優先碼的值最小的元素優先級最高。新的dequeue()方法遍歷隊列底層存儲數組,從中找出優先碼最低的元素,而後使用數據的splice()方法刪除優先級最高的元素。新的dequeue()方法定義以下所示:
function dequeue() { var priority = this.dataStore[0].code; for (var i = 1; i < this.dataStore.length; ++i) { if (this.dataStore.[i].code < priority) { priority = i } } return this.dataStore.splice(priority,1) }
dequeue()方法使用簡單的順序查找方法尋找優先級最高的元素(優先碼最小優先級越高,好比1比5的優先級高)該方法返回包含一個元素的數組---從隊列中刪除的元素。
最後,定義toString()來顯示patient對象
function toString() { var retStr = ""; for (var i=0; i < this.dataStore.length; ++i) { retStr += this.dataStore[i].name + " code:" + this.dataStore[i].code + "\n" } return retStr }
(本文完結)
上一章:第四章:javascript: 棧 下一章:第六章: 字典