适用于连续资源块的数组空闲链表的算法

如何来管理空闲资源,显而易见的是组织成一个双向链表,称作freelist,然后每次从该链表上取出一个

,释放的时候再放回去。为了减少碎片,最好的策略就是优先分配最近释放掉的那个,如果能考虑合并的话

,类似伙伴系统那样,就再好不过了,本文给出的是一个通用的可以将资源映射到一个整型ID的资源分配算

法,完全基于一个数组,不需要内存管理,也不需要分配结构体。

组织链表的时候,内存管理要耗去大量

的工作,前向指针和后向指针的修改前提是必须有这些指针。典型的数据结构就是Linux内核的list_head结

构体。但是对于静态的类似位图的资源并不适合用list_head来组织,因为这类资源本身可以映射到一块连续

的以自然数计数的ID,比较典型的就是磁盘的空闲块,连续内存块的分配。

既然资源位置是连续的,它就

一定能用连续的自然数来表示,那么所有的资源就可以表示成一个数组了-其映射成自然数的ID的数组,记为

ArrayA。

接下来我们需要另外一个数组来表示空闲链表,记为ArrayB。

接下来的然后,就是构造

ArrayB了...ArrayB的大小等于ArrayA大小加上1,多出来的这个元素可以作为不动点存在,它是不会被分配

出去的。ArrayB的元素的大小是ArrayA数组大小占据字节数的两倍,是为了在一个元素中存储两个INDEX,比

如数组大小可以用8位数据表示,即最多256个元素,那么ArrayB的元素就应该是2*8这么大的,举例说明:

数组大小:short-最多65536个元素

ArrayA的数组定义:int arrayA[MAX];MAX最大65536

ArrayB的

数组定义:int arrayB[];int型为两个short型

结构体形象化表示ArrayB:

#define NUM    8
struct freeHL {
        short high_preindex; //表示前一个ArrayA数组中索引
        short low_nextindex;  //表示后一个ArrayA数组中索引
};
struct freeHL  freelist[NUM+1];

相当于将ArrayB劈开成了两半。

然后就可以在连续的数组空

间进行链接操作了。实际上这个数组表示的freelist和指针表示的prev,next的freelist是一致的,数组下

标也是一个指针,只是在数组表示的freelist中,使用的是相对指针偏移而已,表示为下标!

下面就是一

个算法实现问题了,很简单。在freelist中分配了一个index后,需要修改其前向index的后向index以及后向

index的前向index,释放过程和分配过程相反。代码如下:

short data[NUM]; //是为ArrayA
struct freeHL  freelist[NUM+1]; /是为ArrayB
//表示一个下一个分配的index;
unsigned int position = 0;
//全局的一次性初始化,注意,如果是序列化到了文件,
//则不能再次初始化了,应该从文件反序列化来初始化。
void list_init()
{
        int i = 0, j = -1;
        for (; i < NUM+1; i++) {
                freelist[i].high_preindex = (i + NUM)%(NUM+1);
                freelist[i].low_nextindex = (i + 1)%(NUM+1);
        }
        position = 0;
}
//分配接口
int nalloc()
{
        int ret_index = -1, next_index = -1, pre_index = -1;
        ret_index = position;
    //保存当前要分配index的前向index
        next_index = freelist[position].low_nextindex;
    //保存当前要分配index的后向index
        pre_index = freelist[position].high_preindex;
    //分配当前index
	// http://www.bianceng.cn
        position = next_index;
        if (ret_index == next_index) {
                return -1;
        }
    //更新当前index前向index的后向index
        freelist[freelist[ret_index].high_preindex].low_nextindex = next_index;
    //更新当前index后向index的前向index
        freelist[freelist[ret_index].low_nextindex].high_preindex = pre_index;
        return ret_index;
}
//释放接口
int nfree(unsigned int id)
{
        int pos_pre = -1, pos_next = -1;
    //保存下一个要分配的index的前向index,减少碎片以及更加容易命中cache
        pos_pre = freelist[position].high_preindex;
    //释放index为id的元素
        freelist[pos_pre].low_nextindex = id;
        freelist[id].high_preindex = pos_pre;
        freelist[id].low_nextindex = position;
    //下一个要分配的index为刚释放的index
        position = id;
}

下面是一个测试:

int main(int argc, char **argv)
{
        list_init();
        int i = 0;
        printf("begin\n");
        for (; i < NUM+1; i++) {
                printf("\n%d \n", nalloc());
        }
        nfree(5);
        nfree(0);
        nfree(7);
        for (i = 0; i < NUM+1; i++) {
                printf("\n%d \n", nalloc());
        }
        printf("\nend\n");
}

这个代码用在何处呢?前面说过,用在资源可以表示为连续ID的场合,这种场合何在?在《编写一个UNIX

文件系统》中,我说那个空闲i节点以及空闲块的分配算法不好,而上述的方法就可以用,效果比较好,也就

是说,将一点点的工作施放于每次分配/释放的时候,就可以避免在某个时间点做大量的积攒下来的繁重的工

