设计内存分配器

92 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情

问题描述

给你一个整数 n ,表示下标从 0 开始的内存数组的大小。所有内存单元开始都是空闲的。

请你设计一个具备以下功能的内存分配器:

  1. 分配 一块大小为 size 的连续空闲内存单元并赋 id mID 。
  2. 释放 给定 id mID 对应的所有内存单元。

注意:

  • 多个块可以被分配到同一个 mID 。
  • 你必须释放 mID 对应的所有内存单元,即便这些内存单元被分配在不同的块中。

实现 Allocator 类:

  • Allocator(int n) 使用一个大小为 n 的内存数组初始化 Allocator 对象。
  • int allocate(int size, int mID) 找出大小为 size 个连续空闲内存单元且位于  最左侧 的块,分配并赋 id mID 。返回块的第一个下标。如果不存在这样的块,返回 -1 。
  • int free(int mID) 释放 id mID 对应的所有内存单元。返回释放的内存单元数目。

 

示例:

输入
["Allocator", "allocate", "allocate", "allocate", "free", "allocate", "allocate", "allocate", "free", "allocate", "free"]
[[10], [1, 1], [1, 2], [1, 3], [2], [3, 4], [1, 1], [1, 1], [1], [10, 2], [7]]
输出
[null, 0, 1, 2, 1, 3, 1, 6, 3, -1, 0]

解释
Allocator loc = new Allocator(10); // 初始化一个大小为 10 的内存数组,所有内存单元都是空闲的。
loc.allocate(1, 1); // 最左侧的块的第一个下标是 0 。内存数组变为 [1, , , , , , , , , ]。返回 0 。
loc.allocate(1, 2); // 最左侧的块的第一个下标是 1 。内存数组变为 [1,2, , , , , , , , ]。返回 1 。
loc.allocate(1, 3); // 最左侧的块的第一个下标是 2 。内存数组变为 [1,2,3, , , , , , , ]。返回 2 。
loc.free(2); // 释放 mID 为 2 的所有内存单元。内存数组变为 [1, ,3, , , , , , , ] 。返回 1 ,因为只有 1 个 mID 为 2 的内存单元。
loc.allocate(3, 4); // 最左侧的块的第一个下标是 3 。内存数组变为 [1, ,3,4,4,4, , , , ]。返回 3 。
loc.allocate(1, 1); // 最左侧的块的第一个下标是 1 。内存数组变为 [1,1,3,4,4,4, , , , ]。返回 1 。
loc.allocate(1, 1); // 最左侧的块的第一个下标是 6 。内存数组变为 [1,1,3,4,4,4,1, , , ]。返回 6 。
loc.free(1); // 释放 mID 为 1 的所有内存单元。内存数组变为 [ , ,3,4,4,4, , , , ] 。返回 3 ,因为有 3 个 mID 为 1 的内存单元。
loc.allocate(10, 2); // 无法找出长度为 10 个连续空闲内存单元的空闲块,所有返回 -1 。
loc.free(7); // 释放 mID 为 7 的所有内存单元。内存数组保持原状,因为不存在 mID 为 7 的内存单元。返回 0 。

提示:

  • 1 <= n, size, mID <= 1000
  • 最多调用 allocate 和 free 方法 1000 次

思路分析

题目的数据范围并不大,所以我们可以直接按照要求模拟计算操作即可:

  • 1、初始化内存

我们需要定义内存块的长度,初始化传入一个参数作为内存块长度,我们可以将长度记录,并使用一个数组用于模拟,每一个数据的个数可以使用哈希表来记录,后面取值可以少掉很多计算。

/**
 * @param {number} n
 */
var Allocator = function(n) {
    this.n = n;
    this.arr = new Array(n).fill(-1);
    this.count = {};
};
  • 2、存入数据

存入数据,为数据分配内存空间,我们需要先判断内存中是否可以找到一块足够大的连续内存空间来分配给当前数据,无法找到的话我们直接返回-1表示无法为其分配内存空间,可以找到的话,我们将数组指定位置赋值mID,返回找到连续内存空间的左端下标,并更新当前mID出现的个数。

/** 
 * @param {number} size 
 * @param {number} mID
 * @return {number}
 */
Allocator.prototype.allocate = function(size, mID) {
    let num = this.arr[0] == -1 ? 1 : 0;
    for(let i = 0; i < this.n; i++){
        if(i == 0){
            num = this.arr[0] == -1 ? 1 : 0;
        }else if(this.arr[i] == -1 && this.arr[i - 1] == -1){
            num++;
        }else{
            num = this.arr[i] == -1 ? 1 : 0;
        }
        if(num == size){
            let j = i;
            while(this.arr[j] == -1){
                this.arr[j] = mID;
                j--;
            }
            const count = this.count[mID] || 0;
            this.count[mID] = count + size;
            return j + 1;
        }
    }
    return -1;
};
  • 3、删除数据、释放内存

直接遍历数组模拟的内存空间即可,如果值为mID的就将其重置,最后将删除的数据个数返回。

/** 
 * @param {number} mID
 * @return {number}
 */
Allocator.prototype.free = function(mID) {
    let count = this.count[mID] || 0;
    const res = count;
    this.count[mID] = 0;
    if(count == 0) return 0;
    for(let i = 0; i < this.n; i++){
        if(this.arr[i] == mID){
            this.arr[i] = -1;
            count--;
            if(count == 0) return res;
        }
    }
};

AC代码

完整AC代码如下:

/**
 * @param {number} n
 */
var Allocator = function(n) {
    this.n = n;
    this.arr = new Array(n).fill(-1);
    this.count = {};
};

/** 
 * @param {number} size 
 * @param {number} mID
 * @return {number}
 */
Allocator.prototype.allocate = function(size, mID) {
    let num = this.arr[0] == -1 ? 1 : 0;
    for(let i = 0; i < this.n; i++){
        if(i == 0){
            num = this.arr[0] == -1 ? 1 : 0;
        }else if(this.arr[i] == -1 && this.arr[i - 1] == -1){
            num++;
        }else{
            num = this.arr[i] == -1 ? 1 : 0;
        }
        if(num == size){
            let j = i;
            while(this.arr[j] == -1){
                this.arr[j] = mID;
                j--;
            }
            const count = this.count[mID] || 0;
            this.count[mID] = count + size;
            return j + 1;
        }
    }
    return -1;
};

/** 
 * @param {number} mID
 * @return {number}
 */
Allocator.prototype.free = function(mID) {
    let count = this.count[mID] || 0;
    const res = count;
    this.count[mID] = 0;
    if(count == 0) return 0;
    for(let i = 0; i < this.n; i++){
        if(this.arr[i] == mID){
            this.arr[i] = -1;
            count--;
            if(count == 0) return res;
        }
    }
};

/**
 * Your Allocator object will be instantiated and called as such:
 * var obj = new Allocator(n)
 * var param_1 = obj.allocate(size,mID)
 * var param_2 = obj.free(mID)
 */

说在后面

本人为算法业余爱好者,平时只是随着兴趣偶尔刷刷题,如果上面分享有错误的地方,欢迎指出,感激不尽。