进程管理和资源分配算法

63 阅读7分钟

进程管理和资源分配算法

背景介绍

你正在为一款设备管理软件设计其核心的进程管理和资源分配模块。该系统负责管理多种类型的设备(无线、数通、接入),每种类型的设备都由一个专门的进程组进行管理。你的任务是实现这套系统的功能,确保设备能够被正确地创建、删除,并能按需统计。

核心概念

  1. 设备类型与进程组 (Device Types & Process Groups):

    • 系统共管理 3 种设备类型,其 deviceType 值分别为:1 (无线), 2 (数通), 3 (接入)。
    • 每种设备类型都由一个同号的进程组进行管理。
  2. 进程 (Process):

    • 每个进程组内都有 procNum 个进程。
    • 进程的编号 procId0 开始,到 procNum - 1
    • 每个进程的初始内存资源上限都是 maxMemSize
  3. 设备 (Device):

    • 每个设备有一个全局唯一的 deviceId
    • 创建设备会消耗其所在进程的内存资源。

功能要求

你需要实现一个 DeviceMgtSystem 类,支持以下操作:

DeviceMgtSystem(int procNum, int maxMemSize)
  • 功能: 系统初始化。

  • 效果:

    • 为 3 个设备类型分别创建进程组。
    • 每个进程组内创建 procNum 个进程。
    • 每个进程的可用内存初始化为 maxMemSize
createDevice(int deviceId, int deviceType, int memSize)
  • 功能: 在指定的 deviceType 对应的进程组内,为新设备 deviceId 分配资源。

  • 负载均衡规则:

    1. 优先规则: 在所有能满足 memSize 要求的进程中,优先选择空闲内存最多的进程。
    2. 平局规则: 若空闲内存相同,则选择进程编号 (procId) 最小的。
  • 返回值:

    • 成功: 返回设备被分配到的进程编号 procId
    • 失败: 如果该进程组内所有进程的可用内存都不足以满足 memSize,则创建失败,返回 -1
deleteDevice(int deviceId)
  • 功能: 删除指定的设备,并释放其占用的内存。

  • 返回值:

    • 成功: 如果 deviceId 存在,则删除并返回 true
    • 失败: 如果 deviceId 不存在,返回 false
queryDevice(int deviceType)
  • 功能: 查询指定 deviceType 下的所有设备信息。

  • 特殊情况: productId 为 0 时,表示查询所有产品(即所有设备)。(注:此处原文为productId,根据上下文应为deviceType)。

  • 返回格式:

    • 一个设备信息列表,每个设备信息格式为 [deviceId, memSize, procId]

    • 返回顺序 (多级排序):

      1. 主排序: 按设备消耗的内存 memSize 降序排列。
      2. 次排序:memSize 相同,按设备所在的进程 procId 升序排列。
      3. 最终排序:procId 也相同,按 deviceId 升序排列。

输入格式

  • procNum: 1 <= procNum <= 5
  • maxMemSize: 100 <= maxMemSize <= 1000
  • deviceType: 1 <= deviceType <= 3
  • memSize: 1 <= memSize <= 100
  • deviceId: 1 <= deviceId <= 1000
  • data (主存): 输入的十六进制字符串,2 <= data.length <= 30000 且为偶数。
  • linkRelations (连接关系): 1 <= linkRelations <= 10000

(注:上述输入格式描述似乎混合了多个问题,这里根据函数原型和样例,仅保留与本题相关的约束。)

输出格式

  • 根据每个函数的原型要求返回相应的值。最终的整体输出由评测框架完成。

样例 1 解读

输入:

// 操作序列
["DeviceMgtSystem", "createDevice", "createDevice", "createDevice", "queryDevice", "createDevice", "queryDevice", "deleteDevice"]
// 参数序列
[[[2, 200]], [8, 1, 50], [12, 1, 30], [3, 1, 30], [1], [15, 1, 30], [1], [10]]

输出:

[null, 0, 1, 1, [[8, 50, 0], [3, 30, 1], [12, 30, 1]], 0, [[8, 50, 0], [15, 30, 0], [3, 30, 1], [12, 30, 1]], false]

一步步解释:

#调用解释与系统状态变化 (仅展示进程组 1)返回值
1DeviceMgtSystem(2, 200)初始化。进程组1状态: P0: 200, P1: 200null
2createDevice(8, 1, 50)P0, P1 内存相同,选编号小的 P0。P0 内存变为 150。0
3createDevice(12, 1, 30)P1 (200) 内存 > P0 (150),选 P1。P1 内存变为 170。1
4createDevice(3, 1, 30)P1 (170) 内存 > P0 (150),选 P1。P1 内存变为 140。1
5queryDevice(1)设备列表: {id:8, mem:50, proc:0}, {id:12, mem:30, proc:1}, {id:3, mem:30, proc:1}。 排序: mem降序->8在前; 3和12 mem相同, proc相同, 按id升序->3在前。[[8, 50, 0], [3, 30, 1], [12, 30, 1]]
6createDevice(15, 1, 30)P1 (140) 内存 < P0 (150),选 P0。P0 内存变为 120。0
7queryDevice(1)设备列表: ...{id:15, mem:30, proc:0}。 排序: mem=30时, 15(p0) < 3(p1) < 12(p1)。[[8, 50, 0], [15, 30, 0], [3, 30, 1], [12, 30, 1]]
8deleteDevice(10)设备 10 不存在。false
import java.util.*;
import java.util.stream.Collectors;

/**
 * 模拟一个设备管理系统.
 * 该系统通过分层的进程组结构来管理不同类型的设备,
 * 核心功能包括基于负载均衡规则的设备创建、设备删除以及按复杂规则排序的设备查询。
 */
public class DeviceMgtSystem {

    // --- 内部数据结构定义 ---

