您的位置:首页 > 编程语言 > C语言/C++

【C++基础复习02】双向链表实现动态分区分配算法

2018-01-05 10:38 417 查看
这是根据操作系统作业写的一个算法,用于模拟实现内存空间的动态分区分配,写的还是比较简单的。使用C++,创建双向链表来模拟动态分区,也当做是对C++链表的复习了。

首先来看具体动态分区结点的定义以及双向链表中方法的定义,具体需要用到的功能都如下所示:

#include<iostream>
#include<cstring>
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;j<i;j++) //利用数组构造结点
{
node *p=new node;
p->space=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;i<ptr->length;i++,cur=cur->next) //遍历寻找需要释放的结点
{
if(cur->space==e)
{
target=e;        //如果找到,直接跳出循环,该节点就是Cur
break;
}
}
if(target==-1)        //遍历完没有发现需要删除的结点,则输出后直接返回
{
cout<<"没有发现需要删除的内存空间"<<endl;
return ;
}
if(cur->prev->status!=0&&cur->next->status!=0) //该节点的前驱和后继结点均被占用
{
cur->status=0;     //直接释放空间即可
cout<<"已经释放内存空间为"<<target<<"的分区,没有进行合并"<<endl;
}
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<<"已经释放内存空间为"<<target<<"的分区,且与下一个相邻空闲分区合并"<<endl;

}
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<<"已经释放内存空间为"<<target<<"的分区,且与上一个相邻空闲分区合并"<<endl;
}
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<<"已经释放内存空间为"<<target<<"的分区,且与上下两个相邻空闲分区合并"<<endl;
}
}

void doublelink::display(doublelink *ptr)      //显示动态分区的安排情况
{
node *cur=root->next;
for(int i=0;i<ptr->length;i++)   //根据长度遍历整个动态分区
{
cout<<"--------------------------------------------------------"<<endl;
cout<<"第"<<i+1<<"个分区大小为:"<<cur->space<<endl;
cout<<"分区的首地址为:"<<cur->address<<endl;
if(cur->status==0)
cout<<"分区状态为空闲,未分配"<<endl;
else
cout<<"分区已被分配"<<endl;
cout<<endl;
cur=cur->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<<"已成功为进程分配内存空间"<<endl;
return; //分配成功直接返回
}
}
cout<<"无法为进程分配内存空间,内存空间不足"<<endl;  //遍历到最后都没有成功分配,则说明内存空间不足,分配失败
}

void doublelink::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;i<length-1;i++){ //冒泡排序,外循环共进行n-1次
node *cur=new node;
cur=root->next;
for(int j=0;j<length-1-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<<"已成功进行从大到小排序"<<endl;
}

void doublelink::bubble(doublelink *ptr)
//用冒泡排序算法将内存空间从小到大排序 ,就改了一个小于符号,和上述排序同理
{
int temp1,temp2;
bool temp3;
for(int i=0;i<length-1;i++){
node *cur=new node;
cur=root->next;
for(int j=0;j<length-1-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<<"已成功进行从小到大排序"<<endl;

}
void doublelink::addressbubble(doublelink *ptr)
{ //首地址排序 ,也是冒泡排序,即排序依据是首地址
int temp1,temp2;
bool temp3;
for(int i=0;i<length-1;i++){
node *cur=new node;
cur=root->next;
for(int j=0;j<length-1-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<<"已成功将首地址进行从小到大排序"<<endl;

}


其中几个排序算法都写的比较冗余了,所以代码片长度看上去就比较长。最后是主函数部分:

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算法插入一个进程"<<endl;
cout<<"2.利用BF算法插入一个进程"<<endl;
cout<<"3.利用WF算法插入一个进程"<<endl;
cout<<"4.显示内存空间"<<endl;
cout<<"5.按照首地址顺序排序"<<endl;
cout<<"6.释放一个内存空间"<<endl;
cout<<"7.退出"<<endl;
cin>>n;
if(n==7)
break;
switch(n)
{
case 1:
cout<<"请输入要插入的进程所占空间大小:"<<endl;
cin>>i;
ptr->FF(ptr,i);
break;
case 2:
cout<<"请输入要插入的进程所占空间大小:"<<endl;
cin>>i;
ptr->BF(ptr,i);
break;
case 3:
cout<<"请输入要插入的进程所占空间大小:"<<endl;
cin>>i;
ptr->WF(ptr,i);
break;
case 4:
ptr->display(ptr); //调用显示功能
break;
case 5:
ptr->addressbubble(ptr);
break;
case 6:
cout<<"请输入要释放的进程所占空间大小:"<<endl;
cin>>i;
ptr->addressbubble(ptr);  //每次都需要排序后再进行删除
ptr->deletespace(ptr,i);
break;
default:break;
}
}
return 0;
}


我创建了5个内存空间用于初始化测试,分别为30,40,50,40,20大小的内存空间,第一个,第二个,最后一个内存空间被占用。我们运行一下程序来看一下:



这是直接显示了内存空间的分配情况,现在我们来用BF(最佳适应算法)插入一个进程试试:

插入进程的大小为20



再来删除一个20的试试:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言