队列是一种列表,不同的是队列只能在末尾插入元素,在队首删除元素。队列用于存储按顺序排列的数据。先进先出。这点和栈不一样,在栈中,最后入栈的元素反被优先处理。可以将队列想象成银行排队办理业务的人,排队在第一个的人先办理业务,其它人只能排着,直到轮到他们为止。

队列是一种先进先出(FIFO)的数据结构。队列被用在很多地方。比如提交操作系统执行一系列进程。打印任务池等。一些仿真系统用来模拟银行或杂货店里排队的顾客。

一,队列的操作。

队列的两种主要操作是:向队列中插入新元素和删除队列中的元素。插入操作也叫做入队。删除元素也叫做出队。入队是在末尾插入新元素,出队是删除队头的元素。

队列的另外一项操作是读取队头的元素,这个操作叫peek()。该操作返回队头的元素,但不把它从队列中删除。除了读取队头的元素,我们想知道队列中有多少元素,可以使用length属性满足要求;要想清空队列中所有元素。可以使用clear()方法来实现。

二,一个数组实现的队列。

使用数组来实现队列看起来顺理成章。javascript中的数组具有其它编程语言中没有的优点,数组的push()可以在数组末尾加入元素,数组的shift()方法则可以删除数组的第一个元素。

push()方法将它的参数插入数组中第一个开放的位置,该位置总在数组的末尾,即使是个空数组也是如此。

    names = [];
names.push("Cny");
names.push("Jen");
console.log(names);//["Cny", "Jen"]

然后使用shift()方法删除数组的第一个元素:

    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: 栈 下一章第六章: 字典

第五章:javascript:队列的更多相关文章

  1. 第五章 JavaScript对象及初识面向对象

    第五章   JavaScript对象及初识面向对象 一.对象 在JavaScript中,所有事物都是对象,如字符串.数值.数组.函数等. 在JavaScript对象分为内置对象和自定义对象,要处理一些 ...

  2. 学习笔记 第十五章 JavaScript基础

    第15章   JavaScript基础 [学习重点] 了解JavaScript基础知识 熟悉常量和变量 能够使用表达式和运算符 正确使用语句 能够掌握数据类型和转换的基本方法 正确使用函数.对象.数组 ...

  3. 第五章JavaScript

    创建数组://1.字面量方式创建 (推荐大家使用这种方式创建数组 简单粗暴) var colors = ['red','color','yellow'];console.log(colors) //空 ...

  4. 第五章 javascript编程可养成的好习惯

    用户点击某个链接时弹出一个新窗口javascript使用window对象的open()方法来创建新的浏览器窗口,这个方法有三个参数:window.open(url,name,features)url: ...

  5. 为什么我要放弃javaScript数据结构与算法(第五章)—— 链表

    这一章你将会学会如何实现和使用链表这种动态的数据结构,这意味着我们可以从中任意添加或移除项,它会按需进行扩张. 本章内容 链表数据结构 向链表添加元素 从链表移除元素 使用 LinkedList 类 ...

  6. 读《编写可维护的JavaScript》第五章总结

    第五章 UI层的松耦合 5.1 什么是松耦合 在Web开发中,用户界面是由三个彼此隔离又相互作用的层定义的: HTML是用来定义页面的数据和语义 CSS用来给页面添加样式 JavaScript用来给页 ...

  7. Javascript权威指南——第二章词法结构,第三章类型、值和变量,第四章表达式和运算符,第五章语句

    第二章 词法结构 一.HTML并不区分大小写(尽管XHTML区分大小写),而javascript区分大小写:在HTML中,这些标签和属性名可以使用大写也可以使用小写,而在javascript中必须小写 ...

  8. ArcGIS API for JavaScript 4.2学习笔记[16] 弹窗自定义功能按钮及为要素自定义按钮(第五章完结)

    这节对Popups这一章的最后两个例子进行介绍和解析. 第一个[Popup Actions]介绍了弹窗中如何自定义工具按钮(名为actions),以PopupTemplate+FeatureLayer ...

  9. [书籍翻译] 《JavaScript并发编程》第五章 使用Web Workers

    本文是我翻译<JavaScript Concurrency>书籍的第五章 使用Web Workers,该书主要以Promises.Generator.Web workers等技术来讲解Ja ...

  10. 第十五章、线程之queue模块的各种队列

    目录 第十五章.线程之queue模块的各种队列 一.Queue 二.LifoQueue堆栈 三.PriorityQueue优先级队列 第十五章.线程之queue模块的各种队列 一.Queue impo ...

随机推荐

  1. Windows 网络问题

    一.问题描述 每次重启后电脑的ip地址或无故没掉,或不能正常连网,要重新设置ip才能上网.   二.解决方法 在DOS窗口执行 netsh winsock reset netsh int ip res ...

  2. 数据库配置文件 conf.properties

    #数据库配置 #mysql hibernate.dialect =org.hibernate.dialect.MySQLDialect jdbc.driverClassName =com.mysql. ...

  3. WEB安全--业务安全漏洞

    0x00 索引说明 在OWASP的分享,关于业务安全的漏洞检测模型. 0x01 身份认证安全 1 暴力破解 在没有验证码限制或者一次验证码可以多次使用的地方,使用已知用户对密码进行暴力破解或者用一个通 ...

  4. codeforces gym-101078

    题目链接: http://codeforces.com/gym/101078 A: #include <iostream> #include <cstdio> #include ...

  5. 搜索服务solr 一二事(1) - solr-5.5 使用自带Jetty或者tomcat 搭建单机版搜索服务器

    solr,什么是solr,就是你要吃的东西“馊了”,不能吃了,out of date~ 嘛...开个玩笑,发音就是‘搜了’,专门用于搜索的一个开源框架,lunce就不说了,不好用,麻烦 来讲讲solr ...

  6. VS代码片段(snippet)创作工具——Snippet Editor(转)

    原文:http://blog.csdn.net/oyi319/article/details/5605502 从Visual Studio 2005开始,IDE支持代码片段.代码片段以代码缩写和TAB ...

  7. 区块链技术(一):Truffle开发入门

    以太坊是区块链开发领域最好的编程平台,而truffle是以太坊(Ethereum)最受欢迎的一个开发框架,这是我们第一篇区块链技术文章介绍truffle的原因,实战是最重要的事情,这篇文章不讲原理,只 ...

  8. C语言 百炼成钢17

    //题目49:老师将糖果分成若干份,让学生按任意次序领取,第一个领取的,得到1份加上剩余糖果的1/10, //第二个领取的,得到2份加上剩余糖果的1/10,第三个领取的,得到3份加上剩余糖果的1/10 ...

  9. js 中常用的方法

    1..call() 将.call()点之前的属性或方法,继承给括号中的对象. 2.(function(){xxx})() 解释:包围函数(function(){})的第一对括号向脚本返回未命名的函数, ...

  10. WebGIS空间数据请求访问机制

    通用的WebGIS空间数据请求访问机制如下图所示: 图1 WebGIS空间数据请求访问机制