一:队列的概述
队列是一个先进先出的线性表结构,在一端进行插入操作,另一段进行删除操作。例如我们平时打客服电话会忙线(客户数总是多于客服数,当客服空下来时,会先接通最先等待的客户的电话)、使用键盘进行各种数字字母的输入(输入god,也会输出god,而不是dog)、现实生活中的排队(先排队的先出队,后排队的后出队),我们把允许插入的一端称为队尾,允许删除的一段称为队头,插入操作称为入队,删除操作称为出队
定义说队列是一种线性表,它其实是一种特殊的线性表,它限制了插入、删除的位置
二:队列的顺序存储结构
用一段地址连续的存储单元依次存储队列中的数据元素
按照正常的顺序存储结构的话,在插入数据时,时间复杂度是O(1),但是在删除数据时,队列中所有元素都需要向前移动保证下标为0的位置不为空,所以时间复杂度是O(n),其实我们可以不限制队头元素必须是下标为0的位置,我们可以定义两个变量去指向不同位置,front变量指向队头元素,rear变量指向队尾元素的下一个位置,当删除一个元素时,front++,当插入一个元素时,rear++,当front=rear时队列为空,当rear等于存储队列中元素数组的长度时,表示队列已满,但是当数组的最后一个元素被占用时,rear会指向数组存储空间外的位置,发生数组越界的错误,但其实数组的前端是有空位置的,这种现象叫做"假溢出"
这样对队列的顺序存储结构进行了细微优化后,在读、取,插入,删除数据时,时间复杂度都是O(1),但是会发生假溢出现象,造成空间的浪费,于是引出了循环队列,队尾指针溢出的话就再次指向下标为0的位置,我们把这种头尾相连的队列顺序存储结构称为循环队列
但是在循环队列中当front=rear时,到底为空队列还是队列已满呢?我们可以使用count变量进行计数,当front=rear并且count=0时队列为空,当front=rear并且count=存储队列中元素数组的长度时队列为满
三:队列的链式存储结构
引言:对于队列的顺序存储结构,在插入数据时,时间复杂度是O(1),但是在删除数据时,时间复杂度是O(n),进行了细微优化后的循环队列虽然在插入、删除数据的时间复杂度都是O(1),但是又面临着顺序存储结构的通病——需要预先分配内存空间,所以引出了队列的链式存储结构(链队列)
因为队列只能在队头进行删除操作,队尾进行插入操作,所以需要两个指针引用,一个是队头指针,指向链队列的队头结点,一个是队尾指针,指向链队列的队尾结点。当添加元素时,若当前队列中没有元素则添加的结点既是队头结点也是队尾结点,若有元素则让队尾指针的后继指向新添加的结点即可。当删除元素时,若当前元素个数为1时,则出队后队头、队尾结点都为空,若当前元素个数不为1时,则让队头指向当前队头的下一个结点即可
四:实现队列的顺序存储结构(顺序队列)
using System;
//顺序队列类
public class Queue<T>
{
//存储顺序队列中元素的数组
private T[] array;
//顺序队列中元素的个数
public int Count
{
get
{
return rear - front;
}
}
//队头元素的下标
private int front;
//队尾元素的下标
private int rear;
//构造器初始化
public Queue()
{
array = new T[0];
front = 0;
rear = 0;
}
public Queue(int size)
{
array = new T[size];
front = 0;
rear = 0;
}
//判断队列是否为空
public bool IsEmpty()
{
return front == rear;
}
//判断队列是否已满
private bool IsFull()
{
return rear == array.Length;
}
//清空顺序队列
public void Clear()
{
front = 0;
rear = 0;
}
//入队
public void EnQueue(T item)
{
if (!IsFull())
{
array[rear] = item;
rear++;
}
else
{
throw new Exception("队列当前已满");
}
}
//出队
public T DeQueue()
{
if (!IsEmpty())
{
T temp = array[front];
front++;
return temp;
}
else
{
throw new Exception("队列当前为空");
}
}
//得到队头元素
public T Peek()
{
if (!IsEmpty())
{
return array[front];
}
else
{
throw new Exception("队列当前为空");
}
}
}
class Program
{
//*****进行测试*****
static void Main(string[] args)
{
Queue<int> myQueue = new Queue<int>(10);
myQueue.EnQueue(1);
myQueue.EnQueue(2);
myQueue.DeQueue();
myQueue.Peek();
}
}
五:实现队列的顺序存储结构的优化(循环队列)
using System;
//循环队列类
public class Queue<T>
{
//存储循环队列中元素的数组
private T[] array;
//循环队列中元素的个数
private int count;
public int Count
{
get
{
return count;
}
}
//队头元素的下标
private int front;
//队尾元素的下标
private int rear;
//构造器初始化
public Queue()
{
array = new T[0];
front = 0;
rear = 0;
}
public Queue(int size)
{
array = new T[size];
front = 0;
rear = 0;
}
//判断队列是否为空
public bool IsEmpty()
{
return front == rear && count == 0;
}
//判断队列是否已满
private bool IsFull()
{
return front == rear && count == array.Length;
}
//清空循环队列
public void Clear()
{
count = 0;
front = 0;
rear = 0;
}
//入队
public void EnQueue(T item)
{
if (!IsFull())
{
array[rear] = item;
rear = (rear + 1) % array.Length;
count++;
}
else
{
throw new Exception("队列当前已满");
}
}
//出队
public T DeQueue()
{
if (!IsEmpty())
{
T temp = array[front];
front = (front + 1) % array.Length;
count--;
return temp;
}
else
{
throw new Exception("队列当前为空");
}
}
//得到队头元素
public T Peek()
{
if (!IsEmpty())
{
return array[front];
}
else
{
throw new Exception("队列当前为空");
}
}
}
class Program
{
//*****进行测试*****
static void Main(string[] args)
{
Queue<int> myQueue = new Queue<int>(10);
myQueue.EnQueue(1);
myQueue.EnQueue(2);
myQueue.DeQueue();
myQueue.Peek();
}
}
六:实现队列的链式存储结构(链队列)
using System;
//结点类
public class Node<T>
{
//数据域
public T Data { get; set; }
//指针域
public Node<T> Next { get; set; }
//构造器初始化
public Node()
{
this.Data = default(T);
Next = null;
}
public Node(T value)
{
this.Data = value;
Next = null;
}
public Node(T value, Node<T> next)
{
this.Data = value;
this.Next = next;
}
public Node(Node<T> next)
{
this.Next = next;
}
}
//链队列类
public class Queue<T>
{
//队头指针
private Node<T> front;
//队尾指针
private Node<T> real;
//链队列中元素的个数
private int count;
public int Count
{
get
{
return count;
}
}
//构造器初始化
public Queue()
{
front = null;
real = null;
count = 0;
}
//判断队列是否为空
public bool IsEmpty()
{
return count == 0;
}
//清空顺序队列
public void Clear()
{
front = null;
real = null;
count = 0;
}
//入队
public void EnQueue(T item)
{
Node<T> addNode = new Node<T>(item);
if (real == null)
{
real = addNode;
front = addNode;
}
else
{
real.Next = addNode;
real = addNode;
}
count++;
}
//出队
public T DeQueue()
{
if (!IsEmpty())
{
Node<T> temp = front;
if (count == 1)
{
front = real = null;
}
else
{
front = front.Next;
}
count--;
return temp.Data;
}
else
{
throw new Exception("队列当前为空");
}
}
//得到队头元素
public T Peek()
{
if (!IsEmpty())
{
return front.Data;
}
else
{
throw new Exception("队列当前为空");
}
}
}
class Program
{
//*****进行测试*****
static void Main(string[] args)
{
Queue<int> myQueue = new Queue<int>(10);
myQueue.EnQueue(1);
myQueue.EnQueue(2);
myQueue.DeQueue();
myQueue.Peek();
}
}