1.算法解析
扫描算法(SCAN)又称电梯调度算法,SCAN算法是磁头前进方向上的最短查找时间优先算法,它排除了磁头在盘面局部位置上的往复移动,SCAN算法在很大程度上消除了SSTF算法的不公平性,但仍有利于对中间磁道的请求。电梯调度算法是从移动臂当前位置开始沿着臂的移动方向去选择离当前移动臂最近的那个柱访问者,如果沿臂的移动方向无请求访问时,就改变臂的移动方向再选择。
这个算法好比乘电梯,如果电梯已向上运动到4层时,依次有3位乘客陈生、伍生、张生在等候乘电梯。他们的要求是:陈生在2层等待去10层;伍生在5层等待去底层;张生在8层等待15层。由于电梯目前运动方向是向上,所以电梯的形成是先把乘客张生从8层带到15层,然后电梯换成下行方向,把乘客伍生从5层带到底层,电梯最后再调换方向,把乘客陈生从2层送到10层。
由于磁盘移动臂的初始方向有两个,而该算法是与移动臂方向有关,所以分成两种情况来讨论。
现有需要读取的数据的柱面次序为:35 12 73 230 80 20 310 120,初始柱面为65号。
(1)移动臂向外移动:当65操作结束后,应该先处理35号柱面的请求,然后到达20号柱面执行操作,随后处理12号柱面请求,后继操作的次序应该是73、80、120、230、310。
(2)移动臂向内移动:当65操作结束后,应该先处理73号柱面的请求,然后到达80号柱面执行操作,随后处理120号柱面请求,后继操作的次序应该是230、310、35、20、12。
2.代码
①电梯调度算法函数SCAN()
int SCAN(int *cyclist, int *cycorder, int n, int start, int dir){
//参数:cyclist[] 输入的待操作的柱面数组,cycorder[] 操作柱面的顺序结果
// n 柱面的个数,start 初始的柱面号, dir 移动臂方向(0外越小,1内越大)
//返回值:sum SCAN的走道总和int sum, min, mid, index, tag[100] = {0};sum = 0;for(int j=0; j<n; j++){ //此循环得出cycorder[]和累加summin = 9999; //将最小值初始化为无穷大for(int i=0; i<n; i++){ //次循环得出距离start最小值minif(dir == 1 && cyclist[i] > start && tag[i] == 0){ //判断是否时向内运动mid = cyclist[i] - start;if(mid < min){min = mid;index = i; //记录下与start最近柱面的下标}}else if(dir == 0 && cyclist[i] < start && tag[i] == 0){ //判断是否时向内运动mid = abs(cyclist[i] - start);if(mid <min){min = mid;index = i; //记录下与start最近柱面的下标}}}if(dir && Max(cyclist, n, cyclist[index])) //判断此时进行操作的柱面是否为此方向最大dir = 0;else if(Min(cyclist, n, cyclist[index])) //判断此时进行操作的柱面是否为此方向最小dir = 1;sum += min;tag[index] = 1; //将标记数组置为1,表示已经将其柱面进行操作cycorder[j] = cyclist[index];start = cyclist[index];}return sum;
}
②操作柱面大小判断函数Max()、Min()
//参数:cyclist[] 待操作的柱面数组,n 柱面的个数,num 此时操作柱面号
//返回值:返回0或1用于判断
int Max(int *cyclist, int n, int num){for(int i=0; i<n; i++)if(cyclist[i] > num)return 0;return 1;
}int Min(int *cyclist, int n, int num){for(int i=0; i<n; i++)if(cyclist[i] < num)return 0;return 1;
}
③全部代码
#include<iostream>
#include<cmath>
using namespace std;int Max(int *cyclist, int n, int num){for(int i=0; i<n; i++)if(cyclist[i] > num)return 0;return 1;
}
int Min(int *cyclist, int n, int num){for(int i=0; i<n; i++)if(cyclist[i] < num)return 0;return 1;
}
//0外越小,1内越大
int SCAN(int *cyclist, int *cycorder, int n, int start, int dir){int sum, min, mid, index, tag[100] = {0};sum = 0;for(int j=0; j<n; j++){min = 9999;for(int i=0; i<n; i++){if(dir == 1 && cyclist[i] > start && tag[i] == 0){mid = cyclist[i] - start;if(mid < min){min = mid;index = i;}}else if(dir == 0 && cyclist[i] < start && tag[i] == 0){mid = abs(cyclist[i] - start);if(mid <min){min = mid;index = i;}}}if(dir && Max(cyclist, n, cyclist[index]))dir = 0;else if(Min(cyclist, n, cyclist[index]))dir = 1;sum += min;tag[index] = 1;cycorder[j] = cyclist[index];start = cyclist[index];}return sum;
}
int main(){int cyclist[100], cycorder[100], n, start, dir;cout<<"请输入磁臂初始移动方向(1向内,0向外):";cin>>dir;cout<<"请输入初始柱面和待执行柱面数量:";cin>>start>>n;cout<<"请输入待执行柱面:";for(int i=0; i<n; i++)cin>>cyclist[i];cout<<"磁头走过总道数为:"<<SCAN(cyclist, cycorder, n, start, dir)<<endl;cout<<"SCAN走道顺序为:";for(int i=0; i<n; i++){cout<<cycorder[i];if(i+1 != n)cout<<" -> "; }return 0;
}
/*
1
65 8
35 12 73 230 80 20 310 120
*/
3.运行结果
(1)移动臂向内:
(2)移动臂向外: