队列是具有先入先出特征的线性数据结构。
排队是生活中一个十分典型的队列,先到的人可以到达队列的队首,后到的则跟在后面成为队尾。
比如说,在银行中,柜台会处理位于队首的客户的业务。完成后,队列的下一个客户会到达柜台办理。
位于队首的客户办完业务后离开队列被称为出队,而新客户加入等待的队列则是入队。
常用操作
不同于栈,队列的一端可以放入元素,另一端则可以弹出元素。
元素入队、出队和访问队首元素的时间复杂度均为O(1)
。
在C#
中,内置的System.Collections.Queue提供了队列的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| Queue<int> queue = new();
queue.Enqueue(1); queue.Enqueue(1); queue.Enqueue(4); queue.Enqueue(5); queue.Enqueue(1); queue.Enqueue(4);
int dequeue = queue.Dequeue();
int peek = queue.Peek();
int size = queue.Count;
bool isEmpty = queue.Count == 0;
|
实现
与栈类似,队列也可以通过数组、链表或列表实现。
.NET是基于数组实现的
基于列表
对于列表和数组,应当记录队首的索引。在出队时改变索引即可。
同时,将列表的尾部元素定义为队尾,在列表的尾部添加元素是入队。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class ListQueue<T> { List<T> queue = []; private int FrontIndex = 0;
public void Enqueue(T element) => queue.Add(element); public int Size() => queue.Count - FrontIndex; public bool IsEmpty() => Size() == 0;
public T Peek() { if (IsEmpty()) throw new Exception(); return queue[FrontIndex]; }
public T Dequeue() { if (IsEmpty()) throw new Exception(); FrontIndex++; return Peek(); } }
|
基于链表
将链表的头节点视为队首,在链表的头部移除元素是出队,从尾节点添加元素则是入队。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class Node<T>(T item) { public T Item { get; set; } = item; public Node<T> Next { get; set; } }
class LinkedQueue<T> { Node<T> front; Node<T> rear; int size = 0; public int Size() => size;
public bool IsEmpty() => Size() == 0; public void Enqueue(T element) { Node<T> node = new(element); if (front == null) { front = node; } else if (rear != null) { rear.Next = node; } rear = node; size++; }
public T Dequeue() { if (IsEmpty()) throw new Exception(); T element = Peek(); front = front.Next; size--; return element; }
public T Peek() { if (IsEmpty()) throw new Exception(); return front.Item; } }
|
对比
与栈类似,在不触发扩容操作的情况下,列表的实现效率更高。
基于链表实现的效率更加稳定,不会因为扩容操作而突然降低效率。
双向队列
在C#
中,双向队列即是LinkedList<T>
,关于链表。
基本应用
本文和右下角标有www.hello-algo.com
标识的图片采用 署名-非商业性使用-相同方式共享 4.0 国际 许可协议,转载请注明出处。