📍代码(FCFS、SSTF、SCAN)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>
#define inf 0x3f3f3f3f
int N; //磁道个数
int start; //磁头的初始位置
int *distVisitSeq; //访问磁道序列
void init(); //随机初始化测试数据
void FCFS(); //先来先服务算法(FCFS)
void SSTF(); //最短寻道时间优先算法(SSTF)
void SCAN(); //扫描算法(SCAN)
int cmp(const void *a, const void *b); //自定义快排qsort的规则
int main(){
init(); //初始化测试数据
printf("***先来先服务算法(FCFS)***\n");
FCFS();
printf("***最短寻道时间优先算法(SSTF)***\n");
SSTF();
printf("***扫描算法(SCAN)***\n");
SCAN();
free(distVisitSeq); //释放malloc申请的资源
}
void init(){
//从page_data.txt读入数据
FILE* fp = fopen("disk_data.txt", "r");
if (fp == NULL) {
printf("Failed to open file %s\n", "page_data.txt");
}
fscanf(fp,"%d",&start);
fscanf(fp,"%d",&N);
distVisitSeq = malloc(sizeof(int) * N); //请求访问磁道序列
int i;
for(i=0;i<N;i++){
fscanf(fp,"%d",&distVisitSeq[i]);
}
fclose(fp);
printf("初始化%d个磁道,序列为:",N);
for(i=0;i<N;i++)
printf("%d ",distVisitSeq[i]);
printf("\n磁头的位置位于:%d\n",start);
}
void FCFS(){
int steps=0,i;
steps = abs(distVisitSeq[0]-start);
for(i=0;i<N-1;i++)
steps+=abs(distVisitSeq[i+1]-distVisitSeq[i]);
//输出移动轨迹和磁道数
printf("移动轨迹:%d",start);
for(i=0;i<N;i++) printf("-> %d ",distVisitSeq[i]);
printf("\n移动%d个磁道\n\n",steps);
}
void SSTF(){
int steps=0,move=start,i,j,flag;
int *record = malloc(sizeof(int) * N); //记录是否已服务
for(i=0;i<N;i++) record[i]=0; //初始化
printf("移动轨迹:%d",start);
for(j=0;j<N;j++){
//贪心:每次选出距离最短的
int minStep=inf;
for(i=0;i<N;i++){
if(record[i]==0)
if(minStep>abs(distVisitSeq[i]-move)){
minStep = abs(distVisitSeq[i]-move);
flag = i;
}
}
steps+=minStep;
record[flag]=1;
move= distVisitSeq[flag];
printf("-> %d ",move);
}
printf("\n移动%d个磁道\n\n",steps);
}
void SCAN(){
int i,flag,temp,steps;
qsort(distVisitSeq,N,sizeof(int),cmp); //升序排序
//找到第一个大于start位置的磁盘号下标
for(i=0;i<N;i++)
if(distVisitSeq[i]>start){
flag=i;
break;
}
//***初始往左边走***
printf("(初始向左)\n");
printf("移动轨迹:%d",start);
for(i=0;i<(flag/2);i++) //往小的走,将小的翻转
{
temp =distVisitSeq[flag-1-i];
distVisitSeq[flag-1-i] = distVisitSeq[i];
distVisitSeq[i] = temp;
}
//输出轨迹
for(i=0;i<N;i++) //正序输出
printf("-> %d ",distVisitSeq[i]);
//计算移动磁道数
steps = abs(distVisitSeq[0]-start);
for(i=0;i<N-1;i++)
steps+=abs(distVisitSeq[i+1]-distVisitSeq[i]);
printf("\n移动%d个磁道\n",steps);
//***初始往右边走***
printf("(初始向右)\n");
printf("移动轨迹:%d",start);
for(i=flag;i<(flag+(N-flag)/2);i++) //往大的走,将大的翻转
{
temp =distVisitSeq[N-i+flag-1];
distVisitSeq[N-i+flag-1] = distVisitSeq[i];
distVisitSeq[i] = temp;
}
//输出轨迹
for(i=N-1;i>=0;i--)
printf("-> %d ",distVisitSeq[i]); //逆序输出
//计算移动磁道数
steps = abs(distVisitSeq[N-1]-start);
for(i=N-1;i>0;i--)
steps+=abs(distVisitSeq[i-1]-distVisitSeq[i]);
printf("\n移动%d个磁道\n\n",steps);
}
int cmp(const void *a, const void *b){
return *(int *)a - *(int *)b;//升序
}
📍代码中所用数据disk_data.txt
53
8
98 183 37 122 14 124 65 67
📍实验分析
从实验结果来看,对于data_disk.txt这组数据,效率上:SSTF>SCAN>FCFS。
1.对于FCFS:
它不考虑磁道远近,只考虑服务顺序,因此在大多数情况下,基本是移动最多的。考虑它的时间复杂度,来一个处理一个,因此是O(n),但是对物理硬件是个巨大的考验,需要移动的磁道数目过多。
2.对于SSTF:
采用经典的贪心思想,试图每次寻找局部最优,以达到接近全局最优的目的,大多数情况下,从当前位置寻找距离当前位置最短的磁道,所以大多情况下基本上移动是最少的。考虑它的时间复杂度,该算法主要花费在确定最短移动的目标磁道过程中,需要遍历n次,有点类似于上述银行家算法的暴力回溯逻辑,所耗时间为n*(n+1)/2,因此对于n个磁道,其总时间复杂度应该为O(n*n)。另外,该算法还有个缺点就是太远的磁道可能因为长期不能获得服务而导致饥饿。
3.对于SCAN:
又称电梯法,先扫完一边,再扫另一边,从这个实验结果看到,若初始从左移动(规定升序,则先扫磁道号较小的一边),只需移动208个磁道,而若初始向右移动,则需要移动322个磁道。因此可以得出结论,在升序磁道号情况下,若初始位置刚好靠近某一侧,则总移动磁道数会比较小。考虑其时间复杂度,该算法主要花费在排序中,我使用的是快速排序,那么时间复杂度为O(n*logn),只要用排序确定好序列位置,效率会很快,并且符合请求队列具有动态性,解决了以上算法的弊端。