问题描述:
设计程序模拟先来先服务FCFS,最短寻道时间优先SSTF,SCAN和循环SCAN算法的工作过程。假设有n个磁道号所组成的磁道访问序列,给定开始磁道号m和磁头移动的方向(正向或者反向),分别利用不同的磁盘调度算法访问磁道序列,给出每一次访问的磁头移动距离,计算每种算法的平均寻道长度。
程序要求如下:
1)利用先来先服务FCFS,最短寻道时间优先SSTF,SCAN和循环SCAN算法模拟磁道访问过程。
2)模拟四种算法的磁道访问过程,给出每个磁道访问的磁头移动距离。
3)输入:磁道个数n和磁道访问序列,开始磁道号m和磁头移动方向(对SCAN和循环SCAN算法有效),算法选择1-FCFS,2-SSTF,3-SCAN,4-循环SCAN。
4)输出:每种算法的平均寻道长度。
例题:当前磁头停在100号磁道,有15个磁道请求先后到达,依次为64,117, 305,72,166,288,193,11,102,219,95,321,35,146,188,计算FCFS,SSTF,SCAN(向里), CSCAN(向外),这四种算法的平均寻道长度。
package HomeWork_OS.DiskSchedulingAlgorithm;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class disk_Algorithm {
static int totleDistance = 0; //总移动磁道数
static int totleDisk = 0; //总磁盘数
//平均寻道长度
public static void avgSeekTime(int totleDistance, int totleDisk) {
double avgSeekTime = (double) totleDistance / totleDisk;//平均寻道时间
System.out.println("平均寻道长度: " + String.format("%.4f", avgSeekTime) + "\n");
}
/*先来先服务FCFS*/
public static void FCFS(int[] arr, int head) {//磁道抵达数组,当前停留磁头号
totleDisk = arr.length;//获得总磁盘数
totleDistance = 0;//清空总磁道移动距离
//新建一个二维数组存访问的磁道号和移动距离
int[][] resultArr = new int[arr.length][2];
//设置一个存储当前磁头号的标识
int diskNo = head;
//遍历磁道抵达数组
for (int i = 0; i < arr.length; i++) {
resultArr[i][0] = arr[i];
resultArr[i][1] = (int) Math.abs(arr[i] - diskNo);
diskNo = resultArr[i][0];
}
System.out.println("访问磁道号" + "\t\t移动距离<磁道数>");
for (int i = 0; i < resultArr.length; i++) {
System.out.println(resultArr[i][0] + "\t\t\t\t" + resultArr[i][1]);
totleDistance += resultArr[i][1];
}
avgSeekTime(totleDistance, totleDisk);
}
/*最短寻道时间优先SSTF*/
public static void SSTF(int[] arr, int head) {
totleDisk = arr.length;//获得总磁盘数
totleDistance = 0;//清空总磁道移动距离
//新建一个链表用来存储磁道号的数组
List diskList = new LinkedList();
//将磁道号数组,存入链表
for (int i : arr) {
diskList.add(i);
}
// System.out.println(diskList);
System.out.println("访问磁道号" + "\t\t移动距离<磁道数>");
for (int i = 0; i < arr.length; i++) {
//最小移动距离,初始为当前磁头号到链表中第一个元素的绝对值
int minDistance = Math.abs(head - (int) diskList.get(0));
//最小移动距离的磁道号,初始值为链表中第一个元素
int minDiskNo = (int) diskList.get(0);
//链表中最小移动距离磁道号索引
int removeIndex = 0;
//遍历链表,找出离当前磁头最近的磁道号
for (int size = diskList.size(), j = 0; j < size; j++) {
if (minDistance > (int) Math.abs(head - (int) diskList.get(j))) {
minDistance = (int) Math.abs(head - (int) diskList.get(j));
minDiskNo = (int) diskList.get(j);
removeIndex = j;
}
}
totleDistance += minDistance;
//将头节点设为目前最小运动距离磁道号->头节点移动到当前最小移动距离磁道号
head = minDiskNo;
//从链表中移除最小移动距离的磁道号
diskList.remove(removeIndex);
System.out.println(minDiskNo + "\t\t\t\t" + minDistance);
// System.out.println(diskList);
}
avgSeekTime(totleDistance, totleDisk);
}
/*扫描SCAN算法*/
public static void SCAN(int[] arr, int head, boolean flag) { //flag传入方向 true->1外向 false->0里向(向外为磁道号增大的方向移动)
/* System.out.println("===============");
System.out.println("head: " + head);
System.out.println("flag: " + flag);*/
totleDisk = arr.length;//获得总磁盘数
totleDistance = 0;//清空总磁道移动距离
//新建一个链表用来存储磁道号的数组
List diskList = new LinkedList();
for (int i : arr) {
diskList.add(i);
}
//给链表排序(从小到大排序)
Collections.sort(diskList);
System.out.println(diskList);
//链表中最小移动距离磁道号索引
int index = 0;
//遍历链表
for (int size = diskList.size(), j = 0; j < size; j++) {
//根据需要寻道的方向,找到离当前磁道号最近的磁道
if ((int) diskList.get(j) == head) {
index = j;
break;//结束循环
} else if ((int) diskList.get(j) >= head) { //找出head右侧最近的磁道号
index = j;
break;
}else if(j == size -1){
index = j;
break;
}
}
//移动距离,初始为当前磁头号到链表中第一个元素的绝对值
int distance;
int size = diskList.size();
System.out.println("访问磁道号" + "\t\t移动距离<磁道数>");
if (flag) {
for (int j = 0; j < size - index; j++) {
distance = Math.abs(head - (int)diskList.get(index + j));
totleDistance += distance;
head = (int)diskList.get(index + j);
System.out.println((int) diskList.get(index + j) + "\t\t\t\t" + distance);
}
for (int j = index - 1; j >= 0; j--) {
distance = Math.abs(head - (int)diskList.get(j));
totleDistance += distance;
head = (int)diskList.get(j);
System.out.println((int) diskList.get(j) + "\t\t\t\t" + distance);
}
} else {
//当当前磁头号恰好在要扫描的磁道上时,或着当前磁头号大于要扫描的所有磁道号
if ((int)diskList.get(index) == head || index == diskList.size() - 1){
System.out.println("index: " + index);
for (int j = index; j >= 0; j--) {
distance = Math.abs(head - (int)diskList.get(j));
totleDistance += distance;
head = (int)diskList.get(j);
System.out.println((int) diskList.get(j) + "\t\t\t\t" + distance);
}
for (int j = 1; j < size - index; j++) {
distance = Math.abs(head - (int)diskList.get(index + j));
totleDistance += distance;
head = (int)diskList.get(index + j);
System.out.println((int) diskList.get(index + j) + "\t\t\t\t" + distance);
}
} else {
System.out.println("index: " + index);
for (int j = index - 1; j >= 0; j--) {
distance = Math.abs(head - (int)diskList.get(j));
totleDistance += distance;
head = (int)diskList.get(j);
System.out.println((int) diskList.get(j) + "\t\t\t\t" + distance);
}
for (int j = 0; j < size - index ; j++) {
distance = Math.abs(head - (int)diskList.get(index + j));
totleDistance += distance;
head = (int)diskList.get(index + j);
System.out.println((int) diskList.get(index + j) + "\t\t\t\t" + distance);
}
}
}
avgSeekTime(totleDistance,totleDisk);
}
/*循环扫描CSCAN*/
public static void CSCAN(int[] arr, int head, boolean flag) { //flag传入方向 true->1向外 false->0向里
/* System.out.println("===============");
System.out.println("head: " + head);
System.out.println("flag: " + flag);*/
totleDisk = arr.length;//获得总磁盘数
totleDistance = 0;//清空总磁道移动距离
//新建一个链表用来存储磁道号的数组
List diskList = new LinkedList();
for (int i : arr) {
diskList.add(i);
}
//给链表排序(从小到大排序)
Collections.sort(diskList);
System.out.println(diskList);
//链表中最小移动距离磁道号索引
int index = 0;
//遍历链表
for (int size = diskList.size(), j = 0; j < size; j++) {
//根据需要寻道的方向,找到离当前磁道号最近的磁道
if ((int) diskList.get(j) == head) {
index = j;
break;//结束循环
} else if ((int) diskList.get(j) >= head) { //找出head右侧最近的磁道号
index = j;
break;
}else if(j == size -1){
index = j;
break;
}
}
//移动距离,初始为当前磁头号到链表中第一个元素的绝对值
int distance;
int size = diskList.size();
// System.out.println("index: " + index);
System.out.println("访问磁道号" + "\t\t移动距离<磁道数>");
if (flag) {
if ((int) diskList.get(index) < head)
index = 0;
for (int j = 0; j < size - index; j++) {
distance = Math.abs(head - (int)diskList.get(index + j));
totleDistance += distance;
head = (int)diskList.get(index + j);
System.out.println((int) diskList.get(index + j) + "\t\t\t\t" + distance);
}
for (int j = 0; j < index; j++) {
distance = Math.abs(head - (int)diskList.get(j));
totleDistance += distance;
head = (int)diskList.get(j);
System.out.println((int) diskList.get(j) + "\t\t\t\t" + distance);
}
} else {
//当当前磁头号恰好在要扫描的磁道上时,或着当前磁头号大于要扫描的所有磁道号
if ((int) diskList.get(index) > head && index != 0)
index = index - 1;
// System.out.println("index: " + index);
for (int j = index; j >= 0; j--) {
distance = Math.abs(head - (int)diskList.get(j));
totleDistance += distance;
head = (int)diskList.get(j);
System.out.println((int) diskList.get(j) + "\t\t\t\t" + distance);
}
for (int j = size - 1; j > index ; j--) {
distance = Math.abs(head - (int)diskList.get(j));
totleDistance += distance;
head = (int)diskList.get(j);
System.out.println((int) diskList.get(j) + "\t\t\t\t" + distance);
}
}
avgSeekTime(totleDistance,totleDisk);
}
public static void main(String[] args) {
/*测试用例一
* 9
* 55 58 39 18 90 160 150 38 184
* 100
* */
/*测试用例二
* 15
* 64 117 305 72 166 288 193 11 102 219 95 321 35 146 188
* 100
* */
Scanner sc = new Scanner(System.in);
boolean flag = true;
System.out.print("请输入提出磁盘I/O申请的进程数: ");
int inputDiskNum = sc.nextInt(); //用户键盘输入进程数
int[] diskArr = new int[inputDiskNum];
System.out.print("请依次输入要访问的磁道号: ");
for (int i = 0; i < diskArr.length; i++) {
diskArr[i] = sc.nextInt();
}
System.out.print("请输入开始的磁道号: ");
int inputDiskHead = sc.nextInt();
int userOption;
boolean direction;
while (flag) {
System.out.print("请选择寻道方式: " +
"\n1——FCFS 2——SSTF 3——SCAN 4——CSCSN: ");
userOption = sc.nextInt();
switch (userOption) {
case 1:
FCFS(diskArr, inputDiskHead);
System.out.print("是否继续选择寻道算法? 1——是 0——否: ");
flag = sc.nextInt() > 0 ? true : false;
break;
case 2:
SSTF(diskArr, inputDiskHead);
System.out.print("是否继续选择寻道算法? 1——是 0——否: ");
flag = sc.nextInt() > 0 ? true : false;
break;
case 3:
System.out.print("请选择开始方向: 1——向外 0——向里: ");
direction = sc.nextInt() > 0 ? true : false;
SCAN(diskArr, inputDiskHead, true);
System.out.print("是否继续选择寻道算法? 1——是 0——否: ");
flag = sc.nextInt() > 0 ? true : false;
break;
case 4:
System.out.print("请选择开始方向: 1——向外 2——向里: ");
direction = ((sc.nextInt() > 0) ? true : false);
CSCAN(diskArr, inputDiskHead, true);
System.out.print("是否继续选择寻道算法? 1——是 0——否: ");
flag = sc.nextInt() > 0 ? true : false;
break;
default:
System.out.println("输入有误,请重新输入! ");
break;
}
System.out.println( flag ? "" : "成功退出程序!!");
}
// int[] diskArr = new int[]{64, 117, 305, 72, 166, 288, 193, 11, 102, 219, 95, 321, 35, 146, 188};
// FCFS(diskArr, 100);
// SSTF(diskArr, 100);
// SCAN(diskArr, 100, true);
// CSCAN(diskArr, 100, true);
/*测试用例*/
/* int[] testArr = new int[]{55, 58, 39, 18, 90, 160, 150, 38, 184};
FCFS(testArr, 100);
SSTF(testArr, 100);
SCAN(testArr, 100, true);
CSCAN(testArr, 100, true);
FCFS(testArr,100);
SSTF(testArr, 100);
SCAN(testArr,100,true);
SCAN(testArr,100,false);
SCAN(testArr,10,true);
SCAN(testArr,10,false);
SCAN(testArr,18,false);
SCAN(testArr,18,true);
SCAN(testArr,200,false);
SCAN(testArr,200,true);
SCAN(testArr,160,false);
SCAN(testArr,160,true);
CSCAN(testArr,10,true);
CSCAN(testArr,100,true);
CSCAN(testArr,160,true);
CSCAN(testArr,200,true);
CSCAN(testArr,10,false);
CSCAN(testArr,100,false);
CSCAN(testArr,160,false);
CSCAN(testArr,200,false);
CSCAN(testArr,19,false);*/
}
}
运行截图: