数据结构之循环顺序队列

队列的定义

队列(queue)是只允许在一端进行插入操作,另一端进行删除操作的线性表

    队列是一种先进先出的线性表,允许插入的一端称为队尾(rear),允许删除的一端称为队头(front)。向队列中插入元素称为入队,从队列中删除元素称为出队。当队列中没有元素时称为空队列。队列的操作是按先进先出的原则进行的,即新添加的元素总是加到队尾,每次离开的元素总是队头的元素。和栈一样,队列也是一种运算受限制的线性表,所以又叫先进先出表(First In First Out),简称FIFO表。

顺序队列


        假设一个队列有n个元素,则顺序存储的队列需要建立一个大于n的数组,并把队列的所有元素存储在数组的前n个单元,数组下标为0的一端即为队头。
        所谓的入队,就是在队尾追加一个元素,不需要移动任何元素,所以时间复杂度为O(1).


        队列的出队是在队头,即下标为0的位置,也就意味着,队列中的所有位置都得向前移动,以保证下标为0的位置,即对头不为空。此时时间复杂度为O(n)。
         

为了避免当只有一个元素时,队头和队尾重合使得处理变得麻烦,所以引入两个指针,front指针 指向队头元素,rear指针 指向队尾元素的下一个元素。这样当 front 等于 rear 时,不是队列中有一个元素,而是表示空队列。

        假设数组的长度为5,空队列及初始状态如图所示,front与rear指针都指向下标为0的位置。当队列中有4个元素时,front指针不变,rear指针指向下标为4的位置。
    

此时出队两个元素,则front指针指向下标为2的位置,rear不变。再入队一个元素,front指针不变,此时rear指针移动到数组之外 

 

    假设这个队列中的总个数不超过5个,但目前如果接着入队的话,会导致数组越界的错误,但是队列在下标为0和1的位置是没有元素的。我们把这种现象叫做“假溢出”。

循环队列

解决“假溢出”的办法就是后面满了,就再从头开始,也就是头尾相接的循环。我们把队列的这种头尾相接的顺序存储结构称为循环队列

        为了解决“假溢出”的问题,我们引入循环队列。

 接着入队两个元素,会发现rear指针与front重合了。

 解决办法为:当队列空时,判断条件就是 rear == front, 当队列满时,我们修改其判断条件,保留一个元素空闲。也就是说,队列满时,数组中还有一个空闲单元。以下两种情况,我们都认为队列已经满了。

循环队列的顺序存储结构如下: 

#define SIZE 8
 
typedef struct Queue
{
	int elem[SIZE];  // 存放队列元素
	int front;   // 队头
	int rear;    // 队尾
}Queue,*QueueS;

    基本操作:

    void InitQueueS(QueueS queue);     // 初始化循环队列
    bool Push(QueueS queue, int val);    // 入队
    bool Pop(QueueS queue, int *rtv);     // 出队
    void Show(QueueS queue);      // 打印队列元素
    int GetLength(QueueS queue);  // 计算队列长度
    bool IsEmpty(QueueS queue);   // 判空  
    void Clear(QueueS queue);    // 清空队列

void InitQueueS(QueueS queue)
{
	assert(queue != NULL);
	queue->front = 0;
	queue->rear = 0;
}
static bool IsFull(QueueS queue)
{
	return (queue->rear + 1) % SIZE == queue->front;
}
bool Push(QueueS queue, int val)
{
	if (IsFull(queue))
	{
		return false;
	}
	queue->elem[queue->rear] = val;
	queue->rear = (queue->rear + 1) % SIZE;
	return true;
}

bool Pop(QueueS queue, int *rtv)
{
	if (IsEmpty(queue))
	{
		return false;
	}
	if (rtv != NULL)
	{
		*rtv = queue->elem[queue->front];
	}
	queue->front = (queue->front + 1) % SIZE;
	return true;
}

void Show(QueueS queue)
{
	for (int i = queue->front; i != queue->rear; i = (i + 1) % SIZE)
	{
		printf("%d ", queue->elem[i]);
	}
	printf("\n");
}

int GetLength(QueueS queue)
{
	return (queue->rear - queue->front + SIZE) % SIZE;
}

bool IsEmpty(QueueS queue)
{
	return queue->front == queue->rear;
}

void Clear(QueueS queue)
{
	queue->front = queue->rear;
}

猜你喜欢

转载自blog.csdn.net/zhangfei5354/article/details/89668539