动态分区算法

一个不知名大学生,江湖人称菜狗
original author: Jacky Li
Email : 3435673055@qq.com

Time of completion:2024.04.09
Last edited: 2024.04.09

目录

动态分区算法

第1关:首次适应算法

任务描述

相关知识

内存分配

内存回收

编程要求

测试说明

代码如下

第2关:最佳适应算法

相关知识

内存分配

内存回收

编程要求

测试说明

代码如下


动态分区算法

第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为释放内存的作业号

测试说明

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

代码如下

#include <stdio.h>
#include <stdlib.h>

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, 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;	
  m_last->data.address = 0;	
  m_last->data.size = Max_length;	
  m_last->data.ID = 0;
  m_last->data.flag = 0;
}

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

bool first_fit(int id,int m_size)//首次适应算法,id为作业号,m_size为作业大小 
{    
    //请补充使用首次适应算法给作业分配内存的函数代码
    DuLinkList temp=(DuLinkList)malloc(sizeof(DuNode));//申请双向链表指针节点temp(*a.b=a->b) 
    DuNode *p=m_head->next;
    temp->data.ID=id;//*temp.data.ID
    temp->data.size=m_size;
    temp->data.flag=1;
    
    while(p){//循环查找 
      
        if(p->data.flag==0&&p->data.size==m_size){//p节点未占用,并且空间刚好满足 
            p->data.flag=1;
            p->data.ID=id;
           return false;
        }
        if(p->data.flag==0&&p->data.size>m_size){//p节点未占用,且空间大于所需 
            temp->next=p;
            temp->prior=p->prior;//temp 插入p之前 
            
            temp->data.address=p->data.address;//分区起始地址 
            p->prior->next=temp;
            p->prior=temp;
            p->data.address=temp->data.address+temp->data.size;
            p->data.size-=m_size;
          return false;
        }
        p=p->next;
    }
  return true;

}


void recycle(int id)//回收内存,id为释放内存的作业号 
{    
    //请补充回收作业内存的代码
    
     DuLinkList n=m_head->next ;
    while(n)
    {
       
        DuLinkList q=n->next;
        if(n->data.ID==id)
        {
            if(n->prior!=m_head&&n->prior->data.flag==0&&n->next->data.flag==0)
            {
                n->prior->data.size = n->prior->data.size+q->data.size+n->data.size;
                 q->prior= n->prior;
                 n->prior->next=q;
                 
                 if(q==m_last)
                 {
                 n->prior->next=NULL;
                 n->prior->data.ID=0;
                 }
                 delete(n);
                
            }
            else if(n->prior!=m_head&&n->prior->data.flag==0&&n->next->data.flag != 0)
            { 
                n->prior->data.size+=n->data.size;
                n->prior->next=q;
                q->prior=n->prior;
                delete n;
                break; 
            }
            else if(n->next->data.flag==0&&n->prior->data.flag!=0&&n->prior!=m_head)
            { 
              n->data.size+=q->data.size;
              n->next=q->next;
              n->data.flag=0;
              q->next->prior=n;
              delete q;
              break;
            }
            else
            {
              n->data.flag=0;
              
              break;
            }
        }
        n=n->next;
    }
    
}
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;
} 


第2关:最佳适应算法

假设初始状态下可用的内存空间为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) 回收区前后没有空闲分区。这时应为回收区单独建立一个新表项,填写回收区的首址和大小,并根据其首址插入到空闲链中的适当位置

编程要求

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

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

测试说明

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

代码如下

#include <stdio.h>
#include <stdlib.h>

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, 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;	
  m_last->data.address = 0;	
  m_last->data.size = Max_length;	
  m_last->data.ID = 0;
  m_last->data.flag = 0;
}

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


bool best_fit(int id, int m_size)//最佳适应算法,其中需要查找最佳的存放位置
{	
    //请补充使用最佳适应算法给作业分配内存的函数代码
    
    DuLinkList m = new DuNode;
	DuNode *p = m_head->next; 
	DuNode *q;
	int min=1000;
	while(p)
	{
		
		if(p->data.flag==0) 
		{
			int size=p->data.size-m_size;
			if(size<min&&size>0) 
			{
				q=p;
				min = size;
			}
		}
		p=p->next;
	 }
	m->prior= q->prior;
	q->prior->next=m;
	m->next=q;
	q->prior =m;
	
	m->data.flag=1;
	if(m->prior==m_head)
	m->data.address= 0;
	else
	m->data.address=m->prior->data.address+m->prior->data.size;
	
	m->data.ID=id;
	m->data.size=m_size;
	
	q->data.address=m->data.address+m->data.size;
	q->data.ID=0;
	q->data.size = q->data.size-m_size; 
	
	 
	
}
	



