# 队列

TIP

队列(Queue),是一种受限的线性结构,特点是先进先出(FIFO:first in first out)

# 基本特点

  • 受限表现:仅允许在表的前端(front)进行删除操作,在表的后端(rear)进行插入操作

# 结构图例

queue

# 常用操作

  • enqueue(element):向队列尾部添加一个(或多个)新的项
  • dequeue():移除队列的第一(即排在队列最前面的)项,并返回被移除的元素
  • front():返回队列中的第一个元素——最先被添加,也将是最先被移除的元素。队列不做任何变动(不移除元素)
  • isEmpty():如果队列中不包含任何元素,返回 true,否则返回 false
  • size():返回队列包含的元素个数,与数组的 length 属性类似
  • toString():将队列中的内容,转成字符串形式

# 代码实现

// 普通队列
function Queue() {
	var items = []

	/* 队列操作的方法 */
	// 1.enqueue():将元素加入到队列中
	this.enqueue = function(element) {
		items.push(element)
	}

	// 2.dequeue():从队列中删除前端元素
	this.dequeue = function() {
		return items.shift()
	}

	// 3.front(): 查看前端的元素
	this.front = function() {
		return items[0]
	}

	// 4.isEmpty(): 查看队列是否为空
	this.isEmpty = function() {
		return items.length == 0
	}

	// 5.size(): 查看队列中元素的个数
	this.size = function() {
		return items.length
	}

	// 6.toString(): 将队列中元素以字符串形式输出
	this.toString = function() {
		var resultString = ""
		for (let i = 0; index < this.items.length; index++) {
			resultString += this.items[index] + " "
		}
		return resultString
	}
}

// 创建队列对象
var queue = new Queue()

// 在队列中添加元素
queue.enqueue("a")
queue.enqueue("b")
queue.enqueue("c")

// 查看一下队列前端元素
console.log(queue.front()) // a

// 查看队列是否为空和元素个数
console.log(queue.isEmpty()) // false
console.log(queue.size()) // 3

// 从队列中删除元素
console.log(queue.dequeue()) // a
console.log(queue.dequeue()) // b
console.log(queue.dequeue()) // c

# 队列应用-击鼓传花

击鼓传花:传入一组数据和设定的数字 num,循环遍历数组内元素,遍历到的元素为指定数字 num 时将该元素删除,直至数组剩下一个元素

// 面试题:实现击鼓传花的函数
function passGame(nameList, num) {
	// 1.创建一个队列, 并且将所有的人放在队列中
	// 1.1.创建队列
	var queue = new Queue()

	// 1.2.通过for循环, 将nameList中的人放在队列中
	for (var i = 0; i < nameList.length; i++) {
		queue.enqueue(nameList[i])
	}

	// 2.寻找最后剩下的人
	while (queue.size() > 1) {
		// 不是num的时候,重新加入到队列的末尾
		// 是num这个数字的时候,从队列中删除
		// 将前num-1中的人, 都从队列的前端取出放在队列的后端
		for (var i = 0; i < num - 1; i++) {
			queue.enqueue(queue.dequeue())
		}

		// 将第num个人, 从队列中移除(num变为第一个了)
		queue.dequeue()
	}

	// 3.获取剩下的一个人
	console.log("最后队列长度:" + queue.size()) // 1
	var endName = queue.front()
	console.log("最终留下来的人:" + endName) // Ingrid

	// 4.获取该人在队列中的位置
	return nameList.indexOf(endName)
}

// 验证结果
var names = ["John", "Jack", "Camila", "Ingrid", "Carl"]
var index = passGame(names, 7)
console.log("最终位置:" + index) // 3

# 优先级队列

# 特点

  • 每个元素不再只是一个数据,还包含数据的优先级
  • 插入数据的时候,会和其他数据比较优先级,然后根据优先级插入到正确的位置

# 代码实现

// 封装优先级队列
function PriorityQueue() {
	// 内部类:封装一个新的构造函数, 用于保存元素和元素的优先级
	function QueueElement(element, priority) {
		this.element = element
		this.priority = priority
	}

	// 封装属性
	var items = []

	// 1.enqueue(): 实现按照优先级插入方法
	this.enqueue = function(element, priority) {
		// 1.1 根据传入的元素, 创建新的QueueElement
		var queueElement = new QueueElement(element, priority)

		// 1.2 判断队列是否为空
		if (this.isEmpty()) {
			// 如果为空就直接放入队列
			items.push(queueElement)
		} else {
			// 定义一个变量记录是否成功添加了新元素
			var added = false
			for (var i = 0; i < items.length; i++) {
				// // 让新插入的元素与原有元素进行优先级比较(priority越小,优先级越大)
				if (queueElement.priority < items[i].priority) {
					items.splice(i, 0, queueElement)
					added = true
					// 新元素已经找到插入位置了可以使用break停止循环
					break
				}
			}

			// 遍历完所有的元素, 优先级都大于新插入的元素时, 就插入到最后
			if (!added) {
				items.push(queueElement)
			}
		}
	}

	// 2.dequeue(): 从队列中删除前端元素
	this.dequeue = function() {
		return items.shift()
	}

	// 3.front(): 查看前端的元素
	this.front = function() {
		return items[0]
	}

	// 4.isEmpty(): 查看队列是否为空
	this.isEmpty = function() {
		return items.length == 0
	}

	// size(): 查看队列中元素的个数
	this.size = function() {
		return items.length
	}

	// 6.toString():以字符串形式输出队列中的元素
	PriorityQueue.prototype.toString = () => {
		let resultString = ""
		for (let i = 0; i < items.length; i++) {
			resultString += items[i].element + "-" + items[i].priority + " "
		}
		return resultString
	}
}

// 创建优先级队列对象
var pQueue = new PriorityQueue()

// 添加元素
pQueue.enqueue("abc", 10)
pQueue.enqueue("cba", 5)
pQueue.enqueue("nba", 12)
pQueue.enqueue("mba", 3)

// 遍历所有的元素
console.log(pQueue.toString()) // mba-3 cba-5 abc-10 nba-12