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


【操作系統】分區分配算法 (首次適應算法、最佳適應算法)(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");
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM