题外话:嘿嘿,偷懒了两天,吃一天玩一天,今天继续。
PS: 本文的重点是代码代码代码!而不是数据结构的一些基础概念和分类;
完全没接触过的同学,可以去看B站王卓教授的视频。
1.什么是队列?
- 队列是在表尾进行插入操作,在表头进行删除操作的线性表;
- 即“先进先出”。就跟现实世界的排队一样。
说明: 你不能插队,所以你新来的你去队尾,你在我后面,你比我晚上车。
2.队列有几种?
- 同样,根据实现队列的基本数据结构不同,分为:
- 顺序队列: 用数组实现的队列;
- 链队列: 用链表实现的队列。
3.顺序队列(常用)
- 用顺序表(数组)实现的队列,叫顺序队列;
- 顺序队列的基本结构:
- front:用于记录队头;
- rear:用于记录队尾;
- MaxSize:用于记录数组最大容积;
- _array:数组,用于容纳队列中的元素。
- 抛出一个问题: 如果用数组实现队列,不断的入队出队,会导致数组无法再添加元素了,到顶了,如图。
说明: 类似上图这种情况怎么办?空着的部分浪费不说,整个队列也废掉了?当然不行! 所以我们要想办法,把新的元素放到下面空白的部分,这就需要一定的余数计算了。
- 解决方法:
- 首先,我们默认数组永远空一格,便于计算。即6个容积的数组,装了5个元素,我们视为该队列已满。
- 计算元素个数:(rear - front + MaxSize) % MaxSize;
- 是否为空:个数 == 0 ?true : false;
- 是否已满:(rear + 1) % MaxSize == front;
4.代码实现顺序队列
namespace YoyoCode
{
internal class SqQueue<T>
{
public T[] _array;
public int MaxSize = 4;
public int front = 0;
public int rear = 0;
public SqQueue() {
_array= new T[MaxSize];
}
public SqQueue(int size)
{
MaxSize= size;
_array = new T[MaxSize];
}
/// <summary>
/// 队列是否为空
/// </summary>
/// <returns></returns>
public bool IsEmpty()
{
return GetCount() == 0;
}
/// <summary>
/// 获取队列中元素的数量
/// </summary>
/// <returns></returns>
public int GetCount()
{
return (rear - front + MaxSize) % MaxSize;
}
/// <summary>
/// 队列是否已满,注意,这个队列空一个视为满(空一个是为了更好的计算)
/// </summary>
/// <returns></returns>
public bool IsFull()
{
return (rear + 1) % MaxSize == front;
}
/// <summary>
/// 入队,从队尾入队
/// </summary>
/// <param name="value"></param>
public void EnQueue(T value)
{
if (IsFull())
{
throw (new OverflowException());
}
_array[rear] = value;
rear = (rear + 1) % MaxSize;
}
/// <summary>
/// 出队,从队头出队
/// </summary>
/// <returns></returns>
public T DeQueue()
{
if (IsEmpty())
{
throw(new NullReferenceException());
}
var res = _array[front];
front = (front + 1) % MaxSize;
return res;
}
}
}
5.链队列(不常用)
- 用链表实现的队列,叫链队。
- 链队的基本结构:
- front:头结点指针;
- rear:尾结点指针;
- LinkQueueNode:普通的链表结点的数据结构。
6.代码实现链队
namespace YoYoCode
{
public class LinkQueue<T>
{
public LinkQueueNode<T> Front;
public LinkQueueNode<T> Rear ;
public LinkQueue()
{
Front = new LinkQueueNode<T>();
Front.Next = null;
Rear = Front;
}
//是否为空
public bool IsEmpty()
{
return Front == Rear;
}
//入队
public void EnQueue(LinkQueueNode<T> node)
{
Rear.Next = node;
Rear = node;
}
//出队
public LinkQueueNode<T> DeQueue()
{
//队空
if (IsEmpty())
{
return default;
}
LinkQueueNode<T> _res = Front.Next;
//队中只有一个元素
if (_res == Rear)
{
Rear = Front;
}
Front.Next = _res.Next;
return _res;
}
//获取队头元素(不是头结点)
public LinkQueueNode<T> GetHead()
{
if (Front.Next != null)
{
return Front.Next;
}
return default;
}
}
public class LinkQueueNode<T>
{
public T Data;
public LinkQueueNode<T> Next;
public LinkQueueNode(){}
public LinkQueueNode(T data)
{
Data = data;
}
}
}
说明:
- 这里的链队是有头结点的链队哈,头结点的存在,是为了方便处理链队,其本身不存放任何数值。
- 链队相比数组来说,没有复杂的索引计算,所以相对来说更好理解。
- 代码里没有写获取元素个数,如果想,再加一个NodeCount属性,自己维护即可。
结束语:针不戳。