    /**
     * 内部类,表示一个被管理的设备.
     * 存储了设备自身的信息以及它所属的进程ID。
     */
    private static class Device {
        int id;       // 设备ID
        int memSize;  // 消耗的内存大小
        int procId;   // 所属进程的ID

        public Device(int id, int memSize, int procId) {
            this.id = id;
            this.memSize = memSize;
            this.procId = procId;
        }
    }

    /**
     * 内部类,表示一个管理进程.
     * 封装了进程的属性,如内存使用情况,以及其管理的所有设备。
     */
    private static class Process {
        int id;           // 进程ID
        int maxMemSize;   // 最大内存上限
        int usedMem;      // 已使用的内存
        // 使用Map可以快速通过设备ID找到设备对象
        Map<Integer, Device> managedDevices;

        public Process(int id, int maxMemSize) {
            this.id = id;
            this.maxMemSize = maxMemSize;
            this.usedMem = 0;
            this.managedDevices = new HashMap<>();
        }

        /** 获取当前进程的空闲内存. */
        public int getFreeMem() {
            return this.maxMemSize - this.usedMem;
        }

        /** 在该进程下添加一个设备. */
        public void addDevice(Device device) {
            this.managedDevices.put(device.id, device);
            this.usedMem += device.memSize;
        }

        /** 从该进程下移除一个设备. */
        public void removeDevice(Device device) {
            this.managedDevices.remove(device.id);
            this.usedMem -= device.memSize;
        }
    }

    // --- DeviceMgtSystem 类的成员变量 ---

    /**
     * 二维数组,用于存储所有进程组.
     * 第一维的索引对应 deviceType - 1 (0, 1, 2)
     * 第二维是该进程组下的所有进程.
     */
    private final Process[][] processGroups;

    /**
     * 全局设备位置映射表.
     * 这是一个关键的优化,使得删除设备时可以O(1)时间复杂度定位到设备所在的进程。
     * Key: deviceId, Value: 管理该设备的Process对象.
     */
    private final Map<Integer, Process> deviceLocationMap;

    /**
     * 初始化设备管理系统.
     * @param procNum 每个进程组的进程数量
     * @param maxMemSize 每个进程的内存上限
     */
    public DeviceMgtSystem(int procNum, int maxMemSize) {
        // 共3种设备类型,所以有3个进程组
        this.processGroups = new Process[3][procNum];
        this.deviceLocationMap = new HashMap<>();

        // 初始化所有进程
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < procNum; j++) {
                processGroups[i][j] = new Process(j, maxMemSize);
            }
        }
    }

    /**
     * 创建一个新设备.
     * @return 成功则返回所在进程编号;否则返回-1.
     */
    public int createDevice(int deviceId, int deviceType, int memSize) {
        Process[] targetGroup = this.processGroups[deviceType - 1];
        Process bestProcess = null;

        // 遍历目标进程组,根据“负载均衡规则”寻找最佳进程
        for (Process currentProcess : targetGroup) {
            // 筛选条件:进程必须有足够的剩余内存
            if (currentProcess.getFreeMem() >= memSize) {
                if (bestProcess == null) {
                    // 如果还没找到过候选进程,当前进程就是最好的
                    bestProcess = currentProcess;
                } else {
                    // 规则1:优先选择空闲内存较多的
                    if (currentProcess.getFreeMem() > bestProcess.getFreeMem()) {
                        bestProcess = currentProcess;
                    } 
                    // 规则2:空闲内存相同,选择编号较小的
                    else if (currentProcess.getFreeMem() == bestProcess.getFreeMem() && currentProcess.id < bestProcess.id) {
                        bestProcess = currentProcess;
                    }
                }
            }
        }

        // 如果没有找到合适的进程,则创建失败
        if (bestProcess == null) {
            return -1;
        }

        // 创建成功,更新状态
        Device newDevice = new Device(deviceId, memSize, bestProcess.id);
        bestProcess.addDevice(newDevice);
        deviceLocationMap.put(deviceId, bestProcess); // 更新全局位置映射

        return bestProcess.id;
    }

    /**
     * 删除一个设备.
     * @return 如果设备存在并成功删除,返回true;否则返回false.
     */
    public boolean deleteDevice(int deviceId) {
        // 利用全局映射表快速定位设备所在的进程
        Process process = deviceLocationMap.get(deviceId);

        if (process == null) {
            return false; // 设备不存在
        }

        // 从进程中获取并移除设备信息
        Device deviceToDelete = process.managedDevices.get(deviceId);
        process.removeDevice(deviceToDelete);
        
        // 从全局映射表中移除
        deviceLocationMap.remove(deviceId);

        return true;
    }

    /**
     * 查询指定设备类型下的所有设备信息.
     * @return 按复杂规则排序后的设备信息列表.
     */
    public List<List<Integer>> queryDevice(int deviceType) {
        List<Device> allDevicesInGroup = new ArrayList<>();
        Process[] targetGroup = this.processGroups[deviceType - 1];

        // 1. 收集指定进程组中的所有设备
        for (Process process : targetGroup) {
            allDevicesInGroup.addAll(process.managedDevices.values());
        }

        // 2. 根据题目的三级排序规则进行排序
        allDevicesInGroup.sort(
            // 优先按 memSize 降序
            Comparator.comparingInt((Device d) -> d.memSize).reversed()
            // memSize 相同,按 procId 升序
            .thenComparingInt(d -> d.procId)
            // procId 相同,按 deviceId 升序
            .thenComparingInt(d -> d.id)
        );

        // 3. 将排序后的Device对象列表转换为题目要求的 List<List<Integer>> 格式
        return allDevicesInGroup.stream()
                .map(d -> Arrays.asList(d.id, d.memSize, d.procId))
                .collect(Collectors.toList());
    }
}