在编程语言中怎样定义队列及其使用(C++)
队列在编程语言中是如何定义的呢?小编与大家分享自己的经验。
队列的定义
队列是限制结点插入操作固定在一端进行,而结点的删除操作固定在另一端进行的线性表.
队列犹如一个两端开口的管道.允许插入的一端称为队头,允许删除的一端称为队尾.队头和队尾各用一个”指针”指示,称为队头指针和队尾指针.不含任何结点的队列称为”空队列”.队列的特点是结点在队列中的排队次序和出队次序按进队时间先后确定,即先进队者先出队.因此,队列又称先进先出表.简称FIFO(first in first out)表.
步骤
队列是用来存储暂未处理但需要按一定顺序处理的元素的一种数据结构。
队列是一种先进先出(First In First Out,FIFO)的线性表,特点是先进队的元素先出队。
队列只允许在表的一端进行插入,而在另一端删除元素。
队尾是队列中允许插入的一端;队首是队列中允许删除的一端。
一般用顺序表q[m]存储队列中的元素,m是队列能存储元素的最大数量。
front队首指针指向队首元素存储的位置;rear队尾指针指向队尾元素的下一个位置。
顺序队列及其操作
队列的顺序存储结构
顺序存储结构存储的队列称为顺序队列.和顺序表一样,用一个一维数组存.对头在数组的低下标端,队尾设在高下表端.队头,队尾指针值是数组元素的下标.对头指针始终指向对头结点的前一个结点位置,初始值为0.队尾指针是指向队尾结点位置,初始值也为0.
队列初始条件:队头指针=队尾指针=0
队列满条件:队尾指针=m(设队列当前容量为m)
队列空条件:队头指针=队尾指针
在QueueCs.c文件中定义了结构
#define DT char #define M 100 typedef struct { DT data[M]; int front,rear; }SEQUEUE;
data[M]也为数组为队列,front为队头指针,rear为队尾指针.(注意:front和rear是整数类型,不是指针类型),当front=rear=0时,为初始队列.因为C语言中数组的第一个元素下标为0,而不是1;所以这里约定数组元素data[0]闲置不用.
顺序队列上的操作
(1)创建队列
初始化队列,队头指针和队尾指针=0.
在QueueControl.h写出方法声明
/* 创建队列 */ SEQUEUE initQueue();
在QueueControl.c中实现此方法
#include "QueueControl.h" /* 创建队列 */ SEQUEUE initQueue(){ SEQUEUE Q; //1.初始化队列,队头指针=队尾指针=0 Q.front=Q.rear=0; return Q; }
(2)插入
在QueueControl.h写出方法声明
/* 插入 */ SEQUEUE inQueue(SEQUEUE Q,DT x);
在QueueControl.c中实现此方法
#include "QueueControl.h" SEQUEUE inQueue(SEQUEUE Q,DT x){ //1.判断队列是上溢,就是队尾指针是否等于最大申请的空间 if(Q.rear==M){ printf("Up Overflow\n"); }else{ //2.从队尾插入结点 Q.rear++; Q.data[Q.rear]=x; printf("in success\n"); } return Q; }
(3)删除
在QueueControl.h写出方法声明
/* 删除 */ SEQUEUE outQueue(SEQUEUE Q); /* 打印队列元素 */ void printQueue(SEQUEUE Q);
在QueueControl.c中实现此方法
#include "QueueControl.h" SEQUEUE outQueue(SEQUEUE Q){ //1.首先判断是否是空队列 if(Q.front==Q.rear){ printf("queue is empty\n"); }else{ //2.删除结点是从队头删除 Q.front++; printf("out success\n"); } return Q; } /* 打印队列元素 */ void printQueue(SEQUEUE Q){ //1.从队头开始打印数据 SEQUEUE temp=Q; printf("queue={"); while (temp.front<temp.rear) { temp.front++; if(temp.front==Q.front+1){ printf("%c",temp.data[temp.front]); }else{ printf(",%c",temp.data[temp.front]); } } printf("}\n"); }
在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断
#include "QueueControl.h" int main(int argc, const char * argv[]) { //初始化顺序队列 SEQUEUE queue=initQueue(); printQueue(queue); //插入 queue=inQueue(queue, 'a'); queue=inQueue(queue, 'b'); queue=inQueue(queue, 'c'); queue=inQueue(queue, 'd'); printQueue(queue); //删除 queue=outQueue(queue); printQueue(queue); return 0; }
打印结果:
queue={}
in success
in success
in success
in success
queue={a,b,c,d}
out success
queue={b,c,d}
Program ended with exit code: 0
从插入队列和删除队列操作的打印结果来看,队列的特点确实是:先进先出.
循环队列及其操作
循环队列的存储结构
根据顺序队列的操作和叙述可以看出,队尾指针=m表示队满,不能再插入结点了,当队头指针等于队尾指针表示对空.但是当队尾指针和队尾指针都等于m的时候,那么此时表示对空,那么也不能插入了其他的结点,但是此时0-m之间的结点已经空闲,这样许多空闲的结点不能被利用,浪费存储空间.
循环队列是把顺序队列的头尾相接形成一个圆环.逻辑上吧1号结点作为m号结点的后继结点处理.
循环队列初始条件:队头指针=队尾指针=0
循环队列队满条件:MOD(队尾指针+1,m)=队头指针
循环队列空条件:队头指针=队尾指针
队头指针推进计算:队头指针=MOD(队头指针+1,m)
队尾指针推进计算:队尾指针=MOD(队尾指针+1,m)
在QueueCycleCs.c文件中定义了结构
#define CDT char #define CM 5 typedef struct { CDT data[CM]; int front,rear; }SECYCLEQUEUE;
循环队列上的操作
(1)创建循环队列
初始化队列,队头指针和队尾指针=0.
在QueueCycyleControl.h写出方法声明
#include "QueueCycleCs.c" /* 创建循环队列 */ SECYCLEQUEUE initCycleQueue();
在QueueCycyleControl.c中实现此方法
#include "QueueCycleControl.h" /* 创建循环队列 */ SECYCLEQUEUE initCycleQueue(){ SECYCLEQUEUE Q; //队头指针=队尾指针=0; Q.front=Q.rear=0; return Q; }
(2)插入
在QueueCycyleControl.h写出方法声明
#include "QueueCycleCs.c" /* 循环队列插入 */ SECYCLEQUEUE inCycleQueue(SECYCLEQUEUE Q,char x);
在QueueCycyleControl.c中实现此方法
#include "QueueCycleControl.h" SECYCLEQUEUE inCycleQueue(SECYCLEQUEUE Q,CDT x){ //1.判断循环队列是否已经满了,MOD(队尾指针+1,m)=队头指针 if((Q.rear+1)%CM==Q.front){ printf("queue is full!\n"); }else{ //2.在队尾插入,计算队尾指针的 Q.rear=(Q.rear+1)%CM; //3.设置插入结点的值数值 Q.data[Q.rear]=x; printf("in Cycle queue Success!\n"); } return Q; }
(3)删除
在QueueCycyleControl.h写出方法声明
#include "QueueCycleCs.c" /* 循环队列删除 */ SECYCLEQUEUE outCycleQueue(SECYCLEQUEUE Q); /* 打印循环队列 */ void printCycleQueue(SECYCLEQUEUE Q);
在QueueCycyleControl.c中实现此方法
#include "QueueCycleControl.h" SECYCLEQUEUE outCycleQueue(SECYCLEQUEUE Q){ //1.判断循环队列是否是空 if(Q.front==Q.rear){ printf("Cycle queue is Empty!\n"); }else{ //2.删除结点从队头删除,计算队头指针:队头指针=MOD(队头指针+1,m) Q.front=(Q.front+1)%CM; printf("out cycle queue success!\n"); } return Q; } /* 打印循环队列 */ void printCycleQueue(SECYCLEQUEUE Q){ //M=5; //1.从队头开始打印数据 SECYCLEQUEUE temp=Q; printf("queue={"); //2.判断的条件是,队头指针!=队尾指针 while (temp.front!=temp.rear) { temp.front=(temp.front+1)%CM; if(temp.front==((Q.front+1)%CM)){ printf("%c",temp.data[temp.front]); }else{ printf(",%c",temp.data[temp.front]); } } printf("}\n"); }
在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断
#include "QueueCycleControl.h" int main(int argc, const char * argv[]) { //创建循环队列 SECYCLEQUEUE CQ=initCycleQueue(); //插入数据5个结点,但是最大是5,一个空闲,最后一个添加不进去, CQ=inCycleQueue(CQ, 'a'); CQ=inCycleQueue(CQ, 'b'); CQ=inCycleQueue(CQ, 'c'); CQ=inCycleQueue(CQ, 'd'); CQ=inCycleQueue(CQ, 'e'); printCycleQueue(CQ); //删除节点-三个结点 CQ=outCycleQueue(CQ); CQ=outCycleQueue(CQ); CQ=outCycleQueue(CQ); printCycleQueue(CQ); //插入-两个结点 CQ=inCycleQueue(CQ, 'e'); CQ=inCycleQueue(CQ, 'f'); printCycleQueue(CQ); //删除节点--删除四个结点,现在此时是三个结点,最后一个删除不了 CQ=outCycleQueue(CQ); CQ=outCycleQueue(CQ); CQ=outCycleQueue(CQ); CQ=outCycleQueue(CQ); printCycleQueue(CQ); return 0; }
打印结果:
in Cycle queue Success!
in Cycle queue Success!
in Cycle queue Success!
in Cycle queue Success!
queue is full!
queue={a,b,c,d}
out cycle queue success!
out cycle queue success!
out cycle queue success!
queue={d}
in Cycle queue Success!
in Cycle queue Success!
queue={d,e,f}
out cycle queue success!
out cycle queue success!
out cycle queue success!
Cycle queue is Empty!
queue={}
Program ended with exit code: 0
链队列及其操作
队列的链存储结构
链存储结构存储的队列称为链队列.队头指针指向链队列的头结点,头结点的指针域若为空,则为空队列;若不为空,则为指向队首结点的指针.
链队列设有一个队头指针,其值指向队列的头结点.也是唯一地标示一个链队.设置一个队尾指针方便插入结点.队头指针和队尾指针都是指针型变量.
链队列没有容量的限制,所以在可用的存储空间范围内,一般不会出现上溢问题,也不存在如顺序队列的假溢出问题.
在QueueLinkCs.c中定义了结构
#define LDT char //结点类型 typedef struct llnode{ LDT data; struct llnode *next; }LINKNODE; //链队列结构 typedef struct{ LINKNODE *front,*rear; }LINKQUEUE;
链队列上的操作
(1)创建链队列
在QueueLinkControl.h写出方法声明
#include <stdio.h> #include "QueueLinkCs.c" /* 创建链队 */ LINKQUEUE * initLinkQueue(LINKQUEUE *LQ);
在QueueLinkControl.c中实现此方法
#include "QueueLinkControl.h" #include <stdlib.h> /* 创建链队 */ LINKQUEUE *initLinkQueue(LINKQUEUE *LQ){ //设置队头指针 LQ->front=(LINKNODE *)malloc(sizeof(LINKNODE)); LQ->front->data='#';//设置队头指针,也是头结点的指针域 LQ->front->next=NULL; //初始条件:队头指针和队尾指针一致 LQ->rear=LQ->front; return LQ; }
(2)插入
在QueueLinkControl.h写出方法声明
/* 链队插入:队尾 */ LINKQUEUE * inLinkQueue(LINKQUEUE *LQ,LDT x);
在QueueLinkControl.c中实现此方法
(3)删除
在QueueLinkControl.h写出方法声明
/* 链队删除:队头 */ LINKQUEUE *outLinkQueue(LINKQUEUE *LQ); /* 打印链表结点 */ void printLinkQueue(LINKQUEUE *LQ);
在QueueLinkControl.c中实现此方法
#include "QueueLinkControl.h" #include <stdlib.h> LINKQUEUE *outLinkQueue(LINKQUEUE *LQ){ if(LQ==NULL || LQ->rear==LQ->front){ printf("LQ is empty!\n"); return LQ; } //1.获取首结点 LINKNODE *frontNextNode; frontNextNode=LQ->front->next; //2.将首节点的next指针域的值存储头结点的next域 LQ->front->next=frontNextNode->next; //3.如果队尾结点等于首节点的next指针域的值,那么表示是空栈,根据空链队列的结构,还需修改队尾指针,使指向头结点. if(LQ->rear==frontNextNode){ LQ->rear=LQ->front; } //4.释放删除的结点 free(frontNextNode); printf("out link queue success!\n"); return LQ; } /* 打印链表结点 */ void printLinkQueue(LINKQUEUE *Q){ //实例化一个LQ,为了不改变原来链队Q LINKQUEUE *LQ; LQ=(LINKQUEUE *)malloc(sizeof(LINKQUEUE)); LQ->front=Q->front; LQ->rear=Q->rear; printf("queue={"); //1.判断不是空链表 if(LQ!=NULL && LQ->rear!=LQ->front){ int flag=0; do{ //2.输出数据 if(flag==0){ printf("%c",LQ->front->data); flag=1; }else{ printf(",%c",LQ->front->data); } //3.链头指针向后移动 LQ->front=LQ->front->next; }while (LQ->front!=LQ->rear) ; printf(",%c",LQ->front->data); } printf("}\n"); }
在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断
#include "QueueLinkControl.h" int main(int argc, const char * argv[]) { //创建链队列 LINKQUEUE *LQ=(LINKQUEUE *)malloc(sizeof(LINKQUEUE)); LQ=initLinkQueue(LQ); //向链队插入结点 LQ=inLinkQueue(LQ,'a'); LQ=inLinkQueue(LQ,'b'); LQ=inLinkQueue(LQ,'c'); LQ=inLinkQueue(LQ,'d'); printLinkQueue(LQ); //删除结点--从队头 LQ=outLinkQueue(LQ); LQ=outLinkQueue(LQ); printLinkQueue(LQ); return 0; }
打印结果:
in link queue success!
in link queue success!
in link queue success!
in link queue success!
queue={#,a,b,c,d}
out link queue success!
out link queue success!
queue={#,c,d}
Program ended with exit code: 0
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相关文章
关于C/C++中的side effect(负效应)和sequence point(序列点)
不知你在写code时是否遇到这样的问题?int i = 3; int x = (++i) + (++i) + (++i); 问x值为多少?进行各种理论分析,并在编译器上实践,然而可能发现最终的结果是不正确的,也是不稳定的,不同的编译器可能会产生不同的结果。这让人很头疼2013-10-10OpenMP中For Construct对dynamic的调度方式详解
在本篇文章当中主要给大家介绍 OpenMp for construct 的实现原理,与他相关的动态库函数分析以及对 dynamic 的调度方式进行分析,希望对大家有所帮助2023-02-02
最新评论