动态分区算法

第1关:首次适应算法

任务描述

假设初始状态下可用的内存空间为55MB,并有如下的请求序列: 作业1申请15MB 作业2申请30MB 作业1释放15MB 作业3分配8MB 作业4分配6MB 作业2释放30MB 请采用首次适应算法进行内存块的分配和回收,并打印出空闲内存分区链的情况

相关知识

为了完成本关任务,你需要掌握使用首次适应算法进行内存块的分配与回收。

内存分配

空闲分区链按地址递增的顺序链接。在分配内存时,从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区。然后再按照作业的大小,从该分区中划出一块内存空间,分配给请求者,余下的空闲分区仍留在空闲链中。若从链首到链尾都找不到一个能满足要求的分区,则表明系统没有足够大的内存分配给该进程,内存分配失败返回。

内存回收

当进程运行完毕释放内存时,系统根据回收区的首址,从空闲区链(表)中找到相应的插入点,此时可能出现以下四种情况之一: (1) 回收区与插入点的前一个空闲分区F1相邻接,此时应将回收区与插入点的前一分区合并,不必为回收分区分配新表项,而只需修改其前一分区F1的大小。 (2) 回收分区与插入点的后一空闲分区F2相邻接,此时也可将两分区合并,形成新的空闲分区,但用回收区的首址作为新空闲区的首址,大小为两者之和。 (3) 回收区同时与插入点的前、后两个分区F1和F2邻接,此时将三个分区合并,使用F1的表项和F1的首址,取消F2的表项,大小为三者之和。 (4) 回收区前后没有空闲分区。这时应为回收区单独建立一个新表项,填写回收区的首址和大小,并根据其首址插入到空闲链中的适当位置

编程要求

空闲分区采用带头结点的双向链表来管理,主函数、链表初始化函数和打印函数已实现,只需要补充首次适应算法分配内存的函数 first_fit以及内存回收的函数recycle()即可。

bool first_fit(int id,int m_size)//使用首次适应算法给作业分配内存,id为作业号,m_size为作业大小 void recycle(int id)//回收内存,id为释放内存的作业号

测试说明

平台会对你编写的代码进行测试:

预期输出:

 
  1. 首次适应算法:
  2. +++++++++++++++++++++++++++++++++++++++
  3. 分区号:3
  4. 分区起始地址:0
  5. 分区大小:8
  6. 分区状态:已被占用
  7. ——————————————————
  8. 分区号:4
  9. 分区起始地址:8
  10. 分区大小:6
  11. 分区状态:已被占用
  12. ——————————————————
  13. 分区号:FREE
  14. 分区起始地址:14
  15. 分区大小:41
  16. 分区状态:空闲
  17. ——————————————————

开始你的任务吧,祝你成功!

上代码!!!

#include <iostream>
using namespace std;

const int Max_length=55;//最大内存

struct areaNode//管理分区的结构体
{	
    int ID;//分区号	
    int size;//分区大小	
    int address;//分区地址	
    int flag;//使用状态,0为未占用,1为已占用
};

typedef struct DuNode//双向链表结点
{ 
  struct areaNode data;//数据域	
  struct DuNode *prior;//指针域	
  struct DuNode *next;
} *DuLinkList;

DuLinkList m_head = new DuNode;
DuLinkList m_last = new DuNode;//双向链表首尾指针
  
void init()//分区链表初始化
{	
  m_head->prior = NULL;	       //头节点头指针指向空
  m_head->next = m_last;	   //头节点尾指针指向尾指针
  
  m_last->prior = m_head;	//尾节点头指针指向头指针
  m_last->next = NULL;	    //尾节点尾指针指向空
  
  m_head->data.size = 0;	   //头节点数据域的size分区大小为空
  m_head->data.address = 0;   //头节点数据域的分区地址为空
  m_head->data.flag = -1;
  
  m_last->data.address = 0;	   //尾节点数据域的分区地址也初始化为0
  m_last->data.size = Max_length;	  //初始分区为满尺寸,未分配。也就是第一个分区
  m_last->data.ID = 0;               //ID初值设为0,分区号从1开始算 
  m_last->data.flag = 0;             //flag设为0表示没有被使用 
}

