队列
概念解释
队列(Queue)是一种常见的数据结构,它按照先进先出(FIFO)的原则存储元素。队列有两个主要操作,即入队(enqueue)和出队(dequeue)。入队操作将一个元素添加到队列的末尾,而出队操作则从队列的前端移除并返回队列中的第一个元素。
队列可以比喻成排队等待服务的人群,新来的人加入队尾,而被服务结束的人从队头离开。这种结构在很多实际场景中都有应用,比如计算机执行任务的排队调度、网络数据传输的缓存控制等。
常见的操作
循环队列(链表实现)
- 队列顺序存储的假溢出问题
队列也可以进行顺序存储,但这会造成队列假溢出的现象:
队列的假溢出(False Overflow)是一种特殊情况,在队列的实现中可能会出现。它发生在队列的尾端被占满时,仍有空闲位置在队列的头部。通常,队列有一个固定的容量,当队列元素达到容量上限时,继续执行入队操作会导致溢出。然而,在某些情况下,由于队列元素的出队操作,队列的头部会出现空闲位置,这意味着队列尾部实际上没有满员。假溢出的原因可能是由于队列的容量的设置不合理,导致队列尾部实际上不能填满。例如,如果队列的容量设置为10个元素,但在某个时刻只有5个元素在队列中,那么队列的尾部会被占满,而队列的头部却有5个空闲位置。
假溢出可能会导致资源浪费或性能下降。在实际应用中,如果没有及时处理假溢出,可能会造成空间的浪费,而且后续的入队操作可能会因为错误的认为队列已满而被拒绝。所以解决假溢出的办法就是后面满了,就再从头开始,也就是头尾相接的循环。
- 循环队列
链表实现
- Java代码实现
方法接口
public interface Queue<E> {
/**
* 向队列尾插入值
* @param value-待插入值
* @return 插入成功返回true,插入失败返回false
*/
boolean offer(E value);
/**
* 从队列头获取值,并移除
* @return 如果队列非空返回对头值,否则返回null
*/
E poll();
/**
* 从对头获取值,但不移除
* @return 如果队列非空返回对头值,否则返回null
*/
E peek();
/**
* 检查队列是否为空
* @return 空返回true,否则返回false
*/
boolean isEmpty();
/**
* 检验队列是否已满
* @return 满返回true,否则返回false
*/
boolean isFull();
}
代码实现
/**
* 用链表实现队列:单项环形带哨兵的链表
*/
public class LinkedListQueue<E> implements Queue<E>, Iterable<E> {
//1.创建内部节点类
private static class Node<E>{
E value;
Node<E> next;
public Node(E value, Node<E> next) {
this.value = value;
this.next = next;
}
}
//2.创建LinkedListQueue中的属性
//头指针:指向哨兵节点,即队头
private Node<E> head = new Node<>(null, null);
//尾指针:指向链表最后一个节点,即队尾
private Node<E> tail = head;
//队列大小:表示目前队列存储元素的多少
private int size = 0;
//队列的容量:表示队列所能容纳的最大数量
private int capacity = Integer.MAX_VALUE;
//构造方法:将队尾指向对头,实现循环
public LinkedListQueue() {
tail.next = head;
}
public LinkedListQueue(int capacity) {
this.capacity = capacity;
tail.next = head;
}
@Override
public boolean offer(E value) {
//判断队列是否已满
if (isFull()) return false;
//向队列添加元素
Node<E> addElem = new Node<>(value, head);
tail.next = addElem;
tail = addElem;
size++;
return true;
}
@Override
public E poll() {
if (isEmpty()) return null;
//当队列只有一个节点,将tail指向head
if (tail == head.next) tail = head;
//进行删除操作
E removed = head.next.value;
head.next = head.next.next;
size--;
return removed;
}
@Override
public E peek() {
//如果队列为空,返回null
if (isEmpty()) return null;
return head.next.value;
}
@Override
public boolean isEmpty() {
return head == tail;
}
@Override
public boolean isFull() {
return size == capacity;
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
Node<E> p = head.next;
@Override
public boolean hasNext() {
return p != head;
}
@Override
public E next() {
E value = p.value;
p = p.next;
return value;
}
};
}
}
- C代码实现
#include <stdio.h>
#include <stdlib.h>
//节点类的创建
typedef struct Node{
int value;
Node *next;
}Node;
//创建队列
typedef struct Queue{
//头指针:指向哨兵节点,即队头
Node *head;
//尾指针:指向链表最后一个节点,即队尾
Node *tail;
//队列的容量:表示队列所能容纳的最大数量
int capacity;
//目前队列的容量
int size;
}Queue;
//函数方法声明——————————-—————
Queue* initQueue(int capacity);
bool isEmpty(Queue *queue);
bool isFull(Queue *queue);
bool offer(Queue *queue, int value);
int poll(Queue *queue);
int peek(Queue *queue);
//——————————————————————
int main(){
Queue *queue = initQueue(5);
offer(queue, 1);
offer(queue, 2);
offer(queue, 3);
printf("Front element: %d\n", peek(queue)); // 应输出1
printf("Popped element: %d\n", poll(queue)); // 应输出1
printf("Front element: %d\n", peek(queue)); // 应输出2
return 0;
}
/*初始化队列*/
Queue* initQueue(int capacity){
Queue* queue = (Queue*)malloc(sizeof(Queue));
queue->capacity = capacity;
queue->size = 0;
Node* sentinel = (Node*)malloc(sizeof(Node));
sentinel->value = -1; // 设置哨兵节点的值为特定值
sentinel->next = sentinel; // 哨兵节点的next指针指向自身
queue->head = sentinel;
queue->tail = sentinel;
return queue;
}
/*判断队列是否为空*/
bool isEmpty(Queue *queue){
return queue->head == queue->tail;
}
/*判断队列是否为满*/
bool isFull(Queue *queue){
return queue->size == queue->capacity;
}
/*入队操作*/
bool offer(Queue *queue, int value){
if(isFull(queue)) return false;
//创建一个新节点
Node *added = (Node *)malloc(sizeof(Node));
added->value = value;
added->next = queue->head;
//对节点指针的操作
queue->tail->next = added;
queue->tail = added;
queue->size++;
return true;
}
/*出队操作*/
int poll(Queue *queue){
if(isEmpty(queue)) return -1;
if(queue->head->next == queue->tail) queue->tail = queue->head;
//删除操作
Node* removed = queue->head->next;
int val = removed->value;
queue->head->next = removed->next;
free(removed);
queue->size--;
return val;
}
/*从对头获取值,但不移除*/
int peek(Queue *queue){
if(isEmpty(queue)) return -1;
return queue->head->next->value;
}