第二节:队列详解和面试题剖析

一. 队列详解

1. 什么是队列?

   它是一种受限的线性表先进先出(FIFO First In First Out)

   受限之处在于它只允许在队列的前端(front)进行删除操作;而在队列的后端(rear)进行插入操作

2. 队列常见的操作

enqueue(ele) :向队列尾部添加一个(或多个)新的项。

dequeue():移除队列的第一(即排在队列最前面的)项,并返回被移除的元素。

front/peek():返回队列中第一个元素——最先被添加,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息——与Stack类的peek方法非常类似)。

isEmpty():如果队列中不包含任何元素,返回true,否则返回false。

size():返回队列包含的元素个数,与数组的length属性类似。

 

二. 手写队列

1. 分析

  队列和栈一样,可以基于数组实现,也可以基于队列实现。

  使用泛型类、泛型接口,来编写队列。

2. 实操--基于数组实现

   主要用到数组的两个方法:     push:从数组尾部插入元素          shift:删除数组的第一个元素,并返回该元素。

(1). 抽离公共泛型接口IList,可服务于队列和栈

interface IList<T> {
	peek(): T | undefined;
	isEmpty(): Boolean;
	size(): number;
}
export default IList;

(2). 定义泛型队列接口IQueue,继承IList

interface IQueue<T> extends IList<T> {
	enqueue(item: T): void;
	dequeue(): T | undefined;

	// 下面代码注释,继承IList中的即可
	// peek(): T | undefined;
	// isEmpty(): Boolean;
	// size(): number;
}
export default IQueue;

(3). 定义泛型队列MyQueue,实现IQueue接口

class MyQueue<T> implements IQueue<T> {
	//底层数据结构,泛型数组
	private array: T[] = [];

	//入队
	enqueue(item: T): void {
		this.array.push(item);
	}
	//出队,并返回出队元素
	dequeue(): T | undefined {
		return this.array.shift();
	}
	// 返回队首元素,不做任何操作
	peek(): T | undefined {
		return this.array[0];
	}
	//判断队列是否为空
	isEmpty(): Boolean {
		return this.array.length === 0;
	}
	//返回队列元素个数
	size(): number {
		return this.array.length;
	}
	//返回队列元素个数(以属性的形式存在)
	get size2(): number {
		return this.array.length;
	}
}
export default MyQueue;

(4). 测试

import MyQueue from "./01-实现队列结构";

let queue = new MyQueue();

// 入队
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
queue.enqueue(4);
queue.enqueue(5);

console.log(queue.size()); //函数调用
console.log(queue.size2); //属性调用
console.log(queue.isEmpty()); //false
console.log(queue.peek()); //1

//出队
console.log("-------------开始出队--------------");
/* 
  for循环:用于已知个数的情况
  while循环:用于未知个数的情况
*/
while (queue.size2 > 0) {
	console.log(queue.dequeue());
}

 

三. 面试题剖析

1. 击鼓传花

(1). 规则说明

 几个小朋友围成一圈,开始从1数数(1,2,3,4...),数到某个数字n后自动淘汰, 然后剩下的小朋友重新从1开始数,同样规则继续进行,直到剩下一个小朋友位置,请问最后剩下的小朋友的名字和原先所在的位置。

(2). 剖析

 *   A. 首先需要将数组中全部入队

 *   B. 先以第一次数数为例,实际上就是一个for循环,num之前,直接出队,入队;到了num之后,那么就淘汰,该次数数彻底结束

 *   C. 最外层加个while,相当于多次数数,最后剩一个元素的时候停止。

(3). 实操

import MyQueue from "./01-实现队列结构";
/**
 * 击鼓传花方案实操
 * @param array 小朋友名字数组
 * @param num 数字num代表停止,该小朋友淘汰
 * @returns 最后剩下的小朋友的名字
 */
function hotPotato(array: string[], num: number): string {
	//0. 前置判断
	if (array.length === 0) return "数组不能为空";

	//1. 声明队列
	let queue = new MyQueue<string>();

	//2. 所有小朋友入队
	array.forEach(item => queue.enqueue(item));

	//3. 遍历队列,进行出队、入队/淘汰,直到剩下一个小朋友为止
	while (queue.size() > 1) {
		//3.1 不淘汰,重新入队
		for (let i = 1; i < num; i++) {
			//先出队,然后入队
			const item = queue.dequeue();
			if (item) queue.enqueue(item);
		}
		//3.2 直接淘汰
		queue.dequeue(); // 这个就相当于第num个元素,直接淘汰
	}

	return queue.peek()!;
}

//调用
const nameList = ["ypf1", "ypf2", "ypf3", "ypf4", "ypf5"];
const result = hotPotato(nameList, 3);    //ypf3
const index = nameList.indexOf(result);   //3
console.log(`最后剩下的小朋友名字为:${result},所在的位置:${index}`);

 

2. 约瑟夫环的问题

(1). 题目描述

( leetcode:   https://leetcode.cn/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/ 

  0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。

  例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3

(2). 剖析

    思路和击鼓传花是一样的,只不过这里从0开始,但删除的还是第m个数字,与从几开始没有关系,所以解题思路和击鼓传花完全一致。

(3). 实操

import MyQueue from "./01-实现队列结构";
/**
 * 约瑟夫环问题
 * @param n 表示n个数字,注:从0开始,所以最后一个数为n-1
 * @param m 第m个数字删除
 * @returns 剩下的最后一个数字
 */
function leftRemaining(n: number, m: number): number {
	//1. 声明队列
	let queue = new MyQueue<number>();

	//2. 入队
	for (let i = 0; i < n; i++) {
		queue.enqueue(i);
	}
	//3. 遍历操作
	while (queue.size2 > 1) {
		//3.1 不淘汰
		for (let h = 1; h < m; h++) {
			queue.enqueue(queue.dequeue()!);
		}
		//3.2 淘汰
		queue.dequeue();
	}

	return queue.dequeue()!;
}

// 调用
console.log(leftRemaining(7, 4)); //1
console.log(leftRemaining(12, 5)); //0

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @   Yaopengfei  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
历史上的今天:
2021-11-09 第四节:TypeScipt类、接口、枚举类型详解
2020-11-09 第十一节:Redis6.0新特性、剖析线程模型(单线程和多线程)
2019-11-09 第十三节:数据库索引相关和EFCore的索引映射
点击右上角即可分享
微信分享提示