什么是队列?
类似于链表和堆栈,队列也是存储数据的结构。队列中数据进入队列的顺序很重要,一般来说,队列就是一群人或者事物按照排好的顺序等待接受服务或者处理。
举例
拿去银行办业务来举例。生活中我们去银行办理业务,一般都需要去机器拿号,然后等待着柜台业务人员叫号。叫到你,你就过去处理就行了。但是银行是有 vip 服务的,拥有 vip 权益的人可以更快的享受到业务办理,也就是说人家比你有更高的优先权。vip特权通道,你值得拥有!
图解:
任务队列的需求:
应用所实现的队列,设计并完成一个随机任务排队问题的求解。要求:
① 任务由任务号、任务产生时间、任务时长、任务开始处理和任务处理完成时间等信息组成;
② 任务由系统随机产生;任务产生后按产生的顺序排队等候处理。可设平均每5分钟(并非每隔5分名钟)产生一个新任务,任务时长为1~10分钟范围内。
③ 系统将依次处理排队等候的任务。
④ 系统运行超过一定时间后将停止产生新任务;
⑤ 按任务处理顺序,输出处理后的任务信息。
针对所选择的求解问题,编写测试程序完成设计任务的求解,并通过运行结果验证算法和程序设计的正确性。
下面就来实现任务队列基本需求:
状态常量
#include <stdlib.h>
#include <stdio.h>
#include <time.h>//时间的头文件
#include <unistd.h>//sleep的头文件
#include <string.h>
#define OK 1
#define ERROR 0
#define OVERFLOW –2
#define TRUE 1
#define FALSE 0
typedef int Status;
任务结构体
typedef struct Elem{
int TashNum;//任务号
char TaskGenerTime[50];//任务产生时间
int TaskTime;//任务时长
char TaskStartTime[50];//任务开始处理时间
char TaskEndTime[50];//任务结束时间
}ELemType;
//结点结构
typedef struct QNode{
ELemType data;
struct QNode *next;
}QueueNode1,*QueueNode;
//队列的链表结构
typedef struct{
QueueNode front;//队头
QueueNode rear;//对尾
}LinkQueue;
任务队列的基本操作
//结点结构
typedef struct QNode{
ELemType data;
struct QNode *next;
}QueueNode1,*QueueNode;
//队列的链表结构
typedef struct{
QueueNode front;//队头
QueueNode rear;//对尾
}LinkQueue;
//初始化队列
Status QueueInit(LinkQueue *Queue);
//销毁队列
Status QueueDestory(LinkQueue *Queue);
//清空队列
Status QueueClear(LinkQueue *Queue);
//判空
Status QueueEmpty(LinkQueue Queue);
//进队列
Status QueuePush(LinkQueue *Queue,ELemType Node);
//出队列
Status QueuePop(LinkQueue *Queue,ELemType *Node);
//遍历队列
Status QueueTraver(LinkQueue Queue);
//产生任务
ELemType ProduceTask(ELemType *Node,int num);
//求长度
Status QueueLength(LinkQueue Queue);
//打印入队
Status QueuePrint(ELemType Type);
//打印出队
Status QueuePrint1(ELemType Type);
//获取队头元素
Status GetHead(LinkQueue Queue,ELemType *Node);
基本操作的实现
初始化
//初始化空的队列
Status QueueInit(LinkQueue *Queue){
Queue->front = Queue->rear = (QueueNode)malloc(sizeof(QueueNode1));
if(!Queue->front){
printf("分配空间失败");
return FALSE;
}
Queue->front->next =NULL;
printf("链队创建成功!\n");
return OK;
}
销毁队列
//销毁队列
Status QueueDestory(LinkQueue *Queue){
while(Queue->front){
Queue->rear=Queue->front->next;//从队头开始销毁
free(Queue->front);
Queue->front = Queue->rear;
}
return OK;
}
清空队列,头节点还在
//清空队列,队头指针还在
Status QueueClear(LinkQueue *Queue){
QueueNode p,q;
Queue->rear =Queue->front;//跟初始状态相同,Q->rear指向头结点
p=Queue->front->next;//开始销毁队头元素,队头,对尾依然保留
Queue->front->next =NULL;
while(p){
q = p;
p = p->next;
free(q);
}
return OK;
}
判空
/队列是否空
Status QueueEmpty(LinkQueue Queue){
if(Queue.front == Queue.rear)
return TRUE;
else
return FALSE;
}
排队人数
//取队列长度
Status QueueLength(LinkQueue Queue){
int count = 0;
QueueNode p = Queue.front;
while(Queue.rear != p){
count++;
p = p->next;
}
printf("到目前为止还有%d人排队!\n",count);
return OK;
}
获取队头元素
//获取队头元素
Status GetHead(LinkQueue Queue,ELemType *Node){
QueueNode p;
if(Queue.front == Queue.rear)//队空
return ERROR;
p=Queue.front->next;
*Node = p->data;
return OK;
}
在队头插入人数
//对尾插入元素
Status QueuePush(LinkQueue *Queue,ELemType Node){
QueueNode node = (QueueNode)malloc(sizeof(QueueNode1));
if(!node){
return FALSE;
}
node->data = Node;
node->next =NULL;
Queue->rear->next =node;//原来对尾的next指向新的元素
Queue->rear =node;//将新元素变为对尾
return OK;
}
队头元素出队
//队头元素出队
Status QueuePop(LinkQueue *Queue,ELemType *Node){
QueueNode p;
if(Queue->front == Queue->rear)
return ERROR;
p=Queue->front->next;//p指向队头元素
*Node = p->data;
Queue->front->next = p->next;//头结点的后继指向队头的下一个元素
if(Queue->rear == p){//队头等于对尾了
Queue->rear = Queue->front;//对尾指向头结点
}
free(p);
return OK;
}
遍历任务
//遍历元素
Status QueueTraver(LinkQueue Queue){
QueueNode p;
p = Queue.front->next;
while(p){
printf("任务序号:%d\n任务时长:%d分钟\n任务产生时间:%s\n",p->data.TashNum,p->data.TaskTime,p->data.TaskGenerTime);
p=p->next;
}
printf("\n");
return OK;
}
打印入队的任务
//打印入队
Status QueuePrint(ELemType Type){
printf("*******************************************************\n");
printf("任务序号:%d\n任务时长:%d分钟\n任务产生时间:%s",Type.TashNum,Type.TaskTime,Type.TaskGenerTime);
printf("*******************************************************\n");
return OK;
}
打印出队任务
//打印出队
Status QueuePrint1(ELemType Type){
printf("*******************************************************\n");
printf("任务序号:%d\n任务时长:%d分钟\n任务产生时间:%s任务开始时间:%s任务结束时间:%s",Type.TashNum,Type.TaskTime,Type.TaskGenerTime,Type.TaskStartTime,Type.TaskEndTime);
printf("*******************************************************\n");
return OK;
}
产生任务
ELemType ProduceTask(ELemType *Node,int num){
time_t starTime;
srand((unsigned)time(0));//随机数种子
//任务号
Node->TashNum = num;
//任务时长
Node->TaskTime = 1 + rand()%10;
//任务产生时间
char *Timm = Node->TaskGenerTime;
time(&starTime);
Timm = ctime(&starTime);
strcpy(Node->TaskGenerTime, Timm);//将Timm传递给任务产生时间
return *Node;
}
以下是测试环节:
int main(){
//int i;
ELemType Type;
LinkQueue Queue;
QueueInit(&Queue);
QueueEmpty(Queue);
int n;
printf("请输入产生任务的总时间(分钟)\n");
scanf("%d",&n);
for (int i = 1; i <= n; i++) {
sleep(2);
printf("任务%d入队\n",i);
ELemType Type1 = ProduceTask(&Type, i);
QueuePush(&Queue, Type1);
QueuePrint(Type1);
}
// QueueTraverse(q);
time_t tm;
time_t tn;
printf("\n");
printf("任务产生结束,接下来开始处理任务!\n");
printf("\n");
while (!QueueEmpty(Queue)) {
QueueLength(Queue);
//出队列
QueuePop(&Queue,&Type);
char *TIME = Type.TaskStartTime;
time(&tm);
TIME = ctime(&tm);
strcpy(Type.TaskStartTime, TIME);
int TIMEE = Type.TaskTime;
sleep(TIMEE);
char *TIME1 = Type.TaskEndTime;
time(&tn);
TIME1 = ctime(&tn);
strcpy(Type.TaskEndTime, TIME1);
//打印出的队列
QueuePrint1(Type);
//产生一个任务,任务由任务号、任务产生时间、任务时长、任务开始处理和任务处理完成时间等信息组成
//给定任务号;任务号由for循环产生
//获取当前的时间,毫秒值赋值给任务产生时间
//任务时长由是一个随机数,由系统生成1-10的随机数赋值给任务时长
//记录任务进队列排队的时间赋值给任务开始时间
//记录任务出队列的时间赋值给任务结束时间
}
printf("任务处理结束!\n");
QueueClear(&Queue);
QueueDestory(&Queue);
printf("队列已经销毁\n");
return 0;
}
运行结果图
全文终!!!!!!!!!