一、队列是什么

队列是一种可以实现“先进先出”的存储结构。

队列通常可以分为两种类型:

一、顺序队列,采用顺序存储,当长度确定时使用。 顺序队列又有两种情况:

  ①使用数组存储队列的称为静态顺序队列。

  ②使用动态分配的指针的称为动态顺序队列。

二、链式队列,采用链式存储,长度不确定时使用(由链表实现)。

由于链式队列跟链表差不多,所以在这里只针对循环(环形)队列来说明并实践。
循环队列的两个参数:
  ①front,front指向队列的第一个元素。(front==head)
  ②rear,rear指向队列的最后一个有效元素的下一元素。(rear==tail)

队列的两个基本操作:出队和入队。

二、队列的结构

下面是一个循环队列(基于数组实现)的结构图:

三、队列的操作

入队(尾部入队) 
  ①将值存入rear所代表的位置。
  ②rear = (rear+1)%数组的长度。
出队(头部出队) 
  front = (front+1)%数组的长度。
队列是否为空   
  front和rear的值相等,则该队列就一定为空。
队列是否已满

在循环队列中,“队满”和“队空”的条件有可能是相同的,都是front ==rear,这种情况下,无法区别是“队满”还是“队空”。

针对这个问题,有3种可能的处理方法: 【这里采用了第3种处理方法】

(1)另设一个标志以区别是“队满”还是“队空”。(即入队/出队前检查是否“队满”/“队空”)

(2)设一个计数器,此时甚至还可以省去一个指针。

(3)少用一个元素空间,即约定队头指针在队尾指针的下一位置时就作为“队满”的标志,即“队满”条件为:(pQueue->rear+1)%MAX_SIZE == pQueue->front。

 

四、队列的一些问题以及解决办法

从上图可以看出,随着入队、出队的进行,会使整个队列整体向后移动,就会出现上图中的现象:队尾指针已经移到了最后,即队尾出现溢出,无法再进行入队操作,然而实际上,此时队列中还有空闲空间,这种现象称为“假溢出”。

解决“假溢出”的三种办法:

  • 方法一:每次删除队头元素后,把整个队列向前移动一个位置,这样可保证队头元素在存储空间的最前面。但每次删除元素时,都要把表中所有元素向前移动,效率太低。
  • 方法二:当队尾指针出现溢出时,判断队头指针位置,如果前部有空闲空间,则把当前队列整体前移到最前方。这种方法移动元素的次数大为减少。
  • 方法三:将队列看成头尾相接的循环结构,当队尾指针到队尾后,再从队头开始向后指,这样就不需要移动队列元素了,显然,第三种方法最经济、应用最多,这种顺序队列被称为“循环队列”或“环形队列”。

采用了这种头尾相接的循环队列后,入队的队尾指针加1操作及出队的队头指针加1操作必须做相应的修改,以确保下标范围为0~Max_Size-1。对指针进行取模运算,就能使指针到达最大下标位置后回到0,符合“循环”队列的特点。

因此入队时队尾指针加1操作改为: pQueue->tail = (pQueue->tail+1) % MAX_SIZE;

入队时队尾指针加1操作改为: pQueue->head = (pQueue->head+1) % MAX_SIZE;

五、动态顺序队列的实现

基于数组的动态顺序循环队列的具体实现:

5.1  MyQueue.h

#ifndef MYQUEUEC_H
#define MYQUEUEC_H #include <stdio.h>
#include <malloc.h> /* 队列: 只允许在表的一端(队尾rear)进行插入操作,而在另一端(队头front)进行删除操作的线性表
* 插入操作简称为入队 删除操作简称为出队 队列具有先进先出的特点
*/ /*=====队列的入队、出队示意图========
*
* 出队 ----------------- 入队
* <--- a1,a2,a3,...,an <---
* -----------------
*
*================================*/ typedef enum
{
OK=, //正确
ERROR=, //出错
TRUE=, //为真
FALSE= //为假
}status; typedef int ElemType; //宏定义队列的数据类型
#define MAX_SIZE 20 /*一、使用数组存储队列的称为静态顺序队列
*二、使用动态分配的指针的称为动态顺序队列*/
// 【这里的是动态顺序队列】
typedef struct
{
ElemType *pBase; //数组指针
ElemType front; //队头索引
ElemType rear; //队尾索引
int maxSize; //当前分配的最大容量
}queue; //创建空队列 queueCapacity-队列容量
status initQueue(queue *PQueue,int queueCapacity);
//销毁队列
void destroyQueue(queue *PQueue);
//清空队列
void clearQueue(queue *PQueue);
//判断队列是否为空
status isEmpityQueue(queue *PQueue);
//判断队列是否为满
status isFullQueue(queue *PQueue);
//获得队列长度
int getQueueLen(queue *PQueue);
//新元素入队 [先进先出原则:在队尾的位置插入] element-要插入元素
status enQueue(queue *PQueue,ElemType element);
//新元素出队,同时保存出队的元素 [先进先出原则:在队头的位置删除]
status deQueue(queue *PQueue,ElemType *pElement);
//遍历队列
void queueTraverse(queue *PQueue); #endif // MYQUEUEC_H

