【问题描述】
由于频繁的内存申请和释放,会产生大量的内存碎片,假设用链表管理内存的分配与回收,要求实现对存在内存碎片内存进行整理,将不连续的已释放的内存合并成大块内存。
(要求在原链表上操作)
管理内存的节点定义如下:
Struct Node
{
lnt length: //内存大小
lnt flag:1 //1 表示被占用,0 表示已释放 Struct Node*next;
}
【输入形式】
输入第一行为整数 n,表示要输入 n 对数; 第二行输入 n 对整,每一对数字中,第一个为内存大小,第二个为是占用还是释放。
例如:
23 1 21 0,输入了两对数字,第一对表示内存大小为 23,被占用,第二对表示内存大小为 21,已经释放。
【输出形式】
对内存碎片进行整理后的管理链表
【样例输入】
5
12 0 23 1 10 0 30 1 11 0
#include <stdio.h>
#include <stdlib.h>
// 定义内存管理节点结构体
struct Node {
int length; // 内存块大小
int flag; // 状态标记(1:占用 0:释放)
struct Node* next; // 指向下一个节点的指针
};
int main() {
int n;
scanf("%d", &n); // 读取输入的节点数量
struct Node* head = NULL; // 链表头指针初始化为空
struct Node** current_ptr = &head; // 使用二级指针辅助构建链表
// 第一阶段:构建初始链表
for (int i = 0; i < n; ++i) {
int length, flag;
scanf("%d %d", &length, &flag); // 读取每个节点的数据
// 动态创建新节点
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->length = length;
new_node->flag = flag;
new_node->next = NULL;
// 将新节点接入链表(精妙的二级指针操作)
*current_ptr = new_node; // 当前指针指向的位置写入新节点地址
current_ptr = &(new_node->next); // 移动二级指针到新节点的next字段地址
}
// 第二阶段:合并相邻空闲内存块
struct Node* current = head; // 从链表头开始遍历
while (current != NULL) {
if (current->flag == 0) { // 发现空闲块时启动合并流程
struct Node* runner = current->next; // 创建游标指针用于连续检测
// 合并所有后续连续的空闲块
while (runner != NULL && runner->flag == 0) {
current->length += runner->length; // 累加内存大小
current->next = runner->next; // 跳过被合并的节点
// 释放被合并节点的内存
struct Node* temp = runner;
runner = runner->next; // 游标移动到下一个待检测节点
free(temp);
}
}
current = current->next; // 移动到下一个节点(可能是合并后的新next)
}
// 第三阶段:输出整理后的链表
struct Node* output = head;
while (output != NULL) {
printf("%d %d ", output->length, output->flag); // 格式:长度 状态
output = output->next;
}
printf("\n"); // 输出结束换行
// 第四阶段:释放链表内存(防止内存泄漏)
while (head != NULL) {
struct Node* temp = head; // 保存当前节点指针
head = head->next; // 头指针前移
free(temp); // 释放当前节点内存
}
return 0;
}
1. 二级指针构建链表技巧: - current_ptr初始指向head的地址 - *current_ptr = new_node 相当于 head = new_node(首次)或前一个节点的next赋值(后续) - current_ptr = &(new_node->next) 将指针移动到新节点的next字段地址 - 这种写法无需单独处理头节点,实现优雅的链表构建 2. 合并算法优化点: - 时间复杂度O(n):只需单次遍历,遇到空闲块时合并后续连续空闲块 - 原地修改:直接在原链表上操作,不需要额外空间 - 内存安全:及时释放被合并节点的内存 3. 边界条件处理: - 处理链表尾部的连续空闲块 - 处理单个孤立空闲块的情况 - 正确处理全占用链表的特殊情况 4. 内存管理完整性: - 输入时使用malloc分配内存 - 合并时及时free被合并节点 - 最后统一释放整个链表

1091

被折叠的 条评论
为什么被折叠?



