javascript數據結構——隊列
隊列是一種先進先出的數據結。隊列只能在隊尾插入元素,在隊首刪除元素,這點和棧不一樣。它用於存儲順序排列的數據。隊列就像我們日常中的排隊一樣,排在最前面的第一個辦理業務,新來的人只能在後面排隊。隊列這種數據結構在編程中被用到很多地方。
定義隊列的操作
上圖展示了隊列的兩個操作,入隊和出隊。出隊操作是刪除對頭的元素,入隊操作是在隊尾添加元素。除此之外我們還需要能夠獲取隊首和隊尾的元素或者全隊列的元素,還需要知道隊列的長度,還需要一個方法來清空隊列,由此,我們定義隊列的方法。
- enqueue() 入隊
- dequeue() 出隊
- front() 返回隊首
- back() 返回隊尾
- toString() 返回所有隊列中所有元素
- length() 返回隊列的長度
- clear() 清空隊列
隊列的實現
javascript中的數組具有其他編程語言的數組沒有的缺點,直接只用數組的push()方法就可以在數組末端加入元素,使用shift()方法可以刪除數組的第一個元素。使用數組來實現隊列順理成章。
準備開始實現對列Queue類,先從構造函數開始;
function Queue() { this.dataStore = []; this.enqueue = enqueue;this.dequeue = dequeue; this.front = front; this.back = back; this.toString = toString; this.length = length; }
接下來開始實現對列的各個方法。
enqueue()方法向隊尾添加一個元素,dequeue()方法刪除隊首的元素:
function enqueue(element) { this.dataStore.push(element); // 把新來的元素放在隊尾 } function dequeue() { returnthis.dataStore.shift(); // 刪除隊首元素,並把這個元素返回 }
front()和back()方法分別是返回隊列的隊首和隊尾的元素:
function front() { return this.dataStore[0]; // 返回隊首元素 } function back() { return this.dataStore[this.dataStore.length - 1]; // 返回隊尾元素 }
toString() 方法顯示隊列內的所有元素:
function toString() { var retStr = ‘‘; this.dataStore.forEach(val => { // 遍歷隊列,把隊列中的所有元素拼成字符串返回 retStr += val + ‘\n‘; }); return retStr; }
length() 方法返回隊列長度,clear()方法清空隊列:
function length() { return this.dataStore.length; } function clear() { this.dataStore.length = 0; // 通過把隊列的長置0來清空隊列 }
到此,隊列這種數據結構借助javascript已經實現了。接下來測試一下。
隊列的測試
測試代碼:
const q = new Queue(); q.enqueue(‘java‘); q.enqueue(‘php‘); q.enqueue(‘python‘); console.log(‘隊列裏的所有元素:‘); console.log(q.toString()); q.dequeue() console.log(‘出隊之後所有元素:‘); console.log(q.toString()); console.log(‘隊首元素:‘ + q.front()); console.log(‘隊尾元素:‘ + q.back()); console.log(‘隊列長度:‘ + q.length()); q.clear(); console.log(‘清空隊列後的長度:‘ + q.length());
輸出結果:
輸出結構符合預期。
優先隊列
在一般情況下,從隊列中刪除的元素,一定是率先入隊的元素。但有的特殊情況不用遵守先進先出的約定。比如急診室裏的隊列,醫生會根據病人病情的嚴重程度來決定服務的優先級。在這種隊列裏,從隊列中刪除的元素就有可能不是最先入隊的元素。這種情況,就需要使用一個叫優先隊列的數據結構來模擬。
接下來,我們以急診室排隊為例,實現以下優先隊列。
在急診室的候診室裏,分診護士會評估患者病情的嚴重程度,然後給一個優先級代碼,高優先級的患者先於低優先級的患 者就醫,同樣優先級的患者按照先來先服務的順序就醫。
先來定義存儲隊列元素的對象,然後再構建我們的優先隊列系統:
function Patient(name, code) { this.name = name; this.code = code; // 優先級代碼,整數,代表患者優先級 }
現在需要重新定義 dequeue() 方法,使其刪除隊列中擁有最高優先級的元素。我們規定優先碼的值最小的元素優先級最高。新的 dequeue() 方法遍歷隊列的底層存儲數組,從中找出優先碼最小的元素,然後刪除該元素。新的dequeque()方法定義如下所示:
function dequeue() { let priority = this.dataStore[0].code; let pos = 0; // 使用簡單的順序查找方法尋找優先級最高的元素 this.dataStore.forEach((p, i) => { if (p.code < priority) { priority = p.code; pos = i; } }); // 返回從隊列中刪除的元素 return this.dataStore.splice(pos, 1); }
最後,重新實現toString()方法來顯示Patient對象。
function toString() { var retStr = ""; this.dataStore.forEach(p => { retStr += `${p.name} 優先級: ${p.code}\n`; }); return retStr; }
到此,模擬的急診優先隊列已經實現完成,我們測試一下。
var p = new Patient("小一", 5); const ed = new Queue(); ed.enqueue(p); p = new Patient("小二", 4); ed.enqueue(p); p = new Patient("小三", 6); ed.enqueue(p); p = new Patient("小四", 1); ed.enqueue(p); p = new Patient("小五", 1); console.log(‘正在排隊的人:‘); console.log(ed.toString()); // 第一輪 ed.enqueue(p); var seen = ed.dequeue(); console.log(‘正在被接診的病人:‘ + seen[0].name); console.log(‘等待的人:‘) console.log(ed.toString()); // 下一輪 var seen = ed.dequeue(); console.log(‘正在被接診的病人:‘ + seen[0].name); console.log(‘等待的人:‘) console.log(ed.toString()); // 下一輪 var seen = ed.dequeue(); console.log(‘正在被接診的病人:‘ + seen[0].name); console.log(‘等待的人:‘) console.log(ed.toString());
輸入結果:
可以看到,待診病人按照優先級,一個一個的從隊列中被接診。
javascript數據結構——隊列