第十节:高阶队列详解(双端队列、优先级队列)
一. 双端队列
1. 回顾
默认的队列是先进先出的, 即只允许在front前端出队,在near后端入队
2. 什么是双端队列?
允许在队列的两端进行出队 和 入队
3. 实操
继承之前的队列MyQueue,然后新增addFront、removeBack两个方法即可
PS: 双端队列了解即可,实用性不是很大,违背了队列的特性,这里不做详细测试了
import MyQueue from '../02-队列结构/01-实现队列结构';
/**
* 双端队列
*/
class MyDeque<T> extends MyQueue<T> {
/**
* 01-在队首入队
* @param value 添加的元素
*/
addFront(value: T) {
this.array.unshift(value);
}
/**
* 02-在队尾出队
* @returns 返回删除的元素
*/
removeBack(): T | undefined {
return this.array.pop();
}
}
二. 优先级队列
1. 什么是优先级队列?
优先级队列(Priority Queue)是一种比普通队列更加高效的数据结构。它每次出队的元素都是具有最高优先级的,可以理解为元素按照关键字进行排序。
优先级队列可以用数组、链表等数据结构来实现,但是堆是最常用的实现方式。
2. 一些生活场景?
登机顺序,头等舱有限;医院急诊
3. 补充对象大小的比较方式
默认两个对象实例之间是没法比较的,无论怎么比较都是false
解决方案:声明一个valueof方法,里面return返回需要根据比较的属性,如下Person2的两个实例,就可以根据age属性比较大小了
//对象1
class Person1 {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
{
console.log('---------------Person1对象比较---------------------');
let p1 = new Person1('ypf1', 18);
let p2 = new Person1('ypf2', 19);
console.log(`p1<p2的结果:${p1 < p2}`); //false
console.log(`p1>p2的结果:${p1 > p2}`); //false
}
//对象2
class Person2 {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
/**
* 对象比较
* @returns 根据返回的属性进行对象比较
*/
valueOf() {
return this.age;
}
}
{
console.log('---------------Person2对象比较---------------------');
let p1 = new Person2('ypf1', 18);
let p2 = new Person2('ypf2', 19);
console.log(`p1<p2的结果:${p1 < p2}`); //true
console.log(`p1>p2的结果:${p1 > p2}`); //false
}
4. 实现方式1
(1) 思路:
创建优先级节点类,保存在堆中,此时堆中存放的就是这个优先级节点的实例对象。
这个优先级节点类需要实现valueof方法,用于对象之间大小的比较, 否则存入堆的对象无法比较大小
(2).实现的方法
enqueue、dequeue、peek、peek、size
/**
* 优先级节点类
*/
class PriorityNode<T> {
priority: number;
value: T;
constructor(value: T, priority: number) {
this.priority = priority;
this.value = value;
}
// 表示该类根据priority属性进行大小比较
valueOf() {
return this.priority;
}
}
/**
* 优先级队列
*/
class PriorityQueue1<T> {
//底层用堆存储(默认为最大堆)
private heap: Heap<PriorityNode<T>> = new Heap();
/**
* 01-入队
* @param val 内容
* @param priority 优先级
*/
enqueue(val: T, priority: number) {
let pNode = new PriorityNode(val, priority);
this.heap.insert(pNode);
}
/**
* 02-出队
* @returns 返回出队的元素 或 不存在为undefined
*/
dequeue(): T | undefined {
return this.heap.delete()?.value;
}
/**
* 03-返回队首元素,不进行任何操作
* @returns 返回队首元素 或 不存在为undefined
*/
peek(): T | undefined {
return this.heap.peek()?.value;
}
/**
* 04-队列是否为空
* @returns
*/
isEmpty() {
return this.heap.isEmpty();
}
/**
* 05-返回队列元素个数
* @returns
*/
size() {
return this.heap.size();
}
}
测试:
{
console.log('-------------------实现方式1测试--------------------------');
let pQueue1 = new PriorityQueue1<string>();
pQueue1.enqueue('ypf1', 18);
pQueue1.enqueue('ypf2', 66);
pQueue1.enqueue('ypf3', 20);
pQueue1.enqueue('ypf4', 30);
//输出:ypf2 ypf4 ypf3 ypf1
while (!pQueue1.isEmpty()) {
console.log(pQueue1.dequeue());
}
}
5. 实现方式2
数据自身返回优先级的比较值, 即插入的数据Student类,在类内部实现valueof
/**
* 优先级队列
*/
class PriorityQueue2<T> {
//底层用堆存储(默认为最大堆)
private heap: Heap<T> = new Heap();
/**
* 01-入队
* @param val 内容
*/
enqueue(val: T) {
this.heap.insert(val);
}
/**
* 02-出队
* @returns 返回出队的元素 或 不存在为undefined
*/
dequeue(): T | undefined {
return this.heap.delete() ?? undefined;
}
/**
* 03-返回队首元素,不进行任何操作
* @returns 返回队首元素 或 不存在为undefined
*/
peek(): T | undefined {
return this.heap.peek();
}
/**
* 04-队列是否为空
* @returns
*/
isEmpty() {
return this.heap.isEmpty();
}
/**
* 05-返回队列元素个数
* @returns
*/
size() {
return this.heap.size();
}
}
测试:
{
console.log('-------------------实现方式2测试--------------------------');
class Student {
name: string;
score: number;
constructor(name: string, score: number) {
this.name = name;
this.score = score;
}
valueOf() {
return this.score;
}
}
let pQueue2 = new PriorityQueue2<Student>();
pQueue2.enqueue(new Student('ypf1', 18));
pQueue2.enqueue(new Student('ypf2', 66));
pQueue2.enqueue(new Student('ypf3', 20));
pQueue2.enqueue(new Student('ypf4', 30));
//输出:ypf2 ypf4 ypf3 ypf1 [实际格式:Student { name: 'ypf2', score: 66 }]
while (!pQueue2.isEmpty()) {
console.log(pQueue2.dequeue());
}
}
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。