什么事队列呢?队列你可以理解为排队买票,先来先买,后来的人只能站末尾,不允许插队,先进者先出,这就是经典的队列。
双向队列
队列只支持两种基本的操作,出队和入队,跟栈一样也是一种操作受限的线性表数据结构。
队列的应用非常广泛,例如有循环队列,阻塞队列,并发队列,他们在很多偏底层的系统,框架,中间件开发中,起着关键性的作用,比如高性能队列Disruptor,Linux环形缓存都使用循环并发队列。
跟栈一样,队列可以使用数组实现或者是链表是实现,用数组实现的叫顺序队列,用链表是的叫链式队列
下面看下数组和链表的代码实现
typedef int datatype ; /*定义队列中数据元素的数据类型*/
#define maxsize 64 /*定义队列的容量*/
typedef struct {
datatype data[maxsize] ; /*用数组作为队列的储存空间*/
int front,rear ; /*指示队头位置和队尾位置的指针*/ }
sequeue ; /*顺序队列类型定义*/ sequeue *sq ; /*定义指向顺序队列的指针*/
bool pop(int &val)
{
if(front == rear) return false;
*val = data[front];
rear++;
return true;
}
bool push(int val)
{
if(rear == maxsize) return false;
data[rear] = val;
return true;
}
上面顺序队列有个缺陷就是,就是数组删除操作会导致数组中的数据不连续,就要采用数据搬移。也就是每次进行出队操作相当于删除数组下标为0的数据,就要搬移整个队列的数据,出队的时间复杂度就会从原来的O(1)变成O(n)。
那有什么方法优化一下呢?
我们先来看看下面这三张图
第一张是一个大小为7,然后里面有四个人在排队
第二张前面两个人出队了,空出来了两个位置
第三张又有三个小伙子进队了,而且后面没有了位置,那现在一次性搬移过去就行,这样局节省了
由图中可以看出,出队操作的时间复杂度还是O(1),进队O(1),均摊
为了避免搬移大量的数据,那就使用链表来实现循环链式队列
#ifndef QNODE_DATATYPE
#define QNODE_DATATYPE int
#endif
typedef QNODE_DATATYPE datatype;
// 定义一个循环队列的管理结构体
typedef struct seqent_queue
{
datatype *queue;
int front;
int tail;
int size;
}queue;
queue *init_queue(int len)
{
queue *q = calloc(1, sizeof(queue));
if(q != NULL)
{
q->size = len + 1;
q->queue = calloc(q->size, sizeof(datatype));
if(q->queue == NULL)
{
printf("分配队列空间失败!\n");
free(q);
exit(0);
}
q->front = q->tail = 0;
}
return q;
}
bool is_full(queue *q)判断是否为满队列
{
return (q->tail + 1)%q->size == q->front;
}
bool en_queue(datatype data, queue *q)q的tail向下一个移,对size取余,防止越界
{
if(is_full(q))
return false;
q->queue[q->tail] = data;
q->tail = (q->tail+1) % q->size;
return true;
}
bool is_empty(queue *q)判断是否为空队,也就是
{
return q->front == q->tail;
}
bool de_queue(datatype data, queue *q)q的front向下一个移,对size取余,防止越界
{
if(is_empty(q))
return false;
data = q->queue[q->front];
q->front = (q->front+1) % q->size;
return true;
}