JavaScript队列(Queue)数据结构实现与基数排序应用详解

作者:闭包旅人

时间:2026-10-23

浏览:485

本文详细解析了JavaScript中队列(Queue)数据结构的实现原理,涵盖入队、出队、查看首尾元素及清空等核心操作方法。通过原生数组特性简化代码逻辑,并进一步展示如何利用队列特性实现基数排序算法,包括按位分配与收集的具体步骤及代码示例,帮助开发者深入理解线性数据结构及其在排序算法中的实际应用。

文章目录

本文通过具体实例,深入讲解JavaScript中算法与数据结构的核心组件——队列(Queue)。内容旨在为读者提供清晰的实现思路与代码参考,便于学习与实践。

队列(Queue)

此前我们探讨过栈(Stack),这是一种遵循“先入后出”(LIFO, Last-In-First-Out)原则的高效数据结构。相比之下,队列(Queue)同样是一种特殊的线性表,但其操作规则不同:元素只能在队尾插入,在队首删除。这种机制类似于日常生活中排队购票的场景。

队列主要用于存储按顺序排列的数据,严格遵循“先进先出”(FIFO, First-In-First-Out)原则。作为计算机系统中常用的数据结构,队列广泛应用于操作系统进程调度、打印池任务管理等多种场景。

与栈类似,队列的基本操作主要包含两类:向队列插入新元素以及从队列中删除元素,分别对应入队(Enqueue)和出队(Dequeue)操作,我们将通过这两个核心方法来实现队列功能。

除了基本的入队和出队,队列还包含其他辅助操作:例如读取队首元素,该操作仅返回队头数据而不将其移除,类似于栈的peek方法;back方法用于读取队尾元素;toString方法用于打印队列中所有元素;clear方法则用于清空整个队列。

队列(Queue) 队列数据定义

确定数据类型后,我们可以利用JavaScript中的数组来构建队列的实现。

队列的实现


//定义队列

function Queue(){
 this.dataStore = [];
 this.enqueue = enqueue;  //入队
 this.dequeue = dequeue;  //出队
 this.front = front;   //查看队首元素
 this.back = back;   //查看队尾元素
 this.toString = toString; //显示队列所有元素
 this.clear = clear;   //清空当前队列
 this.empty = empty;   //判断当前队列是否为空
}

首先,我们来实现入队操作:

enqueue:向队列添加元素


//向队列末尾添加一个元素,直接调用 push 方法即可

function enqueue ( element ) {
 this.dataStore.push( element );
}

由于JavaScript数组具备其他语言所不具备的特性,可以直接利用shift方法删除数组第一个元素,这使得出队操作的实现变得相对简单。

dequeue:删除队首的元素


//删除队列首的元素,可以利用 JS 数组中的 shift 方法

function dequeue () {
 if( this.empty() ) return 'This queue is empty';
 else this.dataStore.shift();
}

需要注意的是,上述代码中增加了一个判断逻辑,检查队列是否还有元素,因为删除空队列的元素没有意义。接下来,我们将探讨empty方法的具体实现。

empty:判断队列是否为空


//我们通过判断 dataStore 的长度就可知道队列是否为空

function empty(){
 if( this.dataStore.length == 0 ) return true;
 else return false;
}

我们先对这几个核心方法进行测试:


var queue = new Queue();

console.log( queue.empty() );  //true

//添加几个元素
queue.enqueue('Apple');
queue.enqueue('Banana');
queue.enqueue('Pear');

console.log( queue.empty() );  // false

现在,如果我们不确定谁在队首、谁在队尾,可以利用front和back方法分别进行查看:

front:查看队首元素


//查看队首元素,直接返回数组首个元素即可

function front(){
 if( this.empty() ) return 'This queue is empty';
 else return this.dataStore[0];
}

back:查看队尾元素


//查看队首元素,直接返回数组最后一个元素即可

//读取队列尾的元素
function back () {
 if( this.empty() ) return 'This queue is empty';
 else return this.dataStore[ this.dataStore.length - 1 ];
}

先验证一下结果是否正确:


