磁盘调度算法的模拟

使用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
在这里插入图片描述


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

扫描二维码关注公众号,回复: 14653904 查看本文章

--over

猜你喜欢

转载自blog.csdn.net/EX_fish/article/details/124904085
今日推荐