欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第五章队列

程序员文章站 2022-04-03 07:57:40
...

队列介绍

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

第五章队列

Queue 类定义和一些测试代码

function Queue()
{
	this.dataStore=[];
	this.enqueue=enqueue;
	this.dequeue=dequeue;
	this.front=front;
	this.back=back;
	this.toString=toString;
	this.isEmpty=isEmpty;
}

//向队尾添加一个元素
function enqueue(ele)
{
	this.dataStore.push(ele);
}

//删除队首的元素
function dequeue()
{
   return this.dataStore.shift();
}

function front()
{
	return this.dataStore[0];
}

function back()
{
	return this.dataStore[this.dataStore.length-1];
}

function toString()
{
	let retStr="";
	for(let i=0;i<this.dataStore.length;i++){
		retStr +=this.dataStore[i]+"\n";
	}
	return retStr;
}

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

//测试
let q=new Queue();
q.enqueue('Tom');
q.enqueue('Jack');
q.enqueue('Cynthia');
q.enqueue('Jennifer');
console.log(q.toString());
q.dequeue();
console.log(q.toString());
console.log("Front of queue:"+q.front());
console.log("Back of queue:"+q.back());

队列的使用

1)方块舞的舞伴分配问题:使用队列来模拟跳方块舞的人。当 男男女女来到舞池,他们按照自己的性别排成两队。当舞池中有地方空出来时,选两个队 列中的第一个人组成舞伴。他们身后的人各自向前移动一位,变成新的队首。当一对舞伴 迈入舞池时,主持人会大声喊出他们的名字。当一对舞伴走出舞池,且两排队伍中有任意 一队没人时,主持人也会把这个情况告诉大家。

把跳方块舞的男男女女的姓名储存在一个dancers.txt文件中,引入node fs模块。

dancers.txt文件数据:

F Allison McMillan
M Frank Opitz
M Mason McMillan
M Clayton Ruff
F Cheryl Ferenback
M Raymond Williams
F Jennifer Ingram
M Bryan Frazer
M David Durr
M Danny Martin
F Aurora Adney

//舞者信息存储在Dancer对象中
function Dancer(name,sex)
{
	this.name=name;
	this.sex=sex;
}

//从dancers.txt中读取舞者信息
function getDanners(males,females)
{
	let names=fs.readFileSync('dancers.txt','utf-8').split("\n");
	for(let i=0;i<names.length;i++)
	{
		names[i]=names[i].trim();//去除空格
	}
	
	for(let i=0;i<names.length;i++)
	{
		let dancer=names[i].split(" ");
		let sex=dancer[0];
		let name=dancer[1];
		if (sex=="F") {
			females.enqueue(new Dancer(name,sex));
		}else{
			males.enqueue(new Dancer(name,sex));
		}
	}

}

//配对
function dance(males,females)
{
	console.log("The dance partners are:\n");
	while(!females.isEmpty()&&!males.isEmpty()){
		let person=females.dequeue();
		console.log("Females dancer is:"+person.name);
		    person=males.dequeue();
		console.log("Males dancer is:"+person.name);		
	}
}


//测试
let maleDancers=new Queue();
let femaleDancers=new Queue();

getDanners(maleDancers,femaleDancers);
console.log("maleDancers:",maleDancers);
console.log("femaleDancers:",femaleDancers);
dance(maleDancers,femaleDancers);

if (!femaleDancers.isEmpty()) {
	console.log(femaleDancers.front().name+"is waiting to dance");
}
if (!maleDancers.isEmpty()) {
	console.log(maleDancers.front().name+"is waiting to dance");
}
2)使用队列对数据进行排序
使用一组队列来模拟基数排序.对于0~99的数字,基数排序将数据集扫描两次。第一次按个位上的数字进行排序,第二次按十位上的数字进行排序。每个数字根据对应位上的数值被分在不同的盒子里。假设有如下数字:

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 distribute(nums,queues,n,digit)
{
	for(let i=0;i<n;i++){
		if(nums[i]==""|| !nums[i]){
			continue;
		}

		if(digit==1){
			queues[nums[i]%10].enqueue(nums[i]);//按个位排列
		}else{
			queues[Math.floor(nums[i]/10)].enqueue(nums[i]);//按十位排列
		}
	}
}

