实验指南
运行环境:
Dev c++
算法思想
本实验是模拟进程调度中的先来先服务算法,每次CPU都是按照进入就绪队列的先后次序依次选中一个进程装入CPU运行,等结束时再选取下一个。
核心数据结果
struct Time {
int hour, min;
};
struct node {
int id;//编号你
char name[20];//进程名
Time arrive;//到达就绪队列时间
int zx;//执行时间
Time start;//开始时间
Time finish;//完成时间
int zz;//周转时间=完成时间-到达时间
float zzxs;//带权周转系数=周转间/执行时间,下同
struct node* next;
};
程序框架
//函数名:check,函数参数:Time x(当前进程的到达时间),Time y(待插入进程的到达时间)
bool check(Time x, Time y) {
//函数功能:比较到达时间的早晚
}
struct Q{
node *front, *end;
};
//函数名:init,函数参数:Q &x(含有就绪队列的队头和队尾节点地址)
void init(Q &x) {
//函数功能:初始化,为之后操作做准备
}
//函数名:insert,函数参数:Q *x(指向含有就绪队列的队头和队尾节点的指针),node tmp()
void insert(Q *x, node tmp) {
//函数功能:构建并按到达时间先后插入进程节点放入就绪队列中
}
//函数名:dele,函数参数:Q &x(含有就绪队列的队头和队尾节点地址)
void dele(Q &x) {
//函数功能:初始化,为下一个进程序列做准备
}
//函数名:input,函数参数:Q &x(含有就绪队列的队头和队尾节点地址)
void input(Q &x) {
//函数功能:输入节点信息,构建并按到达时间先后依次插入进程节点放入就绪队列中
}
//函数名:cal,函数参数:Time x(当前进程的开始时间), int y(当前进程的执行时间)
Time cal(Time x, int y) {
//函数功能:计算当前进程的结束时间(开始时间+执行时间)
}
//函数名:deline,函数参数:Time x(上一进程的结束时间),Time y(当前进程的到达时间)
int deline(Time x, Time y) {
//函数功能:计算进程的等待时间(即上一进程的结束时间与当前进程的到达时间的时间差)
}
//函数名:fcfs,函数参数:Q *x(指向含有就绪队列的队头和队尾节点的指针)
void fcfs(Q *x) {
//函数功能:计算进程相关时间信息,分别确定开始时间,结束时间(开始时间+执行时间),周转时间(结束时间-到达时间),周转系数(周转时间/执行时间)
}
//函数名:output,函数参数:Q &x(含有就绪队列的队头和队尾节点的地址)
void output(Q &x) {
//函数功能:按进程执行顺序分别输出每个进程全部结果信息和系统平均时间
}
int main() {
Q x;
while(1) {
init(x);
input(x);
fcfs(&x);
output(x);
while(x.front != NULL) dele(x);
}
return 0;
}
测试用例:
14个进程:
100 p14 4:30 10
200 p13 3:20 10
400 p12 6:00 30
200 p11 7:10 40
5001 p1 19:40 20
5002 p4 10:10 10
5003 p5 10:05 30
5004 p2 9:55 15
5005 p3 9:45 25
5006 p6 11:40 20
5007 p8 12:10 10
5008 p9 13:05 30
5009 p10 19:55 15
5010 p7 7:15 155个进程:
5001 p1 9:40 20
5004 p4 10:10 10
5005 p5 10:05 30
5002 p2 9:55 15
5003 p3 9:45 2510个进程:
5009 p9 19:40 20
5005 p5 10:10 10
5004 p4 10:05 30
5003 p3 9:55 15
5002 p2 9:45 25
5006 p6 11:40 20
5007 p7 12:10 10
5008 p8 13:05 30
5010 p10 19:55 15
5001 p1 7:15 15
关键代码
#include<stdio.h>
#include<stdlib.h>
#include <malloc.h>
struct Time {
int hour, min;
};
struct node {
int id;//编号名
char name[20];//进程名
Time arrive;//到达就绪队列时间
int zx;//执行时间
Time start;//开始时间
Time finish;//完成时间
int zz;//周转时间=完成时间-到达时间
float zzxs;//带权周转系数=周转间/执行时间,下同
struct node* next;
};
//函数名:check,函数参数:Time x(当前进程的到达时间),Time y(待插入进程的到达时间)
bool check(Time x, Time y) {
//函数功能:比较到达时间的早晚
if((y.hour>x.hour)||(y.hour==x.hour&&(y.min>x.min)))
return true;
else
return false;
}
struct Q{
node *front, *end;
};void output(Q &x);
//函数名:init,函数参数:Q &x(含有就绪队列的队头和队尾节点地址)
void init(Q &x) {
//函数功能:初始化,为之后操作做准备
x.front=NULL;
x.end=NULL;
}
//函数名:insert,函数参数:Q *x(指向含有就绪队列的队头和队尾节点的指针),node tmp()
void insert(Q *x, node tmp) {
//函数功能:构建并按到达时间先后插入进程节点放入就绪队列中
node*N=(node*)malloc(sizeof(node));
node *p,*q;
p=x->front;
q=NULL;
*N=tmp;
N->next=NULL;
if(p==NULL&&q==NULL)//没有结点
{
x->front=N;
x->end=N;
}
else//有结点
{
while(p!=NULL)
{
if(p->next==NULL)
{
p->next=N;
x->end=N;
break;
}
p=p->next;
}
}
return ;
}
//函数名:dele,函数参数:Q &x(含有就绪队列的队头和队尾节点地址)
void dele(Q &x) {
//函数功能:初始化,为下一个进程序列做准备
node*p;
p=x.front;
x.front=x.front->next;
free(p);
}
//函数名:input,函数参数:Q &x(含有就绪队列的队头和队尾节点地址)
void input(Q &x) {
//函数功能:输入节点信息,构建并按到达时间先后依次插入进程节点放入就绪队列中
int flag;
printf("请输入操作(1:开始进度调度;0:结束进程):");
scanf("%d",&flag);
if(flag==0)
{
printf("操作结束!");
exit(0);
}
else
{
int n;
printf("请输入进程数量: ");
scanf("%d",&n);
printf("请输入进程的参数:\nid名 名字 到达时间 执行时间(分钟)\n");
while(n--)
{
node *p=(node*)malloc(sizeof(node));
scanf("%d %s %d:%d %d",&p->id,&p->name,&p->arrive.hour,&p->arrive.min,&p->zx);
p->next=NULL;
insert(&x,*p);
}
}
}
//函数名:cal,函数参数:Time x(当前进程的开始时间), int y(当前进程的执行时间)
Time cal(Time x, int y) {
//函数功能:计算当前进程的结束时间(开始时间+执行时间)
int m,h;
m=(x.min+y)%60;
h=x.hour+(x.min+y)/60;
x.hour=h;
x.min=m;
return x;
}
//函数名:deline,函数参数:Time x(上一进程的结束时间),Time y(当前进程的到达时间)
int deline(Time x, Time y) {
//函数功能:计算进程的等待时间(即上一进程的结束时间与当前进程的到达时间的时间差)
int h;
h=x.hour*60+x.min-y.hour*60-y.min;
return h;
}
//函数名:fcfs,函数参数:Q *x(指向含有就绪队列的队头和队尾节点的指针)
void fcfs(Q *x) {
//函数功能:计算进程相关时间信息,分别确定开始时间,结束时间(开始时间+执行时间),周转时间(结束时间-到达时间),周转系数(周转时间/执行时间)
node*p,*q,*head=NULL,*pre;
p=x->front;
while(p!=NULL)
{
node*N=(node*)malloc(sizeof(node));
*N=*p;
N->next=NULL;
if(head==NULL)
{
head=N;
q=head;
}
else
{
pre=NULL;
q=head;
while(q!=NULL)
{
if(!check(head->arrive,N->arrive))
{
N->next=head;
head=N;
break;
}
else if(check(q->arrive,N->arrive)&&q->next==NULL)
{
q->next=N;
x->end=N;
break;
}
else if(!check(q->arrive,N->arrive))
{
N->next=q;
pre->next=N;
break;
}
pre=q;
q=q->next;
}
}
p=p->next;
}
x->front=head;
x->end=pre;
p=x->front;
while(p!=NULL)
{
if(p==x->front)
{
p->start.hour=p->arrive.hour;
p->start.min=p->arrive.min;
p->finish=cal(p->start,p->zx);
p->zz=p->zx;
}
else
{
if((q->finish.hour>p->arrive.hour)||((q->finish.hour==p->arrive.hour)&&(q->finish.min>p->arrive.min)))
{
p->start.hour=q->finish.hour;
p->start.min=q->finish.min;
p->finish=cal(p->start,p->zx);
}
else
{
p->start.hour=p->arrive.hour;
p->start.min=p->arrive.min;
p->finish=cal(p->start,p->zx);
}
p->zz=deline(p->finish,p->arrive);
}
p->zzxs=p->zz*1.0/p->zx;
q=p;
p=p->next;
}
}
//函数名:output,函数参数:Q &x(含有就绪队列的队头和队尾节点的地址)
void output(Q &x) {
//函数功能:按进程执行顺序分别输出每个进程全部结果信息和系统平均时间
int sum=0,count=0;
float sum1=0;
node*p;
p=x.front;
printf("模拟进程FCFS调度过程输出结果:\nid名 名字 到达时间 执行时间(分钟) 开始时间 完成时间 周转时间(分钟) 带权周转系数\n");
while(p!=NULL)
{
printf("%5d ",p->id);
printf("%5s ",p->name);
printf("%5d:%2d ",p->arrive.hour,p->arrive.min);
printf("%8d(分钟) ",p->zx);
printf("%14d:%2d ",p->start.hour,p->start.min);
printf("%7d:%2d ",p->finish.hour,p->finish.min);
printf("%7d ",p->zz);
printf("%20.2f\n",p->zzxs);
sum=sum+p->zz;
sum1=sum1+p->zzxs;
count++;
p=p->next;
}
printf("系统平均周转时间为:%.2f\n",sum*1.0/count);
printf("系统平均带权周转系数为:%.2f\n",sum1/count);
}
int main() {
Q x;
while(1) {
init(x);//初始化
input(x);//1函数功能:输入节点信息,构建并按到达时间先后依次插入进程节点放入就绪队列中
fcfs(&x);//2函数功能:计算进程相关时间信息,分别确定开始时间,结束时间(开始时间+执行时间),周转时间(结束时间-到达时间),周转系数(周转时间/执行时间)
output(x);//3函数功能:按进程执行顺序分别输出每个进程全部结果信息和系统平均时间
while(x.front != NULL) dele(x);
}
return 0;
}
运行结果
实验总结
①对*、&的运算还不是很理解,还得多加练习
②在创建单链表时,判断条件没有设计好,比如应该是p!=NULL,如果是p->next==NULL则最后一个结点的值没有比较
③在创建单链表时,对于插入操作中的遍历指针和前驱结点理解有误,导致单链表创建不出来(遍历指针用于遍历,前驱指针为了能插入结点做准备)
④没有理解指针与结点的区别,都分配了空间,造成空间的浪费
⑤在传入node tmp的参数时,如果没有重新分配空间,并对其赋值的话,链表也无法创建
⑥对链表的创建,刚开始输入结点值后并没有输出信息,因为结点的指针没有加以判断,导致链表无法创建。