【操作系统】分区分配算法 (首次适应算法、最佳适应算法)(C语言实现)
(编码水平较菜,写博客也只是为了个人知识的总结和督促自己学习,如果有错误,希望可以指出)
今天测试,发现一点问题:
1.最佳插入算法:对于插入的时候忘记修改temp.next.front的指向
2.回收头节点的时候现在多了一种判断。判断头节点的下一个是否为空。对如果不为空而且后面的空闲的话,做出了处理。原来则没有这一情况。
3.首次适应算法在 第一个分区未分配,第二个分区已分配时没有改变 temp_next->front 的指向,所以导致了后续的一些小问题,已经修改。
1.动态分区分配算法:
为了实现动态分区分配,通常将系统中的空闲分区链接成一个链。所谓顺序查找是指依次搜索空闲分区链上的空闲分区,去寻找一个大小能满足要求的分区。 --------计算机操作系统(第四版)
2.动态分区算法主要包括四种:
(1).首次适应算法(first fit,FF):
要求,空闲分区链以地址递增的顺序链接。每次从链首开始,直到找到第一个能满足要求的空闲分区为止。
简单来说,就是,每次都从第一个开始顺序查找,找到一块区域可以满足要求的。
优点:优先利用内存中低址部分的空闲分区,从而保留了高址部分的大空闲区,这为以后到达的大作业分配大的内存空间创造了条件。
缺点:低址部分不断被划分,会留下许多难以利用的,很小的空闲分区,称为碎片。而每次查找又都是从低址部分开始的,这无疑又会增加查找可用空闲分区时的开销。
(2).循环首次适应算法(next fit,NF):
与FF算法区别就是,不是每次都从首次开始,而是从上次找到的空闲分区的下一个空闲分区开始。(第一次查找的话也是从首页开始)。
特点:能使内存中的空闲区分布得较均匀。
(3).最佳适应算法(best,BF):
将所有空闲分区按照空闲分区容量大小从小到大的顺序连接起来,形成一个空闲分区链。
即,每次都是找空间容量不但可以满足要求的空闲区,而且该空闲分区的容量还要最接近要求的容量大小。
优点:每次分配给文件的都是最合适该文件大小的分区。
缺点:内存中留下许多难以利用的小的空闲区(外碎片)。
(4).最坏适应算法(worst,WF):
与BF算法相反,WF算法是按照空闲分区容量从大到小的顺序连接起来的,而且每次找空闲分区的时候也是按照空闲分区容量最大的。
特点:尽可能的分配大的分区。
缺点:使得内存缺乏大分区,可能使得后续到来的大作业无法装入内存。
3.主要实现的是首次适应算法和最佳适应算法。
运行截图:
4.就不一一截图了,还没有发现什么问题。如果有人发现了,希望可以指正一下,不胜感激
5.代码
#include<stdio.h>
#include<stdlib.h>
typedef struct lei_item //表示空闲分区表中的表箱
{
int id; //假如 id 为-1,表示此分区时一个空闲分区。
int base; //指向分区的首地址
int size; //表示分区大小
int status; //表示此分区是否已经分配 0表示空闲 1表示已经分配
}Item;
typedef Item datatype;
typedef struct lei_list
{
datatype* node; //表示一个datatype类型的链表的结点
struct lei_list* front;
struct lei_list* next;
}List;
#define Max 640
int memory = Max; //定义可用内存空间为640
List init(){ //初始化一个链表;
List list;
list.node = (datatype *)malloc(sizeof(datatype));
list.node->base = 0;
list.node->id = -1; //-1表示是空闲分区
list.node->size = memory;
list.node->status = 0;
list.front = list.next = NULL;
return list;
}
datatype* input(){ //初始化打算申请的内存分区节点
datatype* item = (datatype *)malloc(sizeof(datatype));
printf("请输入作业号:");
scanf("%d",&item->id);
printf("请输入所需要的内存的大小:");
scanf("%d",&item->size);
item->status = 0;
return item;
}
void Momery_state(List *list){
List* temp = list;
printf("-----------------------------------\n");
printf("内存分配状况\n");
printf("-----------------------------------\n");
while (temp)
{
if(temp->node->status == 0 && temp->node->id == -1){
printf("分区号:FREE\n");
printf("起始地址:%d\n",temp->node->base);
printf("内存大小:%d\n",temp->node->size);
printf("分区状态:空闲\n");
}
else
{
printf("分区号:%d\t起始地址:%d\n",temp->node->id,temp->node->base);
printf("内存大小:%d\n",temp->node->size);
printf("分区状态:已分配\n");
}
printf("-----------------------------------\n");
temp = temp->next;
}
}
int First_fit(List *list){
datatype* item = input();
List* temp = list; //定义一个临时变量list* ,指向list
while (temp)
{
if(temp->node->status == 0 && temp->node->size > item->size){ //如果此前的分区未分配,,并且分区大小大于 请求分配的大小 那么此时就可以进行分配
List *front = temp->front; //存储当前未分配分区的 上一个分区地址
List *next = temp->next; //存储当前未分配分区的 下一个分区地址
int base = temp->node->base; //记录未分配当前分区的首地址
datatype* new_node = (datatype*)malloc(sizeof(datatype)); // 多余出来的部分要新建立一个分区
new_node->id = -1; //然后需要对这个新的分区进行一些信息的设置
new_node->size = temp->node->size - item->size; //新分区的大小 等于 还未分配的时的分区大小 - 请求分配的结点的大小
temp->node = item; //对请求分配的分区结点进行分配
temp->node->status = 1;
new_node->status = 0;
new_node->base = base + temp->node->size; //新建立分区的首地址是 请求分配的分区的首地址 + 请求分配的分区的大小
List* temp_next = (List*)malloc(sizeof(List)); //临时节点 (申请一个新的链表节点 表示下一个分区) 并且进行初始化
temp_next->node = new_node; //保存下一个的分区的信息
temp_next->front = temp_next->next = NULL;
if(front == NULL && next == NULL){ //如果 front和next节点都是空,表明它是第一次分配分区
temp->node->base = 0; //初始化首地址
temp->next = temp_next;
temp_next->front = temp;
}
if(front == NULL && next != NULL){ //在第一个分区中插入新的分区
temp->node->base = 0;
temp->node->status = 1;
temp_next->front = temp;
temp_next->next = temp->next;
temp->next = temp_next;
}
if(front != NULL){ //表明不是第一次分配节点,此时需要在中间插入下一个节点
temp->node->base = temp->front->node->base+temp->front->node->size; //初始化首地址
temp_next->next = temp->next; //保证新插入的节点会记录原先节点的下一个节点的首地址
temp_next->front = temp; // 首尾都需要保证
temp->next = temp_next; //最后让所申请的分区节点的下一个节点指向 我们刚刚建立的临时节点
}
return 1;
}
else if(temp->node->status == 0 && temp->node->size == item->size)
{
item->base = temp->front->node->base+temp->front->node->size; //新插入分区的首地址 等于上一个分区的 首地址+分区的大小
item->status = 1; //表示已经分配
temp->node = item;
return 1;
}
else{
temp = temp->next;
continue;
}
temp = temp->next;
}
return 0;
}
int Momory_recycle(List *list){
List* temp = list; //申请一个链表节点 指向list 的头节点
int number; //用于存放要释放的节点的分区号
printf("请输入需要回收的ID号:");
scanf("%d",&number);
while (temp)
{
if(temp->node->id == number) //首先找到 节点id = number 的节点,然后分四种情况讨论
{
// 一、 要回收的是第一个结点
if(temp->front == NULL){
temp->node->status = 0;
temp->node->id = -1;
if(temp->next == NULL){
temp->node->size = temp->node->size + temp->next->node->size;
temp->next = temp->next;
return 1;
}
if(temp->next->node->id == -1 && temp->next->node->status == 0){
List* next = temp->next;
// 此时来判断 temp->next 是否是系统的最后一个结点
// 此时只将当前节点 和下一个结点合并就可以了
//即 首地址不变, 分区状态 和 分区id进行变化
temp->node->size = temp->node->size + next->node->size;
temp->node->status = 0;
temp->node->id = -1;
temp->next = next->next;
if(next->next == NULL){
free(next);
return 1;
}
//如果不是最后一个结点的话就会多一个步骤
// 让 next->next->front 指向上一个结点
else
{
next->next->front = temp;
free(next);
return 1;
}
}
return 1;
}
//二、 前后都没有空闲的分区
//最简单, 直接改变 分区的 id 和 分区的状态就可以了。
// 如果回收第一个分区的话 必须要先进行处理,如果不先进行处理 ,判断 temp->front->node->id != -1 会报一个段错误。因为temp-》front 此时指向的是null
if(temp->front->node->id != -1 && temp->front->node->status != 0 && temp->next->node->id != -1 && temp->next->node->status != 0){
temp->node->status = 0;
temp->node->id = -1;
return 1;
}
//三、要回收的节点 前面和后面都是空闲的
// 将三个空闲区合并到一起,起始地址为前面的分区的起始地址, 大小为三个空闲区大小之和
//还需要做一个判断,如果
if(temp->front->node->id == -1 && temp->front->node->status == 0 && temp->next->node->id == -1 && temp->next->node->status == 0){
List* front = temp->front;
List* next = temp->next;
front->node->size = front->node->size + temp->node->size + next->node->size;
front->next = next->next;
if(next->next == NULL){
free(temp);
return 1;
}
//如果不是最后一个结点的话就会多一个步骤
// 让 next->next->front 指向上一个结点
else
{
next->next->front = front;
free(temp);
return 1;
}
return 1;
}
// 四、 要回收的节点 前面的节点是空闲的
//合并后的分区起始地址为前一个结点, 分区大小为前一个节点 与 当前节点之和。
if(temp->front->node->id == -1 && temp->front->node->status == 0){
List* front = temp->front;
front->next = temp->next;
temp->next->front = front;
front->node->size += temp->node->size;
free(temp);
return 1;
}
//五、 要回收的节点 后面的额节点是空闲的
//合并后的分区首地址为当前节点 , 分区大小为当前节点 与 当前节点的下一个结点大小之和。
// 这个需要多一个步骤, 改变分区的 id 和 分区的状态。
// 还要注意一点: 当要回收的空间是和 系统最后的空闲区相邻时 , temp->next->next 指向的是null;
if(temp->next->node->id == -1 && temp->next->node->status == 0){
List* next = temp->next;
// 此时来判断 temp->next 是否是系统的最后一个结点
// 此时只将当前节点 和下一个结点合并就可以了
//即 首地址不变, 分区状态 和 分区id进行变化
temp->node->size = temp->node->size + next->node->size;
temp->node->status = 0;
temp->node->id = -1;
temp->next = next->next;
if(next->next == NULL){
free(next);
return 1;
}
//如果不是最后一个结点的话就会多一个步骤
// 让 next->next->front 指向上一个结点
else
{
next->next->front = temp;
free(next);
return 1;
}
}
}
temp = temp->next;
}
return 0;
}
int Best_fit(List *list){
int min = 0; //记录 最小分区的结点的大小
int base_min = 0; //记录 最小节点的结点的起始地址
List* temp = list;
datatype* item = input(); // 要对 item 的 起始地址 和 分配状态进行初始化
while (temp)
{
//如果分区未分配 就要进行 比较操作, 并且记录差值 和 分区的id号
if(temp->node->status == 0 && temp->node->id == -1&& temp->node->size > item->size){
if(min == 0){ //加入min为0 表示还未找到一个可以分配的分区
min = temp->node->size;
base_min = temp->node->base;
}
else
{
if(temp->node->size < min){ // 找到一个之后,需要找出最小的分区 也就是它的 size最小。
min = temp->node->size;
base_min = temp->node->base;
}
}
}
if(temp->node->status == 0 && temp->node->id == -1 && temp->node->size == item->size){
int base = temp->node->base;
temp->node = item;
temp->node->status = 1;
temp->node->base = base;
return 1;
}
temp = temp->next;
}
//因为可能没有任何一个空间可以满足要求需要做一个判断处理
temp = list;
while (temp)
{
if(temp->node->base == base_min){
datatype* temp_node = (datatype*)malloc(sizeof(datatype)); //会有多余的空间多出来 所以需要在建立一个结点插入到链表中
temp_node->id = -1;
temp_node->status = 0;
temp_node->base = base_min + item->size;
temp_node->size = temp->node->size - item->size;
temp->node = item; //对item进行完整的初始化
temp->node->base = base_min;
temp->node->status = 1;
List* temp_list_node = (List*)malloc(sizeof(List)); //新申请一个 链表的结点 并且初始化
temp_list_node->node = temp_node;
temp_list_node->front = temp;
temp_list_node->next = temp->next;
if(temp->next != NULL){
temp->next->front = temp_list_node;
}
temp->next = temp_list_node;
return 1;
}
temp = temp->next;
}
}
int main(){
printf("分区模拟\n");
List list = init();
int select;
int insert_state,recycle_state;
int insert_state_best;
do
{
printf("请输入要进行的操作\n");
printf("1-首次适应算法, 2-最佳适应算法, 3-内存回收, 4-显示内存状况, 5-退出\n");
scanf("%d",&select);
switch (select)
{
case 1: // 1. 首次适应算法
insert_state = First_fit(&list);
if(insert_state == 0){
printf("分配失败\n");
}
else {
printf("分配成功!\n");
}
break;
case 2: // 2. 最佳适应算法
insert_state_best = Best_fit(&list);
if(insert_state_best == 1){
printf("分配成功\n");
}
else {
printf("分配失败\n");
}
break;
case 3: //3.内存回收
recycle_state = Momory_recycle(&list);
if(recycle_state == 1){
printf("回收成功!\n");
}
else{
printf("回收失败\n");
}
break;
case 4: //4.显示内存状况
Momery_state(&list);
break;
}
} while (select != 5);
system("pause");
}