转自:http://blog.csdn.net/thefutureisour/article/details/7835273
前言:
队列是从现实的“排队”现象中抽象出来的:新来的只能排在队伍的最后面,当你完成的自己事情,就可以离开队列,不能插队。队列是一种特殊的线性结构,它只能在这个结构的一端插入元素,在另一端删除元素。这两端分别称为队首和队尾。
当我们一看到要频繁的插入、删除元素,第一反应就是中链表实现。的确,在原有链表的基础上,稍作改动,就能把它变成一个队列。但是,程序员们想出了一个更加巧妙地办法,利用数组,准确的说,是循环数组,来方便而快速的实现队列。
循环数组的原理其实也并不复杂,举一个例子就明白了:假设我们有a0,a1,a2,a3这4个元素组成循环数组,并有front和rear两个标记指向队列的队首和队尾。当我们将0~2这3个元素依次入队后,有:a0 = 0,a1 =1,a2 =2。且front指向a0,rear指向a3。当我们让a0出队时,并不像以前那样,通过左移a0后面的元素拉完成,而是让front指向a1,当我们在让一个3入队时,a3=3,rear指向a0.如果再让a1出队,则front指向a2,如果让5入队,则a0 = 5;rear指向a2(我感觉是a1)。
概括的说,所谓的循环队列,完全是概念上YY出来的,我们还是用一般的数组来实现的,但是通过front和rear两个标记,是得队列按照我们事先设定的顺序排列出来。每当给队尾增加一个元素时,rear+1;但是如果rear已经指向数组的最后一个位置,那么通过取模的办法,可以让他跳转到第一个位置(如果这个位置不被队首元素占据的话)。每次出队时,front+1,同样的,如果front已经到了数组的最后,可以通过取模的办法让他跳转到数组的第一个。
代码:
#include <stdio.h>
#include <malloc.h>
typedef int ElemType;
typedef struct Queue
{
ElemType *data;
int front;
int rear;
int Qsize;
}Queue;
//1.初始化通过参数传进来创建队列的大小
bool initQueue(Queue *q, int size)
{
q->front = 0;
q->rear = 0;
q->Qsize = size;
q->data = (ElemType*)malloc(size*sizeof(ElemType));
if (q->data == NULL)
return false;
return true;
}
//2.清空队列
void clearQueue(Queue *q)
{
q->front = 0;
q->rear = 0;
}
//3.判断队列是否为空
//队列为空:q->front ==q->rear
//队列为满:(q->rear+1)%q->Qsize==q->front
bool EmeptyQueue(Queue *q)
{
if (q->front == q->rear)
{
printf("queue is empty !");
return true;
}
else if ((q->rear + 1) % q->Qsize == q->front)
{
printf("queue is not empty !");
return false;
}
}
//4.返回队首元素
bool getHead(Queue *q, ElemType *e)
{
if (EmeptyQueue(q))
{
printf("can not get the head element! \n");
return false;
}
else
{
*e = q->data[q->front];//取元素
return true;
}
}
//5.返回队列长度:在循环队列中
int Qlength(Queue *q)
{
return (q->rear - q->front + q->Qsize) % q->Qsize;
}
//6.入队
bool enQueue(Queue *q, ElemType e)
{
//如果队列已满,重新分配内存
if (q->rear == q->Qsize - 1)
{
q->data = (ElemType*)realloc(q->data, 2 * q->Qsize*sizeof(ElemType));
if (q->data == NULL)
return false;
else
q->Qsize *= 2;
}
//先赋值,然后队尾循环加1
q->data[q->rear] = e;
q->rear = (q->rear + 1) % q->Qsize;
return true;
}
//7.出队
bool deQueue(Queue *q, ElemType *e)
{
if (EmeptyQueue(q))
return false;
else
{
*e = q->data[q->front];
//队首标记循环加1
q->front = (q->front + 1 + q->Qsize) % q->Qsize;
}
return true;
}
说明:
我在定义时,专门定义了队列的容量,以防止不停的放里面加入元素时越界情况的发生。还有一点需要注意,当我定义了5个长度的队列时,实际能用的只有4个,另外一个供队尾标记使用。