以下两种算法的代码均是在c++环境下编译进行
SSTF调度
初版:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int a[1010],n;
bool book[1010];
void change(int u)
{
int i,num=inf,minn=inf,flag;
for(i=0; i<n; i++)
if(abs(a[i]-u)<minn&&book[i]==0)
{
minn=abs(a[i]-u);
flag=a[i];
num=i;
}
if(num==inf)
return;
book[num]=1;
printf("%d\t\t\t%d\n",flag,minn);
change(flag);
return;
}
int main()
{
int i,m;
memset(book,0,sizeof(book));
printf("请输入访盘个数:");
scanf("%d",&n);
printf("\n");
printf("请输入访盘序列:");
for(i=0; i<n; i++)
scanf("%d",&a[i]);
printf("\n");
printf("请输入当前磁道号:");
scanf("%d",&m);
printf("\n");
printf("被访问的下一个磁道号\t移动距离(磁道数)\n");
change(m);
return 0;
}
最终版:
//SSTF调度
#include <bits/stdc++.h>//c++万能头文件
#define Coding author 孙黎明 19110543033
#define inf 0x3f3f3f3f//定义inf为无穷大
using namespace std;
//下面变量开全局,可以在main函数和自定义函数中同时使用,避免了传参数这一步骤
int a[1010];//定义数组a,用来保存访盘序列
int n;//n代表访盘个数
bool book[1010];//book[a]=1表示标号为a的访盘已经访问过,book[a]=0表示标号为a的访盘没有访问过。用来记录是否访问过,防止重复访问
void change(int u)//处理函数,用来处理访盘序列,同时给出被访问的下一个磁道号以及移动距离,u代表当前磁道号
{
int i;
int num=inf;//用来记录被访问的下一个磁道号的编号,后续将其标记,初始赋值为inf,可以根据后续num的值来判断递归是否结束
int minn=inf;//保存最少的移动距离,初始值赋值为无穷大
int flag;//记录被访问的下一个磁道号
for(i=0; i<n; i++)//遍历整个访盘序列
if(abs(a[i]-u)<minn&&book[i]==0)//如果一个磁道号与当前磁道号的差比最小值还要小,同时这个磁道号没有访问过(abs:绝对值函数)
{
minn=abs(a[i]-u);//更新最小值
flag=a[i];//记录被访问的下一个磁道号
num=i;//记录被访问的下一个磁道号的编号
}
if(num==inf)//如果num=inf的话,就说明所有磁盘都访问过了,代表该递归结束
return;//return出去
book[num]=1;//循环完成后,把最终确定的被访问的下一个磁道号的编号标记,代表这个编号的磁道号已经访问过了,后续不会再访问
printf("%d\t\t\t%d\n",flag,minn);//输出被访问的下一个磁道号以及移动距离,\t用来规范格式
change(flag);//递归思想,继续递归处理下一个磁道
return;
}
int main()
{
int i,m;
memset(book,0,sizeof(book));//初始化book数组全为0,代表所有磁道都没访问过
printf("请输入访盘个数:");
scanf("%d",&n);//读入访盘个数
printf("\n");
printf("请输入访盘序列:");
for(i=0; i<n; i++)//读入访盘序列
scanf("%d",&a[i]);
printf("\n");
printf("请输入当前磁道号:");
scanf("%d",&m);//读入当前磁道号
printf("\n");
printf("被访问的下一个磁道号\t移动距离(磁道数)\n");
change(m);//开始第一次调用处理函数处理数据
return 0;
}
输入样例1:
7
55 58 39 18 90 160 150
100
输出样例1:
被访问的下一个磁道号 移动距离(磁道数)
90 10
58 32
55 3
39 16
18 21
150 132
160 10
输入样例2:
8
1 3 5 50 49 55 100 9
3
输出样例2:
被访问的下一个磁道号 移动距离(磁道数)
3 0
1 2
5 4
9 4
49 40
50 1
55 5
100 45
CSCAN调度
初版:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i,ans,n,m,a[1010],num,flag;
printf("请输入访盘个数:");
scanf("%d",&n);
printf("\n");
printf("请输入访盘序列:");
for(i=0; i<n; i++)
scanf("%d",&a[i]);
sort(a,a+n);
printf("\n");
printf("请输入当前磁道号:");
scanf("%d",&m);
ans=m;
printf("\n");
for(i=0; i<n; i++)
if(a[i]>=m)
{
flag=i;
break;
}
printf("请输入磁头移动方向(向磁道号增加的方向请输入1,向磁道号减少的方向请输入0):");
scanf("%d",&num);
printf("被访问的下一个磁道号\t移动距离(磁道数)\n");
if(num==1)
{
for(i=flag; i<n; i++)
{
printf("%d\t\t\t%d\n",a[i],abs(a[i]-m));
m=a[i];
}
for(i=0; i<flag; i++)
{
printf("%d\t\t\t%d\n",a[i],abs(a[i]-m));
m=a[i];
}
}
else
{
for(i=flag-1; i>=0; i--)
{
printf("%d\t\t\t%d\n",a[i],abs(a[i]-m));
m=a[i];
}
for(i=n-1; i>=flag; i--)
{
printf("%d\t\t\t%d\n",a[i],abs(a[i]-m));
m=a[i];
}
}
return 0;
}
最终版:
//CSCAN调度
#include <bits/stdc++.h>//c++万能头文件
#define Coding author 孙黎明 19110543033
using namespace std;
int main()
{
int i;
int ans;//用来保存最开始的那个磁道号
int m;//当前磁道号
int n;//访盘个数
int a[1010];//用来保存访盘序列
int num;//记录磁头移动方向,0代表向磁道号减少的方向移动,1代表向磁道号增加的方向移动
int flag;//记录第一个大于等于当前磁道号的磁道的编号
printf("请输入访盘个数:");
scanf("%d",&n);//读入访盘个数
printf("\n");
printf("请输入访盘序列:");
for(i=0; i<n; i++)//读入访盘序列
scanf("%d",&a[i]);
sort(a,a+n);//利用c++ STL中自带的排序函数排序(默认从小到大排)
printf("\n");
printf("请输入当前磁道号:");
scanf("%d",&m);//读入当前磁道号
ans=m;//把最开始的磁道号赋值给ans保存
printf("\n");
for(i=0; i<n; i++)//遍历整个访盘序列找出第一个大于等于当前磁道号的磁道
if(a[i]>=m)
{
flag=i;//标记第一个大于等于当前磁道号的磁道的编号
break;//因为只需要找第一个,所以找到后就break出去
}
printf("请输入磁头移动方向(向磁道号增加的方向请输入1,向磁道号减少的方向请输入0):");
scanf("%d",&num);//读入磁头移动方向
printf("被访问的下一个磁道号\t移动距离(磁道数)\n");
if(num==1)//如果磁头是向磁道号增加的方向移动
{
for(i=flag; i<n; i++)//从第一个大于等于当前磁道号的磁道编号开始,从小到大,遍历整个访盘序列
{
printf("%d\t\t\t%d\n",a[i],abs(a[i]-m));//输出被访问的下一个磁道号和移动距离(abs绝对值函数,可以直接给出距离)
m=a[i];//更新当前磁道号,更新为刚才被访问的那个磁道
}
for(i=0; i<flag; i++)//如果磁头到达最大处,就再从头开始到flag,遍历访盘序列,寻找被访问的下一个磁道号
{
printf("%d\t\t\t%d\n",a[i],abs(a[i]-m));//输出被访问的下一个磁道号和移动距离(abs绝对值函数,可以直接给出距离)
m=a[i];//更新当前磁道号,更新为刚才被访问的那个磁道
}
}
else//如果磁头是向磁道号减少的方向移动
{
a[flag]==ans ? i=flag : i=flag-1;//判断a[flag]是否等于ans,如果等于i就等于flag,否则i=flag-1。该步判断的意义在于如果a[flag]刚好等于ans的话就从a[flag]开始遍历,否则就代表a[flag-1]是第一个比ans小的磁道,那么就从a[flag-1]开始遍历
for(; i>=0; i--)//道理和上一个差不多
{
printf("%d\t\t\t%d\n",a[i],abs(a[i]-m));//输出被访问的下一个磁道号和移动距离(abs绝对值函数,可以直接给出距离)
m=a[i];//更新当前磁道号,更新为刚才被访问的那个磁道
}
for(i=n-1; a[flag]==ans ? i>flag : i>=flag; i--) //从最大的磁道开始遍历
{
printf("%d\t\t\t%d\n",a[i],abs(a[i]-m));//输出被访问的下一个磁道号和移动距离(abs绝对值函数,可以直接给出距离)
m=a[i];//更新当前磁道号,更新为刚才被访问的那个磁道
}
}
return 0;
}
输入样例1:
7
55 58 39 18 90 160 150
100
1
输出样例1:
被访问的下一个磁道号 移动距离(磁道数)
150 50
160 10
18 142
39 21
55 16
58 3
90 32
输入样例2:
7
55 58 39 18 90 160 150
90
0
输出样例2:
被访问的下一个磁道号 移动距离(磁道数)
90 0
58 32
55 3
39 16
18 21
160 142
150 10
算法或原理的实现思想:
算法:
算法就是磁盘调度算法,我选择的是SSTF调度算法和CSCAN调度算法。
SSTF算法(最短寻道时间优先):就是先选择一个离当前磁道最近的磁道访问,然后以此类推,我感觉就是递归思想,写一个函数,然后所有过程都是一样的,即上一个磁道和下一个磁道的关系,然后一直递归。
CSCAN算法(循环扫描):就是从当前磁道开始,有两种选择,1.磁头向磁道号增加的方向移动 2.磁头向磁道号减少的方向移动,具体过程就是模拟,但是其中我发现一个坑,这个后面在后面遇到的问题里再说。
遇到的问题:
SSTF算法:
第一个算法还好,复习了一下这个过程,然后一遍就敲出来了,和教材上的一模一样(就是我们自己印的那个教材),但是在加注释完注释的时候出现问题了,我找了好一会,又是debug又是单步调试,但是都找不出来错误,最后我发现是我递归的边界没写好。例如,在这个算法中,如果所有的磁道都访问完之后,我原本写的程序没有跳出递归这一步操作,所以程序会输出一些垃圾数,甚至有的时候会导致程序崩溃,最后我加上跳出的那一步操作后就没问题,这里可以参考一下我的原代码,即没有加注释和改错之前的代码(代码查看地址:https://blog.csdn.net/qq_34035720/article/details/110494677 里面我详细写了每个代码的更改过程 包括原代码和注释更改后的最终代码)
CSCAN算法:
这个算法我感觉就更简单了,就是单纯的模拟这个过程,从大到小和从小到大,4个for循环就ok了,但是正如我上面说的那样,我发现一个坑,这个坑是在从大到小的过程中,同时当前磁道号就等于访盘序列中某一个磁盘号时,会出现错误,原因是我用flag标记第一个大于等于当前磁道号的时候,因为是大于等于,所以可能会出现等于的情况,这样我从大到小跑的时候会忽略掉那个等于的部分,具体可以看我博客里写的原代码和最终代码的比较(网址在上面提到过),测试数据的话就是这个算法的样例2,如果用我的原代码和最终版代码跑一遍的话就会发现,两种代码输出的结果不一样,显然最终版是对的,所以我做了改动,里面用了三目运算符,感觉还挺好用的。
参考文献:
山东理工大学19级计科(中外)操作系统教材———复印ppt版
没有参考网络和其他同学
感想、体会和收获:
和上次的银行家算法一样,在敲代码之前从教材上复习了一下磁盘调度算法的整个过程,在熟知了所有磁盘调度算法的方法后我才开始敲代码,然后敲代码的过程总的来说还是挺顺利的,虽然中间出了一些小差错,但是最后都能改正过来。这个过程不仅让我学习了操作系统的相关知识,也让我提高了敲代码的能力,个人还是挺喜欢大作业的这种形式。