• 模拟内存分配(链表实现)


    仅仅是一个最简单的内存模拟……


    规 则: 


    我们拥有长度为m字节的内存,输入的第一行是两个整数,分别代表对内存的操作次数以及m的大小,输入的第二行是一个字符串,也就程序中所支持的三种操作:

    1.alloc n – 分配n字节的连续内存,并输出被分配的内存块的id;

    2.erase x – 释放id为x的内存块;

    3.defragment – 对内存进行碎片整理。


    首先我们来规定:

    1.第一块成功分配的内存的id为1,第二块为2,以此类推;

    2.执行alloc操作所开盘的内存必须是连续的,如果有多块符合这一条件的内存块,选择最靠前的那块来分配。如果不能分配这个大小的连续空闲内存块,则输

    出“提示信息”;

    3.erase操作释放完的内存可以重新使用,如果要释放的内存块在内存中没有找到,则返回“该内存块未找到”的提示信息,如果分配成功则不输出任何东西;

    4.defragment操作将使所有内存尽量向前靠近,不打乱他们原本的顺序。


    模拟内存分配(链表实现)

    • 既然是链表实现,一定少不了这个咯!每一个节点记录此处的ID以及该区域内存大小data,布尔型变量t代表这里是否已被占用。

    struct ab
    {
        int data;
        int id;
        bool t;
        struct ab* next;
    };


    • 主程序呢,比较简单,主要是提示信息以及控制操作次数和输入,部分变量已定义为全局变量,比如mail。最重要的功能还在mallo/search/bing这几个函数里面!

    int main()
    {
        int n;
        cout<<"Please enter the number of operations and total memory size"<<endl;
        cin>>n>>mall;
        struct ab *head=NULL;
        while(n--)
        {
            string a;
            int size,id;
            struct ab *aa=head;
            cout<<"Please enter the operation to be performed: ";
            cin>>a;
            if(a=="alloc")
            {
                cout<<"Please enter the size you want to allocate memory: ";
                cin>>size;
                aa=mallo(head,size);
                if(aa==NULL)cout<<"
    
    NULL	Could not find the assigned area.
    "<<endl;
                else head=aa;
            }
            else if(a=="erase")
            {
                cout<<"Please enter a ID that needs to be freed: ";
                cin>>id;
                if(search(head,id)==0)cout<<"
    The ID does not exist.
    "<<endl;
            }
            else if(a=="defragment")
                head=bing(head);
            if(aa!=NULL)print(head);
        }
        return 0;
    }
    


    • 这是mallo函数,之前在主函数里面定义head=NULL,因此第一次分配内存的时候整个内存都是空的(NULL),所以使用if(head==NULL){} 实现建立一个链表的头节点,并且返回头节点的地址,成功分配内存则赋值给head。
    • 若第二次调用mallo函数,而此时head不是NULL,则从头遍历整个链表,若发现有一段内存未用并且大于需要分配的内存大小(p1->data>size&&p1->t==false),则用两个结构体指针,一个指向此时的位置,另一个新开辟一个节点,表示完成这次分配内存后该区域剩余的内存,而当前分配的空间则缩小到指定大小,然后将新节点插入到链表这个位置中这样就模拟出了内存分配。
    • 假如遍历的时候刚好碰见和指定大小一样的一段空内存,这样的话就把该段内存标记为已占用的就可以了,p1->t=true;要是遍历到最后一个区域,也就是前面内存空缺的位置还是不满足指定的要求,需要在最后面分配,这是先检测最后面的区域大小是否符合,若不符合,返回NULL,代表未成功分配内存,若符合,便和上面的情况一样了,新建一个节点来储存剩余内存的信息,而此时的节点就将大小缩小到指定大小,节点内标记为已占用。
    • 代码中的k便是检测前面是否已经分配,若分配k==false,若没有成功分配k==true;这样便是内存最后面的区域了!成功分配返回head,未成功分配返回NULL,其他操作就在主函数里面了。

    int di=1,mall;
    ab* mallo(struct ab *head,int size)
    {
        struct ab *p1=head,*p2=head;
        if(head==NULL)
        {
            if(size>mall)return NULL;
            p1=(struct ab*)malloc(len);
            p1->data=size;
            p1->id=di++;
            p1->t=true;
            p1->next=NULL;
            return p1;
        }
        else
        {
            bool k=false;
            int s=0;
            while(p1!=NULL)
            {
                p2=p1;
                s+=p1->data;
                if(p1->data>size&&p1->t==false)
                {
                    p2=(struct ab*)malloc(len);
                    p2->data=p1->data-size;
                    p2->t=false;
                    p2->id=0;
                    p2->next=p1->next;
                    p1->data=size;
                    p1->t=true;
                    p1->id=di++;
                    p1->next=p2;
                    k=true;
                    break;
                }
                else if(p1->data==size&&p1->t==false)
                {
                    p1->id=di++;
                    p1->t=true;
                    k=true;
                    break;
                }
                else p1=p1->next;
            }
            if(k==false)
            {
                if(mall-s>=size)
                {
                    p1=(struct ab*)malloc(len);
                    p1->next=NULL;
                    p2->next=p1;
                    p1->data=size;
                    p1->t=true;
                    p1->id=di++;
                }
                else return NULL;
            }
        }
        return head;
    }


    • 最重要的一个已经说完了,search这个功能实现很简单,假如释放一个指定ID的内存,把该内存标记为未被占用(false)就行,假如ID未找到,返回 0,找到并成功释放,返回1,判断的条件当然在主函数啦!

    int search(struct ab *p,int id)
    {
        bool k=false;
        while(p!=NULL)
        {
            if(p->id==id)
            {
                p->t=false;
                k=true;
                break;
            }
            p=p->next;
        }
        if(k==false)return 0;
        return 1;
    }

    • 嗯,这个功能是实现内存整理的,本来可以将标记为(false)的内存块大小变为0,就能实现,不过既然是模拟内存分配,就要把未被分配的内存节点从链表中摘下来,好像有delete这个函数可以把摘下来的内存在计算机内存(此内存非彼内存偷笑中释放!但终究没有加入,下面的代码,第四行,是除去整个内存开始的空区域,将头节点重新选择至链表中第一个出现的已占用的区域,然后在循环里面用p2遍历下面连续的空区域,重新连接整个链表,最后便把链表中标记(false)的区域都摘除了下来!返回新链表的头节点head;

    ab* bing(struct ab* head)
    {
        struct ab *p1=head,*p2=head;
        while(p1!=NULL&&p1->t==0)p1=p1->next;
        head=p1;
        while(p1!=NULL)
        {
            if(p1->next==NULL)return head;
            else p2=p1->next;
            while(p2!=NULL&&p2->t==0)p2=p2->next;
            p1->next=p2;
            p1=p2;
        }
        return head;
    }

    • 最后一个功能,输出整个链表,这样大家便可以查看到此时的内存分配状况了!

    void print(struct ab *p1)
    {
        cout<<"
    Size	ID	T/F"<<endl;
        while(p1!=NULL)
        {
            cout<<p1->data<<"	"<<p1->id<<"	";
            if(p1->t==true)cout<<"true"<<endl;
            else cout<<"false"<<endl;
            p1=p1->next;
        }
        cout<<endl;
    }
    • 好了,用链表模拟内存的分配就是这样。

    下面附上完整源代码:

    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string>
    using namespace std;
    #define len sizeof(struct ab)
    struct ab
    {
        int data;
        int id;
        bool t;
        struct ab* next;
    };
    int di=1,mall;
    ab* mallo(struct ab *head,int size)
    {
        struct ab *p1=head,*p2=head;
        if(head==NULL)
        {
            if(size>mall)return NULL;
            p1=(struct ab*)malloc(len);
            p1->data=size;
            p1->id=di++;
            p1->t=true;
            p1->next=NULL;
            return p1;
        }
        else
        {
            bool k=false;
            int s=0;
            while(p1!=NULL)
            {
                p2=p1;
                s+=p1->data;
                if(p1->data>size&&p1->t==false)
                {
                    p2=(struct ab*)malloc(len);
                    p2->data=p1->data-size;
                    p2->t=false;
                    p2->id=0;
                    p2->next=p1->next;
                    p1->data=size;
                    p1->t=true;
                    p1->id=di++;
                    p1->next=p2;
                    k=true;
                    break;
                }
                else if(p1->data==size&&p1->t==false)
                {
                    p1->id=di++;
                    p1->t=true;
                    k=true;
                    break;
                }
                else p1=p1->next;
            }
            if(k==false)
            {
                if(mall-s>=size)
                {
                    p1=(struct ab*)malloc(len);
                    p1->next=NULL;
                    p2->next=p1;
                    p1->data=size;
                    p1->t=true;
                    p1->id=di++;
                }
                else return NULL;
            }
        }
        return head;
    }
    int search(struct ab *p,int id)
    {
        bool k=false;
        while(p!=NULL)
        {
            if(p->id==id)
            {
                p->t=false;
                k=true;
                break;
            }
            p=p->next;
        }
        if(k==false)return 0;
        return 1;
    }
    void print(struct ab *p1)
    {
        cout<<"
    Size	ID	T/F"<<endl;
        while(p1!=NULL)
        {
            cout<<p1->data<<"	"<<p1->id<<"	";
            if(p1->t==true)cout<<"true"<<endl;
            else cout<<"false"<<endl;
            p1=p1->next;
        }
        cout<<endl;
    }
    ab* bing(struct ab* head)
    {
        struct ab *p1=head,*p2=head;
        while(p1!=NULL&&p1->t==0)p1=p1->next;
        head=p1;
        while(p1!=NULL)
        {
            if(p1->next==NULL)return head;
            else p2=p1->next;
            while(p2!=NULL&&p2->t==0)p2=p2->next;
            p1->next=p2;
            p1=p2;
        }
        return head;
    }
    int main()
    {
        int n;
        cout<<"Please enter the number of operations and total memory size"<<endl;
        cin>>n>>mall;
        struct ab *head=NULL;
        while(n--)
        {
            string a;
            int size,id;
            struct ab *aa=head;
            cout<<"Please enter the operation to be performed: ";
            cin>>a;
            if(a=="alloc")
            {
                cout<<"Please enter the size you want to allocate memory: ";
                cin>>size;
                aa=mallo(head,size);
                if(aa==NULL)cout<<"
    
    NULL	Could not find the assigned area.
    "<<endl;
                else head=aa;
            }
            else if(a=="erase")
            {
                cout<<"Please enter a ID that needs to be freed: ";
                cin>>id;
                if(search(head,id)==0)cout<<"
    The ID does not exist.
    "<<endl;
            }
            else if(a=="defragment")
                head=bing(head);
            if(aa!=NULL)print(head);
        }
        return 0;
    }
    

    程序截图:





    执行的操作:

    1.alloc n – 分配n字节的连续内存,并输出被分配的内存块的id;

    2.erase x – 释放id为x的内存块;

    3.defragment – 对内存进行碎片整理。

    • 6 10
    • alloc 5
    • alloc 3
    • erase 1
    • alloc 6
    • defragment
    • alloc 6

    迷失在幽谷中的鸟儿,独自飞翔在这偌大的天地间,却不知自己该飞往何方……


  • 相关阅读:
    SQL应用初级指南
    XML 文档的基本操作
    SQL中单引号的转义
    C# (输入输出流)
    C# 文件与目录的基本操作(System.IO)
    数据库对象命名
    .Net 中的反射(反射特性) Part.3 (转载)
    C# 中的委托和事件(详解)
    SQL Server TransactSQL 编程
    Brush 色谱
  • 原文地址:https://www.cnblogs.com/im0qianqian/p/5989554.html
Copyright © 2020-2023  润新知