【操做系統】分區分配算法 (首次適應算法、最佳適應算法)(C語言實現)

【操做系統】分區分配算法 (首次適應算法、最佳適應算法)(C語言實現)

(編碼水平較菜,寫博客也只是爲了我的知識的總結和督促本身學習,若是有錯誤,但願能夠指出)

1.動態分區分配算法:

爲了實現動態分區分配,一般將系統中的空閒分區連接成一個鏈。所謂順序查找是指依次搜索空閒分區鏈上的空閒分區,去尋找一個大小能知足要求的分區。 --------計算機操做系統(第四版)node

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;
}


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 的節點,而後分四種狀況討論 
        {   
            // 1、 要回收的是第一個結點
            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;
                }
                return 1;
            }
              //2、 先後都沒有空閒的分區
            //最簡單,   直接改變 分區的 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;
            }
            //3、要回收的節點    前面和後面都是空閒的
            // 將三個空閒區合併到一塊兒,起始地址爲前面的分區的起始地址, 大小爲三個空閒區大小之和
            //還須要作一個判斷,若是
            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;
            }
            // 4、 要回收的節點  前面的節點是空閒的
            //合併後的分區起始地址爲前一個結點, 分區大小爲前一個節點 與 當前節點之和。
            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;
            }
            //5、 要回收的節點    後面的額節點是空閒的
            //合併後的分區首地址爲當前節點 ,  分區大小爲當前節點 與 當前節點的下一個結點大小之和。
            // 這個須要多一個步驟, 改變分區的 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;
 }

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 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;

            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");
}
相關文章
相關標籤/搜索