队列是一种先进先出(FIFO)的数据结构,数据只能在队尾插入或者在队首删除。队列用在很多地方,比如提交操作系统的一系列进程,打印任务池等,一些仿真系统用队列模拟银行或杂货店排队的顾客。
接下来,将从3个方面来深入理解和使用栈这种数据结构。
- 抽象数据类型定义
- 队列的JS实现
- 解决实际问题
抽象数据类型定义
属性及方法 | 作用 |
---|---|
enqueue() | 在队尾插入元素 |
dequeue() | 在队首删除元素 |
front() | 读取队首元素 |
back() | 读取队尾元素 |
empty() | 判断队列是否为空 |
clear() | 清空队列 |
count() | 记录队列长度 |
dataStore | 使用数组存储数据 |
队列的JS实现
使用构造器调用模式,这是一套类似类的对象构建语法,通过在函数前面加上
new
调用,同时this
会绑定到这个新对象上。
//Queue.js
//Queue对象定义
function Queue(){
this.dataStore = [];
this.enqueue = enqueue;
this.dequeue = dequeue;
this.empty = empty;
this.front = front;
this.back = back;
this.count = count;
this.toString = toString;//显示队列元素
}
function enqueue(element){
this.dataStore.push(element);//直接使用数组方法
}
function dequeue(){
return this.dataStore.shift();//直接使用数组方法
}
function empty(){
if(this.dataStore.length == 0)
return true;
else
return false;
}
function clear(){
this.dataStore.length = 0;
}
function front(){
return this.dataStore[0];
}
function back(){
return this.dataStore[this.dataStore.length - 1];
}
function count(){
return this.dataStore.length;
}
function toString(){
var str = "";
for(var i=0; i<this.dataStore.length; i++)
{
str += this.dataStore[i]+"\n"
}
return str;
}
//实例化Queue对象
var oneQueue = new Queue();
队列的实际应用
(一)网页展示
(二)html代码
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Queue Applications</title>
<script src="queue.js" type="text/javascript"></script>
<script src="app.js" type="text/javascript"></script>
</head>
<style>
div {
width: 60%;
margin: 30px auto;
padding: 10px;
border: 1px solid #333;
}
h2{
text-align: center;
margin: auto;
}
</style>
<body>
<h2>方块舞问题</h2>
<div>
<form>
<label for="file">请选择一个文件:</label>
<input type="file" id="file" />
<input type="button" value="读取文本文件" style="display:block;margin:20px 0;" onclick="readAsText()" />
</form>
<textarea id="dancers_content" name="dancers_content"></textarea>
</div>
<div>
<input type="button" value="入场者" onclick="getDancers()" />
<textarea id="guests_name"></textarea>
<input type="button" value="跳舞名单" onclick="goDance()" />
<textarea id="dancers_name"></textarea>
</div>
……
</body>
</html>
(三)Javascript方法
1. 舞伴分配
问题描述:当男男女女来到舞池,他们按照性别排成两队。当舞池有地方空出来时,选择两个队伍中第一个人组成舞伴。他们身后的人各自向前移动一位。
//app.js
var males = new Queue();
var females = new Queue();
function getDancers()
{
//读取依次进来的人
var content = document.getElementById("dancers_content").firstChild.nodeValue;
var names = content.split("\n");
//将人们按照性别分成两队
for(var j=0; j<names.length; j++)
{
var dancer = names[j].split(" ");
var dancer_name = dancer[1];
var dancer_sex = dancer[0];
if(dancer_sex=="F")
{
females.enqueue(new Dancer(dancer_name,dancer_sex));
}
else
{
males.enqueue(new Dancer(dancer_name,dancer_sex));
}
}
}
function goDance()
{
var name = document.getElementById("dancers_name");
name.innerHTML = "";//将结果显示在网页上
while(!males.empty() && !females.empty())
{
name.innerHTML += "Female dancer is "+females.dequeue().name +"; Male dancer is "+males.dequeue().name+".\n";
}
if(males.empty())
{
name.innerHTML += females.count() +" female dancers are waiting."
}
if(females.empty())
{
name.innerHTML += males.count() +" male dancers are waiting."
}
}
2. 基数排序
基数排序具体原理可以参考百度百科。
//app.js
//生成含有12个元素的初始数组,待排序
var startNums = [];
function beforeSort(){
for(var i=0; i<12; i++)
{
startNums[i] = Math.floor(Math.random()*101+1);
}
//将生成的数组显示在网页上
var originalNums = document.getElementById("original_nums");
originalNums.value = "";
for(var i=0; i<startNums.length; i++)
{
originalNums.value += startNums[i]+" ";
}
}
//有10个队列,编号分别为0-9
var globalQueues = [];
for(var i=0; i<10; i++)
{
globalQueues[i] = new Queue();
}
//根据数组中每个数字十位或者个位的数值,将数字分配到对应队列
function distribute(nums, queues, n, 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 sort(){
distribute(startNums, globalQueues, startNums.length, 1);
collect(globalQueues, startNums);
distribute(startNums, globalQueues, startNums.length, 10);
collect(globalQueues, startNums);
//将排序结果显示在网页上
var sortedNums = document.getElementById("sorted_nums");
sortedNums.value = "";
for(var i=0; i<startNums.length; i++)
{
sortedNums.value += startNums[i]+" ";
}
}
3. 优先队列
优先队列:在优先队列中删除元素时,需要考虑优先级的限制。
//app.js
//模拟医院急诊室,当病人进入门诊时,会根据病情严重情况,获得优先级排序。高优先级的患者先于低优先级的患者就医。
//构建病人对象,code为优先级,1为最高优先级
function Patient(name, code)
{
this.name = name;
this.code = code;
}
//优先队列只有出列操作不同于普通队列,需要先比较优先级
function pridequeue(){
var entry = 0;
for(var i=1; i<this.dataStore.length; i++)
{
if(this.dataStore[entry].code > this.dataStore[i].code)
entry = i;
}
return this.dataStore.splice(entry, 1);
}
//模拟创建急诊病人的优先队列
var pri = new Queue();
pri.enqueue(new Patient("Fehrenback", 6));
pri.enqueue(new Patient("Jones", 4));
pri.enqueue(new Patient("Smith", 5));
pri.enqueue(new Patient("Brown", 1));
pri.enqueue(new Patient("Ingram", 1));
function showPri(){
var firstP = pri.pridequeue();
var secondP = pri.pridequeue();
var thirdP = pri.pridequeue();
//将优先出列的病人名字显示在网页上
var priPatients = document.getElementById("pri_patients");
priPatients.value = "1."+ firstP[0].name + " 2."+ secondP[0].name + " 3."+ thirdP[0].name;
}