void recycle(int id)//回收内存,id为释放内存的作业号 
{	
    //请补充回收作业内存的函数代码
     DuLinkList n=m_head->next ;
    while(n)
    {
       
        DuLinkList q=n->next;
        if(n->data.ID==id)
        {
            if(n->prior!=m_head&&n->prior->data.flag==0&&n->next->data.flag==0)
            {
                n->prior->data.size = n->prior->data.size+q->data.size+n->data.size;
                 q->prior= n->prior;
                 n->prior->next=q;
                 
                 if(q==m_last)
                 {
                 n->prior->next=NULL;
                 n->prior->data.ID=0;
                 }
                 delete(n);
                
            }
            else if(n->prior!=m_head&&n->prior->data.flag==0&&n->next->data.flag != 0)
            { 
                n->prior->data.size+=n->data.size;
                n->prior->next=q;
                q->prior=n->prior;
                delete n;
                break; 
            }
            else if(n->next->data.flag==0&&n->prior->data.flag!=0&&n->prior!=m_head)
            {
              n->data.size+=q->data.size;
              n->next=q->next;
              n->data.flag=0;
              q->next->prior=n;
              delete q;
              break;
            }
            else
            {
              n->data.flag=0;
              
              break;
            }
        }
        n=n->next;
    }
    
}

int main()
{
	init();
	 
    //最佳适应算法
	printf("最佳适应算法:\n");
	init();
	best_fit(1,15);
	best_fit(2,30);
	recycle(1);
	best_fit(3,8);
	best_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;
} 


  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
动态分区算法内存管理中常用的一种算法,它的主要思想是根据进程的需要动态地分配内存,以满足进程的需求。下面是一个简单的动态分区算法实验。 实验环境: - 操作系统:Windows/Linux - 编程语言:C/C++ 实验步骤: 1. 初始化内存空间 首先,我们需要初始化一段内存空间,这个空间可以看作是操作系统为进程分配的内存空间。我们可以使用一个结构体来表示这段内存空间,该结构体包含了内存块的大小和状态信息。 ```c++ struct MemoryBlock { int size; // 内存块大小 bool is_free; // 内存块是否空闲 }; ``` 然后,我们可以创建一个数组来表示内存空间中的多个内存块,如下所示: ```c++ MemoryBlock memory[10]; ``` 在初始化时,我们需要将这些内存块的状态都设为“空闲”。 ```c++ for (int i = 0; i < 10; i++) { memory[i].size = 0; memory[i].is_free = true; } ``` 2. 实现动态分区分配算法动态分区分配算法中,我们需要实现两个主要函数:分配函数和释放函数。 分配函数的作用是根据进程需要的内存大小,从内存空间中找到一个足够大的内存块,并将其分配给进程使用。如果找不到足够大的内存块,则分配失败。 ```c++ void* allocate_memory(int size) { for (int i = 0; i < 10; i++) { if (memory[i].is_free && memory[i].size >= size) { // 找到一个足够大的空闲内存块 memory[i].is_free = false; return &memory[i]; } } // 没有找到足够大的空闲内存块 return nullptr; } ``` 释放函数的作用是将进程占用的内存块标记为“空闲”,以便其他进程可以使用该内存块。 ```c++ void free_memory(void* ptr) { MemoryBlock* block = (MemoryBlock*)ptr; block->is_free = true; } ``` 3. 测试动态分区分配算法 我们可以编写一个简单的程序来测试我们实现的动态分区分配算法。该程序首先初始化内存空间,然后分配、释放若干内存块,并输出每个内存块的状态信息。 ```c++ int main() { // 初始化内存空间 for (int i = 0; i < 10; i++) { memory[i].size = rand() % 100 + 1; // 随机生成内存块大小 memory[i].is_free = true; } // 分配、释放若干内存块 void* p1 = allocate_memory(20); void* p2 = allocate_memory(50); free_memory(p1); void* p3 = allocate_memory(30); void* p4 = allocate_memory(80); free_memory(p2); free_memory(p3); void* p5 = allocate_memory(70); // 输出每个内存块的状态信息 for (int i = 0; i < 10; i++) { printf("Memory block %d: size=%d, is_free=%d\n", i, memory[i].size, memory[i].is_free); } return 0; } ``` 运行程序后,输出结果如下: ``` Memory block 0: size=31, is_free=0 Memory block 1: size=69, is_free=1 Memory block 2: size=56, is_free=1 Memory block 3: size=42, is_free=1 Memory block 4: size=47, is_free=1 Memory block 5: size=40, is_free=1 Memory block 6: size=38, is_free=1 Memory block 7: size=25, is_free=0 Memory block 8: size=81, is_free=0 Memory block 9: size=9, is_free=1 ``` 可以看到,我们实现的动态分区分配算法可以正确地分配、释放内存块,并维护每个内存块的状态信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

羁旅少年

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

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

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

打赏作者

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

抵扣说明:

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

余额充值