一、题目
请实现一个简易内存池,根据请求命令完成内存分配和释放。
内存池支持两种操作命令REQUEST和RELEASE。其格式为:
REQUEST=请求的内存大小
表示请求分配指定大小内存。 如果分配成功,返回分配到的内存首地址;如果内存不足,或指定的大小为零则输出error
RELEASE=释放的内存首地址
表示释放掉之前分配的内存。释放成功无需输出;如果释放不存在的首地址则输出error
注意:
- 内存池总大小为100字节
- 内存池地址分配必须是连续内存,并优先从低地址分配
- 内存释放后可被再次分配,已释放的内存在空闲时不能被二次释放
- 不会释放已申请的内存块的中间地址
- 释放操作只是针对首地址所对应的单个内存块进行操作,不会影响其他内存块
二、输入
首行为整数N,表示操作命令的个数,取值范围0<N<=100
接下来的N行,每行将给出一个操作命令。操作命令和参数之间用”=“分割,输出描述见题目输出要求
三、输出
输出请求的内存块的首地址
四、示例
示例一
输入:
2
REQUEST=10
REQUEST=20
输出:
0
10
示例二
输入:
5
REQUEST=10
REQUEST=20
RELEASE=0
REQUEST=20
REQUEST=10
输出:
0
10
30
0
五、题解
- 注意题解中的 memory 不是真正分配的内存,可以理解为真实内存的逻辑地址,用来管理真正内存块
- 分配过的内存用 Map 来管理比较好理解;申请过的内存和释放的内存中通过标记数组来表示,让算法理解和实现起来更简单
- 网上还有一种解法是通过 Java 的 TreeMap 来管理分配过的内存块(key 为内存块起始地址,值为终地址)。方法比较高效,但是实现起来稍微有点技巧
5.1 Java 实现
package org.stone.study.algo.ex202411;
import java.util.*;
/**
* 简易内存池
*/
public class MemoryPool {
private final int[] memory;
private final Map<Integer, Integer> allocated;
public MemoryPool() {
this.memory = new int[100];
Arrays.fill(memory, 0);
this.allocated = new HashMap<>();
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
sc.nextLine();
List<String> cmds = new ArrayList<>();
for (int i = 0; i < n; i++) {
cmds.add(sc.nextLine());
}
List<Object> res = new MemoryPool().execute(cmds);
res.forEach(System.out::println);
}
/**
* 执行引擎
* @param cmds
* @return
*/
public List<Object> execute(List<String> cmds) {
List<Object> res = new ArrayList<>();
for(String cmd : cmds) {
String[] cmdArr = cmd.split("=");
if("REQUEST".equals(cmdArr[0])) {
res.add(request(Integer.parseInt(cmdArr[1])));
} else if("RELEASE".equals(cmdArr[0])) {
Object errMsg = release(Integer.parseInt(cmdArr[1]));
if(errMsg != null) {
res.add(errMsg);
}
}
}
return res;
}
/**
* 申请内存
* @param size
* @return
*/
private Object request(int size) {
int start = 0;
if(size <= 0 || size > 100) {
return "error";
}
while(start < 100) {
// 找到连续的空闲内存起点
while (start < 100 && memory[start] != 0) {
start++;
}
if (start + size > 100) {
return "error";
}
// 找到连续的空闲内存终点
int end = start;
while (end < 100 && memory[end] == 0) {
++end;
}
// 找打一块连续的空闲内存
if (end - start >= size) {
allocated.put(start, size);
for (int i = start; i < start + size; i++) {
memory[i] = 1;
}
return start;
}
// 没有找到继续往后找连续内存
start = end;
}
return "error";
}
/**
* 释放内存
* @param address
* @return
*/
private Object release(int address) {
if(!allocated.containsKey(address)) {
return "error";
}
int size = allocated.get(address);
for(int i = address; i < address + size; i++) {
memory[i] = 0;
}
allocated.remove(address);
return null;
}
}
5.2 Python实现
class MemoryPool:
def __init__(self, size):
self.size = size
self.memory = [0] * size
self.allocates = {}
def request(self, size):
if size <= 0 or size > self.size:
return 'error'
start = 0
while start < self.size:
# 找空闲内存起点
while start < self.size and self.memory[start] != 0:
start += 1
if start + size > self.size:
return 'error'
# 找空闲内存终点
end = start
while end < self.size and self.memory[end] == 0:
end += 1
# 如果找到空闲内存
if end - start >= size:
self.memory[start:start+size] = [1] * size
self.allocates[start] = size
return start
start = end
return 'error'
def release(self, address):
if address not in self.allocates:
return 'error'
size = self.allocates[address]
self.memory[address : address + size] = [0] * size
del self.allocates[address]
return None
def main():
# 5
n = int(input())
memoryPool = MemoryPool(100)
res = []
'''
REQUEST=10
REQUEST=20
RELEASE=0
REQUEST=20
REQUEST=10
'''
for _ in range(n):
op = input().split('=')
if op[0] == 'REQUEST':
size = int(op[1])
res.append(memoryPool.request(size))
elif op[0] == 'RELEASE':
address = int(op[1])
res.append(memoryPool.release(address))
'''
0
10
30
0
'''
for s in res:
if s != None:
print(s)
if __name__ == '__main__':
main()