作。这个算法省去了遍历操作,代价就是占用了一点连续的地址空间。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索指针
, 数组
, 数组大小为2n+1
, index
, position
, 大量连续序列数据
, 链表合并
, 一个
分配
空闲链表、隐式空闲链表、链表适用于 查找、链表排序算法、链表查找算法,以便于您获取更多的相关知识。

时间: 2024-11-01 10:59:32

适用于连续资源块的数组空闲链表的算法的相关文章

android 从资源中获取数组

   8.1.1.概述 除了在Java代码中定义数组,Android还提供了在资源中定义数组,然后在Java代码中解析资源,从而获取数组的方法. 实际开发中,推荐将数据存放在资源文件中,以实现程序的逻辑代码与数据分离,便于项目的管理,尽量减少对Java代码的修改. 8.1.2.在资源中定义数组 步骤1.在res/values文件夹下创建arrays.xml文件: 步骤2.在arrays.xml文件中创建一个数组,如下代码所示: <?xml version="1.0" encodi

[数据结构] 数组与链表的优缺点和区别

概述 数组 是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素.但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中.同样的道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素.如果应用需要快速访问数据,很少插入和删除元素,就应该用数组. 链表 中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起,每个结点包括两个部分:一个是存储 数据元素 的 数据域,另一个是存储下一个结点地址的

数组、链表、Hash(转)

     在程序中,存放指定的数据最常用的数据结构有两种:数组和链表.       数组和链表的区别:       1.数组是将元素在内存中连续存放.            链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起.       2.数组必须事先定义固定的长度,不能适应数据动态地增减的情况.当数据增加时,可能超出原先定义的元素个数:当数据减少时,造成内存浪费.            链表动态地进行存储分配,可以适应数据动态地增减的情况.       3.(静态)数组

用数组模拟链表 解释一段程序

问题描述 publicclassCount3Quit3{publicstaticvoidmain(String[]args){//用数组模拟链表//初始化int[]a=newint[500];for(inti=0;i<a.length-1;i++){a[i]=i+1;}a[a.length-1]=0;//从这里解释intleftCount=a.length;intlastIndex=a.length-1,index=0;intnum=0;while(leftCount>1){num++;if(

网易面试题解析:和为n连续正数序列(数组)

网易面试题:和为n连续正数序列(数组) 题目:输入一个正数n,输出所有和为n连续正数序列. 例如:输入15,由于 1+ 2 + 3 + 4 +5 = 4 + 5 + 6 = 7 + 8 = 15, 所以输入3个连续序列1,2,3,4,5  和 4,5,6 和7,8. 分析: 找连续序列可以从2个开始找,再找3个,4个等等,那到什么时候结束呢? 当发现找到的k个数的起始数小于1,终止. 还可以分析出,当k为偶数的时候, n*1.0/k = *.5 ,小数位必须是5,否则找不成功,continue.

数据结构-用数组或链表依次存几个数,要求每次存之前判断要存的数是否和之前的数重复,如果重复就把原先的数删掉。

问题描述 用数组或链表依次存几个数,要求每次存之前判断要存的数是否和之前的数重复,如果重复就把原先的数删掉. 原先的数删掉之后要存的数也不要在存进数组或链表中了.依次存入12,2,6,15,6,2,15,8.最后遍历出来按升序排列.答案应该是8,12 解决方案 int[] data = { 12, 2, 6, 15, 6, 2, 15, 8 }; int[] result = data.GroupBy(x => x).Where(x => x.Count() == 1).Select(x =&

链表排序算法

包括冒泡.选择.插入.快排.归并.希尔和堆排序 以下排序算法的正确性都可以在LeetCode的链表排序这一题检测.本文用到的链表结构如下(排序算法都是传入链表头指针作为参数,返回排序后的头指针) struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; 插入排序(算法中是直接交换节点,时间复杂度O(n^2),空间复杂度O(1)) class Solution { public: Li

已知一个带有头结点的单链表,设计算法将该单链表复制一个拷贝,急急急

问题描述 已知一个带有头结点的单链表,设计算法将该单链表复制一个拷贝,急急急 已知一个带有头结点的单链表,设计算法将该单链表复制一个拷贝,急急急 解决方案 http://zhidao.baidu.com/link?url=07NsUCYjlwgZFGwfyhqq9NxVTk7hVXs7yBAZAyChUU_CPFIZ_WjwusNVPD7CDC1vjFVaMMTGFwp-H8tnfQb9Qa

指针-在C中求char* s[]={};数组元素的个数算法

问题描述 在C中求char* s[]={}:数组元素的个数算法 在C中求char* s[]={"key1=value1","key2= value2","key3 =value3 "}中s数组元素的个数 如,在这个指针数组中元素个数为3: 用什么算法可以算出3: 我用sizeof(s)/sizeof(**s),这个得出值为12 解决方案 首先你要弄清楚这是个数组,元素类型是char *指针. 然后两种方式: 1. sizeof(s) / size