磁盘调度算法的模拟

使用C语言完成磁盘调度算法中的 最短寻道时间优先调度算法 和 电梯调度算法 !
假设进程请求的访问磁盘的磁道序列号为:100 55 58 39 18 90 160 150 38 184
请输出采用不同算法时访问的磁道号,并计算平均寻道长度。

挑了两个相对简单的磁盘调度算法, 模拟可解, 不考虑时间复杂度的情况下都可以暴力搜索.
(天天都在写暴力, 只会暴力了QAQ.
借这个实验作业来书写一下磁盘的两个调度算法 – 最短寻道时间优先调度算法 ( S S T F ) (SSTF) (SSTF)和电梯调度算法 ( S C A N ) (SCAN) (SCAN).
平均寻道长度: 总共走的磁道数 / 更改磁道的次数.
平均寻道时间: 平均寻道长度 * 移动每道的单位时间


一. 最短寻道时间优先调度 ( S S T F ) (SSTF) (SSTF)
 怎么个实现过程? 从最开始的磁道开始时, 每次都寻找到离当前位置最近的磁道. (你没有看错, 就是这么简单. 过程可结合输出来理解. 那么直接贴上代码.
在这里插入图片描述

#include<bits/stdc++.h>
#define getpch(type) (type*)malloc(sizeof(type))
using namespace std;
struct _list{ //构造能够双向遍历的链表结构体
    struct _list* left;
    int val;
    struct _list* right;
};
struct _list* ide; //确定“头”指针
int cnt, first;
double run; //步长记录
vector<int>nums; //存储磁道号
void _input(){ //输入
    cin >> first;
    vector<int>vec(1, first);
    while(cin >> cnt) vec.emplace_back(cnt);
    nums = vec; //vec可删除
}
void left_work(){
    ide = ide->left;
    //输出操作
    cout << setw(14) << ide->val;
    cout << "           ";
    cout << setw(8) << ide->right->val-ide->val << endl;
    run += ide->right->val-ide->val;

    //删除节点(如果从节点A离开,那么A节点被删除
    struct _list* p = ide->right;
    if(ide->right->right) ide->right->right->left = ide;
    ide->right = ide->right->right;
    free(p); //释放指针空间
}
void right_work(){
    ide = ide->right;
    //输出操作
    cout << setw(14) << ide->val;
    cout << "           ";
    cout << setw(8) << ide->val-ide->left->val << endl;
    run += ide->val-ide->left->val;

    //删除节点(如果从节点A离开,那么A节点被删除
    struct _list* p = ide->left;
    if(ide->left->left) ide->left->left->right = ide;
    ide->left = ide->left->left;
    free(p); //释放指针空间
}
// void debug(){
//     struct _list* head = ide;
//     while(head->left) head=head->left;
//     while(head) {cout << head->val << ' '; head=head->right;}
//     cout << endl;
// }
void Print(){
    int n = nums.size() - 1;
    cout << "start: " << ide->val << endl;
    cout << "the next place           len nums" << endl;
    while(ide->left || ide->right){ //因为当左右都不具有节点时,我们没法离开,所以会“死”,那么我提前结束就好了,反正也遍历完成了
        int cnt = ide->val;
        //寻找left和right近的那个, 并基于相应的操作
        if(!ide->left && ide->right) right_work(); //如果没有更小的了
        else if(!ide->right && ide->left) left_work(); //如果没有更大了了
        else if(ide->right && ide->left) cnt-ide->left->val < ide->right->val-cnt?left_work():right_work(); //存在小的节点并且存在大的节点
        // debug();
    }
    cout << setiosflags(ios::fixed) << setprecision(1) << "平均寻道时间: " << run / (nums.size()-1) << endl;
}
void _work(){
    sort(nums.begin(), nums.end());
    struct _list* l = NULL;
    // for(auto ao : nums) cout << ao << " ";
    for(auto ao : nums){
        struct _list* _list_ = getpch(struct _list);
        if(ao == first) ide = _list_; //标记head节点
        _list_->val = ao; //赋值

        //链表的建立, 左右索引指针的赋值(能够双向遍历的链表
        if(l) l->right = _list_;
        _list_->left = l;
        l = _list_;
    }l->right = NULL;

    // debug();
    Print();
}
signed main(void){ //这样书写的优点,时间复杂度小nlog(n), 用桶排可压缩到n
    freopen("in.txt","r",stdin); //100 55 58 39 18 90 160 150 38 184
    freopen("SSTFout.txt","w",stdout);
 
    _input();
    _work();
    return 0;
}

 这里使用的是建立一个从小到大排好顺序的 可以双向的寻址的链表. 然后每一次更改位置都删除上一个节点. 这样每次寻找都只需要比较 l e f t left left r i g h t right right 的大小就好了. 这样写主要为了降低时间复杂度.

 你也可以不对读取的数据进行处理, 而是每次都寻找未被索引的离当前位置最近的磁道(从头到尾查找). 但是这样就会造成极高的时间复杂度. (这样书写很简单, 你也不需要建立链表, 只需要一个数组就可以了. 如果你不在乎时间复杂度建议就暴力查询. 主体的代码片段如下:

bool bo[100]; //标记是否被索引过
int nums[100]; //记录需要索引的磁道号
int first; //第一个磁道
int ide; //标记下一个索引的位置, 初始等于first的下标
int sum = 0; //标记索引过的个数
while(sum < n){ //n表示需要索引的总的磁道个数
	int cnt = INT_MAX, ans;
	for(int i = 0;i < n;i ++){ //每次都暴力寻找离当前位置最近的磁道
		if(cnt < abs(nums[i] - nums[ide]) && bo[i]){
			cnt = abs(nums[i] - nums[ide]), ans = i;
		}
	}
	//nums[ans]
	bo[ans] = true, ide = ans;
}

给出第一个使用双向链表遍历得到的结果:

start: 100
the next place           len nums
            90                 10
            58                 32
            55                  3
            39                 16
            38                  1
            18                 20
           150                132
           160                 10
           184                 24
平均寻道时间: 27.6

 最短寻道时间优先调度算法本身存在的问题: 因为我的示例都是给好了需要访问的磁道, 而未进行后续添加. 实际过程中, 我们需要访问的磁道都是一个动态的过程. 假若我们每次到达指定的磁道后, 又在附近的磁道发出了请求, 那么远的磁道就可能一直存在不访问的情况. 也就是"饥饿"现象.


二. 电梯调度算法 ( S C A N ) (SCAN) (SCAN)
 使用电梯调度算法,我们必须在最开始就给定一个向外还是向里寻找的优先级. 然后在这个优先级的作用下, 寻找离当前磁盘号最近的磁盘号. (优先级优于大小, 当外道优先级大于内道时, 那么我们需要先全部索引完 f i r s t first first 的外道磁盘号, 再索引 f i r s t first first 的内道磁盘号.
代码演示:
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
char trend;
int first, cnt, ans, far;
double run;
vector<int>nums;
void _input(){
    trend = getchar();
    cin >> first; nums.emplace_back(first);
    while(cin >> cnt) nums.emplace_back(cnt);
}
void Print(){
    if(trend == '+') far = 1;
    else far = -1;
    cout << "start: " << nums[ans] << endl;
    cout << "the next place           len nums" << endl;
    int ide = ans + far;
    while(ide < nums.size() && ide >= 0){
        cout << setw(14) << nums[ide];
        cout << "           ";
        cout << setw(8) << abs(nums[ide] - nums[ide - far]) << endl;
        run += abs(nums[ide] - nums[ide - far]);
        ide += far;
    }
    int c = abs(nums[ide - far] - nums[ans]);
    far = -far, ide = ans + far;
    while(ide < nums.size() && ide >= 0){
        cout << setw(14) << nums[ide];
        cout << "           ";
        cout << setw(8) << abs(nums[ide] - nums[ide - far]) << endl;
        run += abs(nums[ide] - nums[ide - far]);
        ide += far;
    }
    cout << setiosflags(ios::fixed) << setprecision(1) << "平均寻道时间: " << (run + c) / (nums.size() - 1) << endl;
}
void _work(){ //排序后,只需要判断一次距离就行
    sort(nums.begin() , nums.end());
    ans = find(nums.begin() , nums.end() , first) - nums.begin();
    Print();
}
signed main(void){
    freopen("in.txt","r",stdin); //+ 100 55 58 39 18 90 160 150 38 184
    freopen("SCANout.txt","w",stdout);

    _input();
    _work();
    return 0;
}

 实际上我们只需要对输入数据排序, 然后分别遍历 f i r s t first first 所在位置的左边或者右边即可. (具体先遍历左边还是右边, 看给定的优先级.
 数据输入中的 ‘ + + +’ 表示先向外道寻找, 而 ‘ − - ’ 理所当然先向里道寻找.
这个算法很简单, 也不需要绕弯子.
结果演示如下:

start: 100
the next place           len nums
           150                 50
           160                 10
           184                 24
            90                 10
            58                 32
            55                  3
            39                 16
            38                  1
            18                 20
平均寻道时间: 27.8

三. CSCAN
在这里插入图片描述


快期末考试了, 还没开始预习, 这种东西真的会考吗 눈_눈

--over

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
磁盘调度算法是操作系统中磁盘I/O的重要部分,常用的磁盘调度算法有FCFS、SSTF、SCAN、C-SCAN等。在C语言中实现磁盘调度算法的主要步骤如下: 1. 定义磁盘请求队列结构体,包括请求序号、磁道号、请求处理时间等信息。 ```c typedef struct { int req_no; // 请求序号 int track_no; // 磁道号 int service_time; // 请求处理时间 } request_queue; ``` 2. 实现各种磁盘调度算法的处理函数。以SCAN算法为例: ```c void scan(request_queue *queue, int size, int start_track) { int direction = 1; // 扫描方向,1表示向外扫描,0表示向内扫描 int current_track = start_track; // 当前磁道号 int total_time = 0; // 总处理时间 // 对请求队列按磁道号进行排序 sort_by_track(queue, size); // 扫描磁道 while (size > 0) { int next_track = -1; // 下一个请求的磁道号 int next_index = -1; // 下一个请求在队列中的下标 // 找到距离当前磁道最近的请求 for (int i = 0; i < size; i++) { if (queue[i].track_no == current_track) { next_track = current_track; next_index = i; break; } else if (queue[i].track_no > current_track && direction == 1) { next_track = queue[i].track_no; next_index = i; break; } else if (queue[i].track_no < current_track && direction == 0) { next_track = queue[i].track_no; next_index = i; break; } } // 如果找到了下一个请求,将其从队列中删除并计算处理时间 if (next_index != -1) { total_time += queue[next_index].service_time; current_track = next_track; for (int i = next_index; i < size - 1; i++) { queue[i] = queue[i + 1]; } size--; } else { // 如果未找到下一个请求,改变扫描方向并重新扫描 direction = 1 - direction; } } printf("SCAN算法总处理时间为%d\n", total_time); } ``` 3. 编写主函数,创建请求队列并调用磁盘调度算法处理函数。 ```c int main() { request_queue queue[] = { {1, 10, 6}, {2, 22, 3}, {3, 5, 4}, {4, 8, 5}, {5, 12, 2}, {6, 17, 7}, {7, 25, 8} }; int size = sizeof(queue) / sizeof(request_queue); int start_track = 15; scan(queue, size, start_track); return 0; } ``` 以上代码仅供参考,具体实现方式可以根据不同的磁盘调度算法进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值