• [数据结构


    一、什么是顺序队列?

    队列的顺序储存结构:用数组存储队列,为了避免当只有一个元素时,队头和队尾重合使得处理变得麻烦,所以引入两个指针:front 指针指向队头元素,rear 指针指向队尾元素的下一个位置,当 front=rear 时,为空队列,结构如下图所示:


    顺序队列的结构代码如下:

    typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */
    
    /* 循环队列的顺序存储结构 */
    typedef struct
    {
        ElemType data[MAXSIZE];
        int front;      /* 头指针 */
        int rear;       /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
    }SeqQueue;
    

    假设是长度为 5 的数组,初始状态,空队列如下图左所示,front 与 rear 指针均指向下标为 0 的位置。然后入队 a1、a2、a3、a4,front 指针依然指向下标为 0 位置,而 rear 指针指向下标为 4 的位置,如下图右所示:


    出队 a1、a2,则 front 指针指向下标为 2 的位置,rear 不变,如下图左所示,再入队 a5,此时 front 指针不变,rear 指针移动到数组之外。数组之外, 那将是哪里?如下图右所示:


    问题还不止于此。假设这个队列的总个数不超过5个,但目前如果接着入队的话,因数组末尾元素已经占用,再向后加,就会产生数组越界的错误,可实际上,我们的队列在下标为0和1的地方还是空闲的。我们把这种现象叫做 “假溢出"。


    二、什么是顺序循环队列?

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

    刚才的例子继续,上图的 rear 可以改为指向下标为 0 的位置,这样就不会造成指针指向不明的问题了,如下图所示:


    接着入队 a6,将它放置于下标为 0 处,rear 指针指向下标为 1 处,如下图左所示。若再入队 a7,则 rear 指针就与 front 指针重合,同时指向下标为 2 的位置,如下图右所示:


    此时问题又出来了,我们刚才说,空队列时,front 等于 rear,现在当队列满时,也是 front 等于 rear,那么如何判断此时的队列究竟是空还是满呢?

    • 办法一是设置一个标志变量 flag, 当 front == rear,且 flag = 0 时为队列空,当 front== rear,且 flag= 1 时为队列满。
    • 办法二是当队列空时,条件就是 front = rear,当队列满时,我们修改其条件,保留一个元素空间。也就是说,队列满时,数组中还有一个空闲单,例如下图所示,我们就认为此队列已经满了,也就是说,我们不允许上图右的情况出现:


    我们重点来讨论第二种方法,由于 rear 可能比 front 大,也可能比 front 小,所以尽管它们只相差一个位置时就是满的情况,但也可能是相差整整一圈。 所以若队列的最大尺寸为 QueueSize,那么队列满的条件是(rear+1) % QueueSize == front ,因此通用的计算队列长度公式为:(rear - front + QueueSize) % QueueSize

    注意:front 指针和 rear 指针后移不能直接使用 ++,而要使用Q->front = (Q->front + 1) % MAXSIZE,因为到达数组尾后需要移动到数组开头。


    三、基本操作

    3.1 初始化队列操作

    实现代码如下:

    // 初始化队列操作
    Status initQueue(SeqQueue *Q)
    {
    	Q->front = 0;
    	Q->rear = 0;
    
    	return  TRUE;
    }
    

    3.2 入队操作

    实现代码如下:

    // 入队操作
    Status enQueue(SeqQueue *Q, const ElemType e)
    {
    	// 判断队列是否已满
    	if ((Q->rear + 1) % MAXSIZE == Q->front) 
    		return FALSE;
    
    	Q->data[Q->rear] = e; // 将元素e赋值给队尾
    	Q->rear = (Q->rear + 1) % MAXSIZE; // rear指针向后移一位置,若到最后则转到数组头部
    
    	return  TRUE;
    }
    

    3.3 出队操作

    实现代码如下:

    // 出队操作
    Status deQueue(SeqQueue *Q, ElemType *e)
    {
    	// 判断是否为空队
    	if (Q->front == Q->rear) 
    		return FALSE;
    
    	*e = Q->data[Q->front]; // 将队头元素赋值给e
    	Q->front = (Q->front + 1) % MAXSIZE; // front指针向后移一位置,若到最后则转到数组头部
    
    	return  TRUE;
    }
    

    3.3 遍历队列操作

    实现代码如下:

    // 遍历队列操作
    Status tarverseQueue(const SeqQueue Q)
    {
    	int cur = Q.front; // 当前指针
    	while (cur != Q.rear) // 直到cur指向了队尾元素的下一个位置,即Q.rear,结束循环
    	{
    		printf("%d ", Q.data[cur]);
    		cur = (cur + 1) % MAXSIZE; // 当前指针向后推移
    	}
    	printf("
    ");
    
    	return TRUE;
    }
    

    四、完整程序

    #include <stdio.h>
    #include <stdlib.h>  
    
    #define TRUE 1
    #define FALSE 0
    #define MAXSIZE 5 /* 存储空间初始分配量 */
    
    typedef int Status;
    typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */
    
    /* 顺序循环队列的顺序存储结构 */
    typedef struct
    {
    	ElemType data[MAXSIZE];
    	int front; // 头指针
    	int rear; // 尾指针,若队列不空,指向队列尾元素的下一个位置
    }SeqQueue;
    
    Status initQueue(SeqQueue *Q); // 初始化队列操作
    Status enQueue(SeqQueue *Q, const ElemType e); // 入队操作
    Status deQueue(SeqQueue *Q, ElemType *e); // 出队操作
    Status tarverseQueue(const SeqQueue Q); // 遍历队列操作
    Status clearQueue(SeqQueue *Q); // 清空队列操作
    Status isEmpty(const SeqQueue Q); // 判断是否为空队列
    Status getHead(const SeqQueue Q, ElemType *e); // 获得队头元素
    int getLength(const SeqQueue Q); // 获得队列的长度
    
    // 初始化队列操作
    Status initQueue(SeqQueue *Q)
    {
    	Q->front = 0;
    	Q->rear = 0;
    
    	return  TRUE;
    }
    
    // 入队操作
    Status enQueue(SeqQueue *Q, const ElemType e)
    {
    	// 判断队列是否已满
    	if ((Q->rear + 1) % MAXSIZE == Q->front) 
    		return FALSE;
    
    	Q->data[Q->rear] = e; // 将元素e赋值给队尾
    	Q->rear = (Q->rear + 1) % MAXSIZE; // rear指针向后移一位置,若到最后则转到数组头部
    
    	return  TRUE;
    }
    
    // 出队操作
    Status deQueue(SeqQueue *Q, ElemType *e)
    {
    	// 判断是否为空队
    	if (Q->front == Q->rear) 
    		return FALSE;
    
    	*e = Q->data[Q->front]; // 将队头元素赋值给e
    	Q->front = (Q->front + 1) % MAXSIZE; // front指针向后移一位置,若到最后则转到数组头部
    
    	return  TRUE;
    }
    
    // 遍历队列操作
    Status tarverseQueue(const SeqQueue Q)
    {
    	int cur = Q.front; // 当前指针
    	while (cur != Q.rear) // 直到cur指向了队尾元素的下一个位置,即Q.rear,结束循环
    	{
    		printf("%d ", Q.data[cur]);
    		cur = (cur + 1) % MAXSIZE; // 当前指针向后推移
    	}
    	printf("
    ");
    
    	return TRUE;
    }
    
    // 清空队列操作
    Status clearQueue(SeqQueue *Q)
    {
    	Q->front = Q->rear = 0;
    
    	return TRUE;
    }
    
    // 判断是否为空队列
    Status isEmpty(const SeqQueue Q)
    {
    	return Q.front == Q.rear ? TRUE : FALSE;
    }
    
    // 获得队头元素
    Status getHead(const SeqQueue Q, ElemType *e)
    {
    	if (Q.front == Q.rear) // 判断是否为空队列
    		return FALSE;
    	*e = Q.data[Q.front];
    
    	return TRUE;
    }
    
    // 获得队列的长度
    int getLength(const SeqQueue Q)
    {
    	return  (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
    }
    
    int main()
    {
    	SeqQueue Q;
    
    	// 初始化队列
    	initQueue(&Q);
    
    	// 入队操作 
    	for (int i = 0; i < MAXSIZE - 1; i++)
    		enQueue(&Q, i);
    	printf("入队操作(0、1、2、3)! 
    
    ");
    
    	// 出队操作
    	ElemType d;
    	deQueue(&Q, &d);
    	printf("删除的元素是%d 
    
    ", d);
    
    	// 遍历队列
    	printf("遍历队列: ");
    	tarverseQueue(Q);
    	printf("
    ");
    
    	// 判断是否为空队列
    	printf("现在队列空否? %u (1:空 0:否)
    
    ", isEmpty(Q));
    
    	// 获得队列的长度
    	printf("队列长度为: %d 
    
    ", getLength(Q));
    
    	// 获得队头元素
    	getHead(Q, &d);
    	printf("队头元素是%d 
    
    ", d);
    
    	return 0;
    }
    

    输出结果如下图所示:


    参考:

    《大话数据结构 - 第4章》 栈与队列


  • 相关阅读:
    Xor 2020CCPC网络赛 数位DP
    D. Cleaning 前缀后缀
    Sum of Log ICPC上海区域赛 数位dp 双线程
    Sky Garden icpc上海站 2020
    Gitignore 2020 上海icpc区域赛
    单片机常用调试的接口有哪些
    基于单片机和温度传感器实现专用测温系统的设计
    大神带你如何正确认识它
    linux的top命令详解
    基于S3C44B0XARM7处理器的嵌入式统扩展USB接口的技术方案
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/10327803.html
Copyright © 2020-2023  润新知