//从队列中收集数字
function collect(queues,nums){
	let i=0;
	for(let digit=0;digit<10;digit++){
		while(!queues[digit].isEmpty()){
			nums[i++]=queues[digit].dequeue();
		}
	}
}

//展示数组内容
function dispArray(arr){
	for(let i=0;i<arr.length;i++){
		console.log(arr[i]+" ");
	}
}

//测试
let queues=[];
for(let i=0;i<10;i++){
	queues[i]=new Queue();
}

let nums=[];
for(let i=0;i<10;i++){
	nums[i]=Math.floor(Math.floor(Math.random()*101));
}
//nums=[91,46,85,15,92,35,31,22];

console.log("Before redix sort:");
dispArray(nums);
distribute(nums,queues,10,1);
collect(queues,nums);
distribute(nums,queues,10,10);
collect(queues,nums);
console.log("After redix sort:");
dispArray(nums);
3)医院急诊科(Emergency Department)的候诊室,就是一个采取优先队列的例子。

当病人进入候诊室时,分诊护士会评估患者病情的严重程度,然后给一个优先级代码。高优先级的患者先于低优先级的患者就医,同样优先级的患者按照先来先服务的顺序就医。

//定义患者对象
function Patient(name,code)
{
	this.name=name;
	this.code=code;
}

//重新定义dequeue方法,code小的元素优先级高
function dequeue()
{
	let priority=0;
	for(let i=0;i<this.dataStore.length;i++){
		if(this.dataStore[i].code<this.dataStore[priority].code){
			priority=i;
		}
	}
	return this.dataStore.splice(priority,1);
}

//重新定义toString方法
function toString(){
	let retVar="";
	for(let i=0;i<this.dataStore.length;i++){
		retVar +=this.dataStore[i].name+" code:"
			   +this.dataStore[i].code+"\n";
	}
	return retVar;
}

let ed=new Queue();
let p=new Patient('Tom',5);
ed.enqueue(p);
p = new Patient("Jones", 4);
ed.enqueue(p);
p = new Patient("Fehrenbach", 6);
ed.enqueue(p);
p = new Patient("Brown", 1);
ed.enqueue(p);
p = new Patient("Ingram", 1);
ed.enqueue(p); 

console.log(ed.toString());
while(!ed.isEmpty())
{
	let seen=ed.dequeue();
	console.log("Patient being treated:"+seen[0].name);
	console.log("Patient waiting to be seen:")
	console.log(ed.toString());
}

队列练习

1.修改 Queue 类,形成一个Deque类。这是一个和队列类似的数据结构,允许从队列两端添加和删除元素,因此也叫双向队列。写一段测试程序测试该类

function Deque()
{
	this.dataStore=[];
	this.push_front=push_front;
	this.push_back=push_back;
	this.pop_front=pop_front;
	this.pop_back=pop_back;
	this.front=front;
	this.back=back;
	this.toString=toString;
	this.isEmpty=isEmpty;
}

//向队首添加一个元素
function push_front(ele)
{
	this.dataStore.unshift(ele);
}

//向队尾添加一个元素
function push_back(ele)
{
	this.dataStore.push(ele);
}

//删除队首的元素
function pop_front()
{
   return this.dataStore.shift();
}

//删除队尾的元素
function pop_back()
{
   return this.dataStore.pop();
}
function front()
{
	return this.dataStore[0];
}

function back()
{
	return this.dataStore[this.dataStore.length-1];
}

function toString()
{
	let retStr="";
	for(let i=0;i<this.dataStore.length;i++){
		retStr +=this.dataStore[i]+"\n";
	}
	return retStr;
}

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

//测试

let d=new Deque();
d.push_back('Tom');
d.push_back('Jack');
d.push_front('Divid');
d.push_front('White');
console.log(d.toString());

d.pop_front();
console.log(d.toString());
d.pop_back();
console.log(d.toString());

2.使用前面完成的Deque类来判断一个给定单词是否为回文。

function isPalindrome(word)
{
	let d=new Deque();
	for(let i=0;i<word.length;i++){
		d.push_front(word[i]);
	}
    let p=new Deque();
    for(let i=0;i<word.length;i++){
		p.push_back(word[i]);
	}

	if(d.dataStore.join("")==p.dataStore.join("")){
		return true;
	}else{
		return false;
	}

}

let word="aba";
let flag=isPalindrome(word.split(""));
console.log(flag);