5.2  MyQueue.c

#include "myqueuec.h"

/* 队列: 只允许在表的一端(队尾rear)进行插入操作,而在另一端(队头front)进行删除操作的线性表
* 插入操作简称为入队 删除操作简称为出队 队列具有先进先出的特点
*/ /*=====队列的入队、出队示意图========
*
* 出队 ----------------- 入队
* <--- a1,a2,a3,...,an <---
* -----------------
*
*================================*/ //创建队列 queueCapacity-队列容量
status initQueue(queue *PQueue,int queueCapacity)
{
//给数组指针分配内存
PQueue->pBase = (ElemType *)malloc(sizeof(ElemType)*queueCapacity);
if(!PQueue->pBase)
{
printf("给数组指针分配内存失败\n");
return ERROR;
} PQueue->front = ; //最开始创建时,队头索引为0
PQueue->rear = ; //最开始创建时,队尾索引为0
PQueue->maxSize = queueCapacity; return OK;
} //销毁队列
void destroyQueue(queue *PQueue)
{
free(PQueue); //释放队列数组指针指向的内存
PQueue = NULL; //队列数组指针重新指向NULL,避免成为野指针
} //清空队列
void clearQueue(queue *PQueue)
{
PQueue->front = ; //队头索引清0
PQueue->rear = ; //队尾索引清0
} //判断队列是否为空
status isEmpityQueue(queue *PQueue)
{
if( PQueue->front == PQueue->rear ) //队头==队尾,说明为空
return TRUE; return FALSE;
} /*
*在循环队列中,“队满”和“队空”的条件有可能是相同的,都是front==rear,
*这种情况下,无法区别是“队满”还是“队空”。
*针对这个问题,有3种可能的处理方法:
*(1)另设一个标志以区别是“队满”还是“队空”。(即入队/出队前检查是否“队满”/“队空”)
*(2)设一个计数器,此时甚至还可以省去一个指针。
*(3)少用一个元素空间,即约定队头指针在队尾指针的下一位置时就作为“队满”的标志,
*即“队满”条件为:(PQueue->rear+1)%MAX_SIZE == PQueue->front。
* 【这里采用了第3种处理方法】
*/
//判断队列是否为满
status isFullQueue(queue *PQueue)
{
if( (PQueue->rear+)%PQueue->maxSize == PQueue->front ) //队列满
return TRUE; return FALSE;
} //获得队列长度
int getQueueLen(queue *PQueue)
{
//正常情况下,队列长度为队尾队头指针之差,但如果首尾指针跨容量最大值时,要%
return (PQueue->rear - PQueue->front + PQueue->maxSize)%PQueue->maxSize;
} //新元素入队 [先进先出原则:在队尾的位置插入] element-要插入元素
status enQueue(queue *PQueue,ElemType element)
{
if(isFullQueue(PQueue)==TRUE)
{
printf("队列已满,不能再插入元素了!\n");
return FALSE;
} //向队列中添加新元素
PQueue->pBase[PQueue->rear] = element;
PQueue->rear = (PQueue->rear+) % PQueue->maxSize; //将rear赋予新的合适的值 return TRUE;
} //新元素出队,同时保存出队的元素 [先进先出原则:在队头的位置删除]
status deQueue(queue *PQueue,ElemType *pElement)
{
//如果队列为空,则返回false
if(isEmpityQueue(PQueue)==TRUE)
{
printf("队列为空,出队失败!\n");
return FALSE;
} *pElement = PQueue->pBase[PQueue->front]; //先进先出
PQueue->front = (PQueue->front+) % PQueue->maxSize; //移到下一位置 return TRUE;
} //遍历队列
void queueTraverse(queue *PQueue)
{
int i = PQueue->front; //从头开始遍历
printf("遍历队列:\n");
while(i != PQueue->rear) //如果没有到达rear位置,就循环
{
printf("%d ", PQueue->pBase[i]);
i = (i+) % PQueue->maxSize; //移到下一位置
}
printf("\n");
}

5.3  main.c

#include <stdio.h>
#include "myqueuec.h" int main(void)
{
int value; //用于保存出队的元素
//创建队列对象
queue *PQueue = (queue *)malloc(sizeof(queue));
if(!PQueue->pBase)
{
printf("给队列对象分配内存失败\n");
return -;
} //调用初始化队列的函数
initQueue(PQueue,MAX_SIZE);
//调用出队函数
enQueue(PQueue, );
enQueue(PQueue, );
enQueue(PQueue, );
enQueue(PQueue, );
enQueue(PQueue, );
enQueue(PQueue, );
enQueue(PQueue, );
enQueue(PQueue, );
//调用遍历队列的函数
queueTraverse(PQueue);
//调用出队函数
if(deQueue(PQueue, &value))
{
printf("出队一次,元素为:%d\n", value);
}
queueTraverse(PQueue);
if(deQueue(PQueue, &value))
{
printf("出队一次,元素为:%d\n", value);
}
queueTraverse(PQueue); free(PQueue);
PQueue = NULL; getchar();
return ;
}

