第五章:javascript:队列

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

队列是一种先进先出(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)

(本文未完待续 )

即将更新:

优先队列方法

上一章:第四章:javascript: 栈 下一章:第六章: 链表

时间: 2024-08-03 01:11:11

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

第四、五章解决队列和串的编程问题

第四章      解决队列的编程问题 队列是一种特殊的线性表,是一种只允许在表的一端进行插入操作而在另一端进行删除操作的线性表.把进行插入操作的表尾称为队尾,进行删除操作的头部称为对头: 队列的主要特点是:先进先出,或后进后出 用一片连续的存储空间来存储队列中的数据元素,这样的队列称为顺序队列. 将顺序队列看成是首位相接的循环结构,这种队列叫做循环队列. 第五章      解决串的编程问题 串即字符串,是由0个或多个字符组成的有限序列,是数据元素为单个字符的特殊线性表. 顺序结构存储串: 串的静

学习笔记 第十五章 JavaScript基础

第15章   JavaScript基础 [学习重点] 了解JavaScript基础知识 熟悉常量和变量 能够使用表达式和运算符 正确使用语句 能够掌握数据类型和转换的基本方法 正确使用函数.对象.数组等核心知识和技法 能够编写简单的脚本,解决网页中常见特效和互动效果 15.1  JavaScript入门 JavaScript是一种轻量级.解释型的Web开发语言.现代浏览器都已嵌入了JavaScript引擎./sc 15.1.1 在网页中插入JavaScript代码 使用<script>标签,可

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

用户点击某个链接时弹出一个新窗口javascript使用window对象的open()方法来创建新的浏览器窗口,这个方法有三个参数:window.open(url,name,features)url:新窗口地址,如果省略,则弹出空白窗口name:新窗口的名字features:新窗口的属性. 比如: function open_url(url){ window.open(url,"new-window","width:320,height:480"); } 用 “ja

第五章JavaScript

创建数组://1.字面量方式创建 (推荐大家使用这种方式创建数组 简单粗暴) var colors = ['red','color','yellow'];console.log(colors) //空数组 var emptyArray = []; //2.使用构造函数的方式创建 使用new关键词对构造函数进行创建对象 var colors2 = new Array(); var colors3 = new Array('white','red','orange') console.log(col

JavaScript高级程序设计(第3版)第五章读书笔记

第五章 引用类型 创建Object实例的方式有两种,第一种是使用new操作符后跟Object构造函数,例如: var person = new Object( ); person.name = “Nicholas”; person.age=29; 第二种是使用对象字面量表示法.如: var person = { name : “Nicholas”, age : 29 }; 在最后一个属性后面添加逗号,会在IE7及更早版本和Opera中导致错误. 两种访问对象属性的方法,一是方括号语法,例如per

javascript高级程序设计 学习笔记 第五章 上

第五章 引用类型的值(对象)是引用类型的一个实例.在 ECMAScript 中,引用类型是一种数据结构, 用于将数据和功能组织在一起.它也常被称为类,但这种称呼并不妥当.尽管 ECMAScript 从技术上讲是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基本结构.引用类型有时候也被称为对象定义,因为它们描述的是一类对象所具有的属性和方法. 对象是某个特定引用类型的实例.新对象是使用 new 操作符后跟一个构造函数来创建的. 构造函数本身就是一个函数,只不过该函数是出于创建新

《javascript高级程序设计》第五章知识点总结

第五章知识点总结 1.object类型 访问对象的方法:①点表示法        (people.name) :      ②方括号表示法         (people[name]). 常用方法:hasOwnProperty()         用于检查给定属性在当前对象实例中是否存在 isPrototypeOf()              用于检测传入的对象是否传入对象原型 toString()                        返回对象的字符串表示 valueOf()    

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

这节对Popups这一章的最后两个例子进行介绍和解析. 第一个[Popup Actions]介绍了弹窗中如何自定义工具按钮(名为actions),以PopupTemplate+FeatureLayer的形式测量要素的长度为例子进行介绍. 第二个[Custom popup actions per feature]则是上一个的升级,如果说上一个例子的功能是写死的,那么这个例子就把这个功能写活了.什么意思呢?上个例子的测距仅仅能测距,没有什么别的特别的.而这个例子以啤酒店的分布(点要素图层)为例,在自

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

第五章 UI层的松耦合 5.1 什么是松耦合 在Web开发中,用户界面是由三个彼此隔离又相互作用的层定义的: HTML是用来定义页面的数据和语义 CSS用来给页面添加样式 JavaScript用来给页面添加行为 我们的目标:确保对一个组件的修改不会经常性地影响其他部分. 结果: 遇到和文本或结构相关的问题,通过查找HTML即可定位 当发生了样式相关的问题,你知道问题出现在CSS中 对于那些行为相关的问题,你直接去JavaScript中找到问题所在 5.2 将JavaScript从CSS中抽离 I

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

本文是我翻译<JavaScript Concurrency>书籍的第五章 使用Web Workers,该书主要以Promises.Generator.Web workers等技术来讲解JavaScript并发编程方面的实践. 完整书籍翻译地址:https://github.com/yzsunlei/javascript_concurrency_translation .由于能力有限,肯定存在翻译不清楚甚至翻译错误的地方,欢迎朋友们提issue指出,感谢. Web workers在Web浏览器中