这是根据操作系统作业写的一个算法,用于模拟实现内存空间的动态分区分配,写的还是比较简单的。使用C++,创建双向链表来模拟动态分区,也当做是对C++链表的复习了。
首先来看具体动态分区结点的定义以及双向链表中方法的定义,具体需要用到的功能都如下所示:
#include
#include
using namespace std;
const int minsize=5; //允许的最小碎片空间大小为5
struct node //动态分区结点
{
int space; //空间大小
int address; //分区首地址
bool status; //状态号
node* prev;
node* next;
};
class doublelink //双向链表类来存储
{
public:
doublelink(int sp[],int ad[],int i,bool st[]); //构造函数
void FF(doublelink* ptr,int size);//FF算法 首次适应算法
void BF(doublelink* ptr,int size);//BF算法 最佳适应算法
void WF(doublelink* ptr,int size);//WF算法 最坏适应算法
void display(doublelink* ptr); //显示
int getlength(doublelink* ptr); //获得链表长度
void bubble(doublelink* ptr); //将链表从小到大排序
void rebubble(doublelink* ptr);//将链表从大到小排序
void addressbubble(doublelink* ptr); //将链表按照首地址从小到大排序
void deletespace(doublelink* ptr,int i);//回收内存空间
private:
int length; //记录链表长度
node* root; //头结点
node* tail; //尾结点
};
接下来是关于函数的实现,具体的用法以及思路都写在注释中了:
doublelink::doublelink(int sp[],int ad[],int i,bool st[])
//构造函数的实现
{
root=new node; //头结点中无数据
tail=new node; //尾结点中无数据
root->prev=NULL; //头结点前驱为NULL
tail->next=NULL; //尾结点后继为NULL
root->status=1; //将头尾结点均设置为永久占用状态,方便之后的排序用
tail->status=1;
node *q;
q=root;
length=i; //length记录链表的长度(不包括头和尾)
for(int j=0;jspace=sp[j];
p->address=ad[j];
p->status=st[j];
q->next=p;
p->prev=q;
q=q->next;
}
q->next=tail; //记得将最后一个动态分区的后继结点指向尾结点
}
int doublelink::getlength(doublelink *ptr) //获得链表的长度
{
return ptr->length;
}
void doublelink::deletespace(doublelink* ptr,int e) //释放内存空间
{
node *cur=root->next; //利用cur结点来遍历整个空间
int target=-1; //初始化释放内存空间的大小为-1
for(int i=0;ilength;i++,cur=cur->next) //遍历寻找需要释放的结点
{
if(cur->space==e)
{
target=e; //如果找到,直接跳出循环,该节点就是Cur
break;
}
}
if(target==-1) //遍历完没有发现需要删除的结点,则输出后直接返回
{
cout<<"没有发现需要删除的内存空间"<if(cur->prev->status!=0&&cur->next->status!=0) //该节点的前驱和后继结点均被占用
{
cur->status=0; //直接释放空间即可
cout<<"已经释放内存空间为"<"的分区,没有进行合并"<else if(cur->prev->status!=0&&cur->next->status==0)//该结点的后继结点为空
{
cur->status=0;
cur->space=cur->space+cur->next->space; //将后继结点合并到当前结点
cur->next=cur->next->next;
cur->next->prev=cur;
length--; //记得将动态分区数减1
cout<<"已经释放内存空间为"<"的分区,且与下一个相邻空闲分区合并"<else if(cur->prev->status==0&&cur->next->status!=0)//该节点的前驱结点为空闲
{
cur->prev->space=cur->space+cur->prev->space; //将前驱结点与当前结点合并
cur->prev->next=cur->next;
cur->next->prev=cur->prev;
delete cur;
length--;
cout<<"已经释放内存空间为"<"的分区,且与上一个相邻空闲分区合并"<else if(cur->prev->status==0&&cur->next->status==0) //该节点的前驱和后继结点都为空闲
{
node *p=cur->prev;
node *q=cur->next;
p->space=p->space+cur->space+q->space; //将该节点以及其后继合并到其前驱结点
p->next=q->next;
q->next->prev=p;
delete cur,q;
length=length-2; //注意3个分区合并成1个,所以要减去2
cout<<"已经释放内存空间为"<"的分区,且与上下两个相邻空闲分区合并"<next;
for(int i=0;ilength;i++) //根据长度遍历整个动态分区
{
cout<<"--------------------------------------------------------"<"第"<1<<"个分区大小为:"<space<"分区的首地址为:"<address<if(cur->status==0)
cout<<"分区状态为空闲,未分配"<else
cout<<"分区已被分配"<next;
}
}
void doublelink::FF(doublelink *ptr,int size) //FF算法
{
node *cur=root->next;
for(;cur!=tail;cur=cur->next)//遍历所有空间
{
if(size<=cur->space&&cur->status==0)//首次找到适应的就插入
{
cur->status=1;
if(cur->space-size>minsize) //剩余空间大于最小碎片要求,进行分区
{ node *p=new node; //p为插入新的动态分区,成为当前结点的后继结点
node *q=new node; //q为当前结点的后继结点
q=cur->next;
p->space=cur->space-size;
p->address=cur->address+size;
p->status=0;
q->prev=p; //开始重新设置指针指向
p->next=q;
cur->next=p;
p->prev=cur;
length++; //多了一个分区,长度+1
cur->space=size; //当前分区大小为正好需要内存空间的大小
}
cout<<"已成功为进程分配内存空间"<"无法为进程分配内存空间,内存空间不足"<BF(doublelink *ptr,int size) //BF算法 最佳适应算法
{
bubble(ptr); //只要将内存空间从小到大排序后再进行一次FF算法即可完成
FF(ptr,size);
bubble(ptr);
}
void doublelink::WF(doublelink *ptr,int size)//WF算法 最坏适应算法
{
rebubble(ptr);//只要将内存空间从大到小排序后再进行一次FF算法即可完成
FF(ptr,size);
rebubble(ptr);
}
void doublelink::rebubble(doublelink *ptr) //用冒泡排序算法将内存空间从大到小排序
{
int temp1,temp2; //用于交换内存空间大小
bool temp3; //用于交换分区占用情况
for(int i=0;i1;i++){ //冒泡排序,外循环共进行n-1次
node *cur=new node;
cur=root->next;
for(int j=0;j1-i;j++,cur=cur->next){ //内循环一一比较
node *p=new node;
p=cur->next;
if(cur->spacespace) //如果小于则进行交换
{
temp1=cur->space;
temp2=cur->address;
temp3=cur->status;
cur->space=p->space;
cur->address=p->address;
cur->status=p->status;
p->space=temp1;
p->address=temp2;
p->status=temp3;
}
}
}
//cout<<"已成功进行从大到小排序"<0;i1;i++){
node *cur=new node;
cur=root->next;
for(int j=0;j1-i;j++,cur=cur->next){
node *p=new node;
p=cur->next;
if(cur->space>p->space)
{
temp1=cur->space;
temp2=cur->address;
temp3=cur->status;
cur->space=p->space;
cur->address=p->address;
cur->status=p->status;
p->space=temp1;
p->address=temp2;
p->status=temp3;
}
}
}
//cout<<"已成功进行从小到大排序"<0;i1;i++){
node *cur=new node;
cur=root->next;
for(int j=0;j1-i;j++,cur=cur->next){
node *p=new node;
p=cur->next;
if(cur->address>p->address)
{
temp1=cur->space;
temp2=cur->address;
temp3=cur->status;
cur->space=p->space;
cur->address=p->address;
cur->status=p->status;
p->space=temp1;
p->address=temp2;
p->status=temp3;
}
}
}
cout<<"已成功将首地址进行从小到大排序"<
其中几个排序算法都写的比较冗余了,所以代码片长度看上去就比较长。最后是主函数部分:
int main()
{
int space[]={30,40,50,40,20};
int address[]={0,30,70,120,140};
bool st[]={1,1,0,0,1};
int i=1; //控制输入内存空间大小
int n; //控制功能选择
doublelink *ptr=new doublelink(space,address,5,st); //创建内存空间
while (1)
{
cout<<"1.利用FF算法插入一个进程"<cout<<"2.利用BF算法插入一个进程"<cout<<"3.利用WF算法插入一个进程"<cout<<"4.显示内存空间"<cout<<"5.按照首地址顺序排序"<cout<<"6.释放一个内存空间"<cout<<"7.退出"<cin>>n;
if(n==7)
break;
switch(n)
{
case 1:
cout<<"请输入要插入的进程所占空间大小:"<cin>>i;
ptr->FF(ptr,i);
break;
case 2:
cout<<"请输入要插入的进程所占空间大小:"<cin>>i;
ptr->BF(ptr,i);
break;
case 3:
cout<<"请输入要插入的进程所占空间大小:"<cin>>i;
ptr->WF(ptr,i);
break;
case 4:
ptr->display(ptr); //调用显示功能
break;
case 5:
ptr->addressbubble(ptr);
break;
case 6:
cout<<"请输入要释放的进程所占空间大小:"<cin>>i;
ptr->addressbubble(ptr); //每次都需要排序后再进行删除
ptr->deletespace(ptr,i);
break;
default:break;
}
}
return 0;
}
我创建了5个内存空间用于初始化测试,分别为30,40,50,40,20大小的内存空间,第一个,第二个,最后一个内存空间被占用。我们运行一下程序来看一下:
这是直接显示了内存空间的分配情况,现在我们来用BF(最佳适应算法)插入一个进程试试:
插入进程的大小为20