//查看队首元素
console.log( queue.front() ); // Apple
//查看队尾元素 
console.log( queue.back() ); // Pear

//出队
queue.dequeue();

//查看队首元素
console.log( queue.front() ); // Banana
//查看队尾元素 
console.log( queue.back() ); // Pear

确认无误后,如果想查看队列中总共有多少元素,可以使用toString方法来实现:

toString:查看队列中所有元素


//查看对了所有元素,我这里采用数组的 join 方法实现

function toString(){
 return this.dataStore.join('\n');
}

现在,你可以检查是否还有剩余元素未处理:


console.log( queue.toString() )  // Apple
         // Banana
         // Pear

最后剩下一个clear方法,如果所有元素都已处理完毕,应使用clear方法来清空队列:


//清空当前队列,也很简单,我们直接将 dataStore 数值清空即可

function clear(){
 delete this.dataStore;
 this.dataStor = [];
}

至此,我们已使用JavaScript成功实现了一个完整的队列。可以看出,利用JS数组特性可以省去不少繁琐步骤,确实非常便捷。


//清空队列

queue.clear();

console.log( queue.empty() ); // true

接下来,我们将利用队列来实现基数排序(Radix Sort)。

基数排序(Radix Sort)属于“分配式排序”(Distribution Sort),它通过键值的局部信息,将待排序元素分配到特定的“桶”中,从而达到排序目的。基数排序是一种稳定性排序算法,其时间复杂度为O(nlog(r)m),其中r为基数,m为堆数。在某些情况下,基数排序的效率高于其他稳定性排序算法。

首先看一下基数排序的实现步骤(以两位数为例):需要进行两次扫描,第一次按个位数字排序,第二次按十位数字排序。每个数字根据对应数值被分配到不同的盒子中,最后将盒子中的数字依次取出,组成新的列表,即为排序后的结果。

  1. 假设我们有一串数字,分别为 73, 22, 93, 43, 55, 14, 28, 65, 39, 81
  2. 首先根据个位数字排序,放到不同的盒子里,如下图

    队列(Queue)
    第一次排序
  3. 接下来将这些盒子中的数值重新串接起来,成为以下的数列:81, 22, 73, 93, 43, 14, 55, 65, 28, 39
  4. 然后根据十位数字排序,再放到不同的盒子里,如下图

    队列(Queue)
    第二次排序
  5. 接下来将这些盒子中的数值重新串接起来,整个数列已经排序完毕:14, 22, 28, 39, 43, 55, 65, 73, 81, 93

我们已经了解了基数排序的算法思想,接着我们要结合队列去实现它,一起来看看吧。


//基数排序

var queues = []; //定义队列数组
var nums = [];  //定义数字数组

//选十个0~99的随机数进行排序
for ( var i = 0 ; i < 10 ; i ++ ){
 queues[i] = new Queue();
 nums[i] = Math.floor( Math.random() * 101 );
}

//排序之前
console.log( 'before radix sort: ' + nums );

//基数排序
distribution( nums , queues , 10 , 1 );
collect( queues , nums );
distribution( nums , queues , 10 , 10 );
collect( queues , nums );

//排序之后
console.info('after radix sort: ' + nums );

//根据相应的(个位和十位)数值,将数字分配到相应队列

function distribution ( 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].front();
   queues[digit].dequeue();
  }
 }
}

我这里贴出两组测试的结果,大家自己动手实践一下。


//第一组测试

before radix sort: 23,39,2,67,90,41,47,21,98,13
after radix sort: 2,13,21,23,39,41,47,67,90,98

//第二组测试

before radix sort: 29,62,38,16,55,26,33,54,76,65
after radix sort: 16,26,29,33,38,54,55,62,65,76

至此,我们队列也就告一段落了,大家还可以往深入拓展,比如优先队列,循环队列等,希望大家能发散思维,多动手实践,一起加油!

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《JavaScript数学运算用法总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript数组操作技巧总结》、《JavaScript排序算法总结》、《JavaScript遍历算法与技巧总结》、《JavaScript查找算法技巧总结》及《JavaScript错误与调试技巧总结》

希望本文所述对大家JavaScript程序设计有所帮助。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章