void show()
{	
  DuNode *p = m_head->next;//指向空闲区队列的首地址	
  cout<<"+++++++++++++++++++++++++++++++++++++++"<<endl;	
  while (p)	
  {		
    printf("分区号:");		
	
	if (p->data.flag == 0)			
	  cout<<"FREE"<<endl;		
	else
		{
			cout<<p->data.ID<<endl;
		}		
	 cout<<"分区起始地址:"<<p->data.address<<endl;		
	 cout<<"分区大小:"<<p->data.size<<endl;		
	 cout<<"分区状态:";		
	if (p->data.flag)			
	   cout<<"已被占用"<<endl;		
	else			
	   cout<<"空闲"<<endl;		
	 cout<<"——————————————————"<<endl;		
	p = p->next;	
  }
} 

bool first_fit(int id, int m_size)//首次适应算法,id为作业号,m_size为作业大小 
{
	//请补充使用首次适应算法给作业分配内存的函数代码
	DuNode* p = m_head->next;//从头结点出发
    while(p){         //找到合适大小的,并且空闲
        if(p->data.size>=m_size&&p->data.flag==0){
            break;
        }
        p = p->next;
    }
    //p为空值,表示没找到
    if(!p){     //查找完都没找到
        return false;
    }
    //反之就是找到了
    //开始分配
    if(p->data.size==m_size){ //大小正好
        p->data.flag =1;
        p->data.ID = id;
    }

    //反之就是找到了个稍微大了的空间分区
    DuLinkList ff = new DuNode;
    ff->data.ID = id;
    ff->data.size = m_size;

    ff->data.flag = 1;
    ff->data.address = p->data.address;

    //更新被划分的分区信息
    p->data.address = (ff->data.address)+(ff->data.size);
    p->data.size = (p->data.size)-(ff->data.size);
    //插入节点
    ff->next = p;
    ff->prior= p->prior;
    p->prior->next = ff;
    p->prior = ff;

    return true;

}


void recycle(int id)//回收内存,id为释放内存的作业号 
{
	//请补充回收作业内存的代码
	DuNode* f = m_head->next; //取出下一个节点,可能是数据节点,也可能是尾结点
  if(!f->next){   //没有数据节点,删除不了
    return;
  }
  //反之有数据节点,开始查找,标记为ff
  while(f->data.ID!=id) //找到ID为id的节点,为指针f
  {
    f = f->next;
  } 
  if(!f){       //没找到
    return;
  }
	
  DuNode* p = f->next;  //找到ID的下一个节点
  //标记释放的进程为f
  //这里不一定释放哦
  /*
  p->prior = f->prior;
  f->prior->next = p;
  */

  //开始回收合并
  if(f->prior->data.flag==0){     //id前空闲
    if(p->data.flag==0){    //id分区前后都有空闲,一起合并,此时连p一起去删掉

      //保留p
      p->prior = f->prior->prior;
      f->prior->prior->next = p;

      p->data.flag = 0;
      p->data.ID = 0;
      p->data.address = f->prior->data.address;
      p->data.size = (f->prior->data.size) + (f->data.size) + (p->data.size); //更新size

      delete f,f->prior;
    }
    else{   //id前空闲,id分区后不空闲,向前合并
      f->prior->data.size = (f->prior->data.size) + (f->data.size);
      delete f;
    }
  }
  else{     //id分区前不空闲
    if(p->data.flag==0){      //id分区后是空闲的,和后项合并
      
      f->data.size = (f->data.size) + (p->data.size);
      f->data.ID = 0;
      f->data.flag = 0;
      delete p;
    }
    else{       //单独成表项
      f->data.flag = 0;
      f->data.ID = 0;
    }
  }
}



int main()
{
	init();
      
    printf("首次适应算法:\n");
	first_fit(1,15);
	first_fit(2,30);
	recycle(1);
	first_fit(3,8);	
	first_fit(4,6);
	recycle(2);
	show();
	
	DuNode *p = m_head;
	while(p != NULL)
	{
		DuNode *temp =  p;
		p = p->next;
		delete(temp);
		temp = NULL;
	}
	
	return 0;
} 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

eye了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值