【操作系統】分區分配算法 (首次適應算法、最佳適應算法)(C語言實現)
(編碼水平較菜,寫博客也只是為了個人知識的總結和督促自己學習,如果有錯誤,希望可以指出)
今天測試,發現一點問題:
1.最佳插入算法:對於插入的時候忘記修改temp.next.front的指向
2.回收頭節點的時候現在多了一種判斷。判斷頭節點的下一個是否為空。對如果不為空而且后面的空閑的話,做出了處理。原來則沒有這一情況。
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->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");
}