Algorithm 压缩被阻止文件中的记录的好算法是什么?
假设您有一个由一堆固定大小的块组成的大文件。每个块都包含一些大小可变的记录。每个记录必须完全适合于单个块,根据定义,这样的记录永远不会大于一个完整的块。随着时间的推移,随着记录从这个“数据库”中来来去去去,记录被添加到这些块中并从中删除 在某个时刻,特别是在可能有许多记录被添加到数据库中并删除了一些记录之后,许多块可能最终只被部分填充 通过更好地填充部分填充的块,在数据库中洗牌记录以压缩文件末尾不必要的块的好算法是什么 算法的要求:Algorithm 压缩被阻止文件中的记录的好算法是什么?,algorithm,language-agnostic,np-complete,defragmentation,knapsack-problem,Algorithm,Language Agnostic,Np Complete,Defragmentation,Knapsack Problem,假设您有一个由一堆固定大小的块组成的大文件。每个块都包含一些大小可变的记录。每个记录必须完全适合于单个块,根据定义,这样的记录永远不会大于一个完整的块。随着时间的推移,随着记录从这个“数据库”中来来去去去,记录被添加到这些块中并从中删除 在某个时刻,特别是在可能有许多记录被添加到数据库中并删除了一些记录之后,许多块可能最终只被部分填充 通过更好地填充部分填充的块,在数据库中洗牌记录以压缩文件末尾不必要的块的好算法是什么 算法的要求: 压缩必须代替原始文件进行,而不会临时将文件从其起始大小扩展最
- 压缩必须代替原始文件进行,而不会临时将文件从其起始大小扩展最多几个块
- 该算法不应不必要地干扰已基本满的块
- 整个块必须一次从文件中读取或写入,并且应该假设写入操作相对昂贵
- 如果记录从一个块移动到另一个块,则在从起始位置移除之前,必须在其新位置添加记录,以便在操作中断的情况下,不会因“失败”压缩而丢失任何记录。(假设恢复时可以检测到此类记录的临时重复)
- 可用于此操作的内存可能只有几个块,占整个文件大小的百分比很小
- 假设记录的大小约为10字节到1K字节,平均大小约为100字节。固定大小的块大小约为4K或8K,文件大小约为1000块
更新:我忽略了维护“仅内存中无块”规则。我已经更新了伪代码来修复这个问题。还修复了我的循环条件中的一个小故障。这听起来像是的一个变体,但您已经有了一个需要改进的劣质分配。因此,我建议研究各种方法,这些方法成功地解决了箱子包装问题 首先,你可能想通过定义你认为“足够充分”(块足够满,你不想碰它),以及什么是“太空”(块有很多空的空间,它必须有更多的记录添加到它)来参数化你的问题。然后,您可以将所有块分类为“足够满”、“太空”或“部分满”(既不够满也不太空的块)。然后,您将问题重新定义为如何通过创建尽可能多的足够满的块来消除所有太空的块,同时最小化部分满的块的数量 您还需要确定什么更重要:将记录放入尽可能少的块中,或者充分打包,但读写的块数最少 我的方法是对所有块进行初始遍历,将它们全部分类为上面定义的三个类中的一个。对于每个块,您还需要跟踪其中的可用空间,对于太空的块,您需要一个所有记录及其大小的列表。然后,从太空的块中的最大记录开始,将它们移动到部分满的块中。如果要最小化读写,请将它们移动到内存中当前的任何块中。如果要最大限度地减少浪费的空间,请找到仍保留记录的具有最少空空间的块,如有必要,请读入该块。如果没有块将保留记录,请创建一个新块。如果内存中的某个块达到“足够满”阈值,则将其写出。重复此操作,直到已放置部分填充块中的所有记录
我跳过了很多细节,但这应该会给你一些想法。请注意,装箱问题是,这意味着在实际应用中,您需要决定什么对您最重要,因此您可以选择一种方法,在合理的时间内为您提供近似最佳的解决方案。以下是一种您可以利用的算法,尽管在固定大小的块中记录可能需要更多的工作
对在线(一次整理碎片)有限空间(内存需求)装箱算法的修改可能在这里起作用
请参阅Coffman等人的文章。感谢您指出箱子包装问题。这很有帮助。解决方案中一个棘手的部分是,在第一次通过时要扫描的记录数量太大,并且无法保存统计数据。另外,因为写操作的成本很高,从某种意义上说,你只会有一两次机会重新写一个给定的块理想情况下,我想有一些过程是用来针对特定的块和记录进行整合的。ie:找到每个过程中挂起的最低的果实来收获,当时间太长或没有显著优化时停止。再次感谢!这种方法基本上是我们开始的,但事实证明,记录大小的不规则性通常会留下次优压实块。有了更多的搜索意愿,可以找到更好的拟合,但随后它就变成了NP难,现在正在寻找更多的启发式。欢迎你。我希望调整内存中的块数会有所帮助。比如说,如果你在内存中保存了10个区块的记录,我希望你能大致填满大部分
// records should be sorted by size in memory (probably in a balanced BST)
records = read last N blocks on disk;
foreach (block in blocks) // read from disk into memory
{
if (block.hasBeenReadFrom())
{
// we read from this into records already
// all remaining records are already in memory
writeAllToNewBlocks(records);
// this will leave some empty blocks on the disk that can either
// be eliminated programmatically or left alone and filled during
// normal operation
foreach (record in records)
{
record.eraseFromOriginalLocation();
}
break;
}
while(!block.full())
{
moveRecords = new Array; // list of records we've moved
size = block.availableSpace();
record = records.extractBestFit(size);
if (record == null)
{
break;
}
moveRecords.add(record);
block.add(record);
if (records.gettingLow())
{
records.readMoreFromDisk();
}
}
if(moveRecords.size() > 0)
{
block.writeBackToDisk();
foreach (record in moveRecords)
{
record.eraseFromOriginalLocation();
}
}
}