数据结构之顺序队列(C实现)的更多相关文章

  1. 数据结构 - 顺序队列的实行(C语言)

    数据结构-顺序队列的实现 1 顺序队列的定义 线性表有顺序存储和链式存储,队列作为一种特殊的线性表,也同样存在这两种存储方式.我们先来看队列的顺序存储结构. 队列的顺序储存结构:用数组存储队列,为了避 ...

  2. [Python] 数据结构--实现顺序表、链表、栈和队列

    说明: 本文主要展示Python实现的几种常用数据结构:顺序表.链表.栈和队列. 附有实现代码. 来源主要参考网络文章. 一.顺序表 1.顺序表的结构 一个顺序表的完整信息包括两部分,一部分是表中元素 ...

  3. 数据结构——顺序队列(sequence queue)

    /* sequenceQueue.c */ /* 顺序队列 */ #include <stdio.h> #include <stdlib.h> #include <std ...

  4. 数据结构Java实现07----队列:顺序队列&顺序循环队列、链式队列、顺序优先队列

    一.队列的概念: 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其 ...

  5. Javascript数据结构与算法--队列(顺序队列、优先队列、循环队列)的实现与用法

    前言 队列和栈非常类似,前面已经讲过了栈的实现与用法,现在我们来说说队列. 队列介绍 队列遵循FIFO(First In First Out,先进先出)原则的一组有序的项. 队列是一种特殊的线性表,特 ...

  6. 数据结构----队列:顺序队列&顺序循环队列、链式队列、顺序优先队列

    一.队列的概念: 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其 ...

  7. javascript数据结构与算法---队列

    javascript数据结构与算法---队列 队列是一种列表,不同的是队列只能在队尾插入元素,在队首删除元素.队列用于存储按顺序排列的数据,先进先出,这点和栈不一样(后入先出).在栈中,最后入栈的元素 ...

  8. C语言顺序队列

    顺序队列是一种只能在一头进和另一头出的数据结构,所以结构体里设2个指针分别指向头部和尾部,用数组来存储数据. #define MAXSIZE 1024 typedef int elemtype; ty ...

  9. <数据结构系列3>队列的实现与变形(循环队列)

    数据结构第三课了,今天我们再介绍一种很常见的线性表——队列 就像它的名字,队列这种数据结构就如同生活中的排队一样,队首出队,队尾进队.以下一段是百度百科中对队列的解释: 队列是一种特殊的线性表,特殊之 ...

随机推荐

  1. easyUI pagination分页控件点击下一页后跳转到最后一页

    easyui-pagination点击下一页直接跳转到最后一页的可能原因 今天做到聊天记录展示页面的时候发现一个bug:初次进入页面加载出第一页的数据,点击下一页的时候不是到第二页而是到最后一页. 如 ...

  2. Linux下使用make install安装的软件如何卸载

    如果是Ubuntu的系统,那么可以使用checkinstall来生成deb包来安装,然后卸载 参考:http://blog.sina.com.cn/s/blog_4178f4bf0101cmt7.ht ...

  3. Ubuntu 16.04安装网络流量监控工具Netspeed(附带10款最佳的指示器工具)

    安装: sudo add-apt-repository ppa:ferramroberto/linuxfreedomlucid sudo apt-get update sudo apt-get ins ...

  4. yum install tree 出错primary.sqlite.bz2: [Errno -1] Metadata file does not match checks 解决办法

    Loaded plugins: fastestmirrorLoading mirror speeds from cached hostfilehttp://ftp.sjtu.edu.cn/centos ...

  5. ETL增量单表同步简述_根据timestamp增量

    ETL增量单表同步简述 1. 实现需求 当原数据库的表有新增.更新.删除操作时,将改动数据同步到目标库对应的数据表. 2. 设计思路 设计总体流程图如下: 步骤简单说明: 1.设置job的执行属性,如 ...

  6. Java之旅(1)—Class类

    看到Class的时候,我们是不是会一下子想到我们敲代码中的class呢?此Class非彼class,这里讲的Class类实际上就是java类的统称,我们能够将其称之为抽象的类不是详细的一个类的名字. ...

  7. Codeforces Round #247 (Div. 2) B

    B. Shower Line time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  8. delphi的一些语法知识 以及参数传递问题,按引用方式传递参数,按值方式传递参数

    //delphi中exit,abort,break,continue 的区别 exit: 退出函数体abort: 遇到异常,安静处理,就是不显示不提示break: 退出当前循环体,包括for ,whi ...

  9. 自已实现一个UI库

    [2014年写一个UI库时写的几个文章,公布出来] 几年前的一个嵌入式的UI开发,使自己有机会接触到了UI的一些底层知识,尽管之前也开发过非常多Windows下的信息应用系统,也做非常多的界面开发,但 ...

  10. Tcl学习之--文件操作

    Tcl中文件名称操作遵循Unix/Linux的命名规范. x/y/z表示x文件夹下的y 子文件夹及y以下的子文件夹z. ~admin/email则表示admin用户的email目录. l  file ...