Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 队列 #18

Open
Checkson opened this issue Feb 25, 2019 · 0 comments
Open

JavaScript 队列 #18

Checkson opened this issue Feb 25, 2019 · 0 comments

Comments

@Checkson
Copy link
Owner

Checkson commented Feb 25, 2019

简介

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

定义

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

队列(Queue)类实现

完整代码地址,这里我们采用的底层数据结构仍是数组。涉及到的操作大概有:

  • enqueue 方法在队列队尾插入新元素,该操作也称为入队。
  • dequeue 方法在队列对头删除元素,该操作也称为出队。
  • peek 方法读取队头的元素。该操作返回队头元素,但不把它从队列中删除。
  • length 方法来记录队列中存储了多少元素。
  • clear 方法清空队列种的所有元素。
  • toString 方法将队列种的元素输出为字符串形式

1. 构造函数

构造我们可以接收一些可以初始化队列的参数。

function Queue () {
    var args = [].slice.call(arguments);
    this.dataList = args;
}

2. enqueue:入队

JavaScript相对其他编程语言,有一个天然的优势,就是它的数组提供 push 方法,能模仿队列的入队操作。

Queue.prototype.enqueue = function (el) {
    this.dataList.push(el);
}

3. dequeue:出队

JavaScript数组操作除了提供 push 操作,还提供了 shift 方法,来模仿队列的出队操作。

Queue.prototype.dequeue = function () {
    return this.dataList.shift();
}

4. peek:获取队头元素

Queue.prototype.peek = function () {
    return this.dataList[0];
}

5. length:获取队列的元素个数

Queue.prototype.length = function () {
    return this.dataList.length;
}

6. clear:清楚队列种所有元素

Queue.prototype.clear = function () {
    delete this.dataList;
    this.dataList = [];
}

7. toString:将队列转换为字符串

Queue.prototype.toString = function () {
    return this.dataList.join();
}

队列(Queue)类测试

var queue = new Queue('JavaScript', 'HTML', 'CSS');
console.log(queue.toString()); // JavaScript,HTML,CSS
console.log(queue.length());   // 3
queue.enqueue('React');
console.log(queue.toString()); // JavaScript,HTML,CSS,React
console.log(queue.dequeue());  // JavaScript
console.log(queue.peek());        // HTML
queue.clear();
console.log(queue.toString()); // ''

队列(Queue)实战

1. 使用队列对数据进行排序(基数排序)

队列不仅用于执行现实生活中与排队有关的操作,还可以用于对数据进行排序。计算机刚刚出现时,程序是通过穿孔卡输入主机的,每张卡包含一条程序语句。这些穿孔卡装在一个盒子里,经一个机械装置进行排序。我们可以使用一组队列来模拟这一过程。这种排序技术叫做基数排序,参见 Data Structures with C++(Prentice Hall)一书。它不是最快的排序算法,但是它展示了一些有趣的队列使用方法。

对于有限的整型数字,基数排序将数据集扫描 n(n取决于最大位数的数)次。第一次按个位上的数字进行排序,第二次按十位上的数字进行排序,直到队列对比完队列中最高位数的数。每个数字根据对应位上的数值被分在不同的盒子里。假设有如下数字:

91, 46, 85, 15, 92, 35, 31, 22

经过基数排序第一次扫描之后,数字被分配到如下盒子中:

Bin 0:
Bin 1: 91, 31
Bin 2: 92, 22
Bin 3:
Bin 4:
Bin 5: 85, 15, 35
Bin 6: 46
Bin 7:
Bin 8:
Bin 9:

根据盒子的顺序,对数字进行第一次排序的结果如下:

91, 31, 92, 22, 85, 15, 35, 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

使用队列代表盒子,可以实现这个算法。我们需要九个队列,每个对应一个数字。将所有队列保存在一个数组中,使用取余和除法操作决定个位和十位,或者更高位。算法的剩余部分将数字加入相应的队列,根据个位数值对其重新排序,然后再根据十位上的数值进行排序,直到最高位数值进行排序,结果即为排好序的数字。

示例代码:

function radixSort (nums) {
    // 构建队列数组
    var queues = [];
    for (var i = 0; i < 10; i++) {
        queues[i] = new Queue();
    }
    // 基排序
    var isLoop = true, radix = 10;
    do {
        isLoop = false;
        for (var i = 0, len = nums.length; i < len; i++) {
            var divide = Math.floor(radix / 10),
                temp = Math.floor(nums[i] / divide),
                index = temp % 10;
            if (temp) isLoop = true;
            queues[index].enqueue(nums[i]);
        }
        var j = 0;
        for (var i = 0; i < 10; i++) {
            while (queues[i].length()) {
                nums[j++] = queues[i].dequeue();
            }
        }
        radix *= 10;
    } while (isLoop);
    // 返回基排序结果
    return nums;
}

测试代码:

var nums = [];

for (var i = 0; i < 10; i++) {
    nums[i] = Math.floor(Math.random() * 10000);
}

console.log('排序前:')
console.log(nums.toString());

radixSort(nums);

console.log('排序后:')
console.log(nums.toString());

运行几次测试代码,结果为:

排序前:
5806,7829,7540,3360,9198,7427,4536,5336,1391,4148
排序后:
1391,3360,4148,4536,5336,5806,7427,7540,7829,9198

排序前:
9895,3646,9204,7545,1192,8832,9639,3162,2642,3995
排序后:
1192,2642,3162,3646,3995,7545,8832,9204,9639,9895

可见,基排序的时间复杂度大概为:O(n*m)。其中n是数组长度,m是最大的数的位数。(后面排序算法章节详解)。

2. 优先队列

优先队列和普通队列最大的不同是在于,在出队(dequeue)的时候,优先队列不会遵循先进先出的原则,它会根据队列中元素的权值来判断到底先删除哪个元素。

3. 循环队列

定义,循环队列在JavaScript中应用得很少,是因为JavaScript中的数组是动态的,可以动态增删数组元素,来避免队列溢出的现象。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant