在旋转的磁盘上,我有N个要置换的记录。在RAM中,我有N个索引数组,其中包含所需的排列。我也有足够的RAM一次容纳n条记录。考虑到顺序磁盘访问要快得多的事实,我可以使用哪种算法尽快在磁盘上执行置换?
如果需要,我有很多多余的磁盘可用于中间文件。
答案 0 :(得分:0)
这是一个已知问题。在排列顺序中找到循环。例如,给定五个要置换[1、0、3、4、2]的记录,您有循环(0、1)和(2、3、4)。您可以通过选择一个未使用的起始位置来完成此操作;遵循索引指针,直到返回起点。指针的顺序描述了一个循环。
然后使用一个内部临时变量(一个记录长)对记录进行置换。
temp = disk[0]
disk[0] = disk[1]
disk[1] = temp
temp = disk[2]
disk[2] = disk[3]
disk[3] = disk[4]
disk[4] = temp
请注意,您还可以在遍历指针时执行排列。您还需要一些方法来调出已被置换的位置,例如清除置换索引(将其设置为-1)。
您能看到如何概括吗?
答案 1 :(得分:0)
这是间隔协调的问题。我将通过更改<img>
记录的可用内存来略微简化表示法-大写和小写的M
有点令人困惑。
首先,我们重新排列排列为一系列间隔,即记录需要驻留在RAM中的旋转范围。如果需要将记录写入编号较低的位置,我们将通过增加列表大小来增加端点,以指示卷回-必须等待下一次磁盘旋转。例如,使用我之前的示例,我们扩展列表:
N
现在,我们应用标准的贪婪调度解决方案。首先,按端点排序:
[1, 0, 3, 4, 2]
0 -> 1
1 -> 0+5
2 -> 3
3 -> 4
4 -> 2+5
现在,将算法应用于[0, 1]
[2, 3]
[3, 4]
[1, 5]
[4, 7]
“车道”;交换空间需要额外的空间。我们填充每个车道,并在区间的末尾附加起点,起点不重叠:
M-1
如果M> = 3,我们总共可以进行7次“滴答”。如果M = 2,我们将第二车道推迟2圈旋转到[11,15]。
[0, 1] [2, 3] [3, 4] [4, 7]
[1, 5]
的很好的例子为我们带来了更多麻烦,而且重叠程度更高:
Sneftal
这需要4个“车道”(如果有),如果[0, 4]
[1, 5]
[2, 6]
[3, 7]
[4, 0+8]
[5, 1+8]
[6, 2+8]
[7, 3+8]
<5,则根据需要推迟车道。
病理情况是需要将排列中的每个记录复制回一个位置,例如{3,0,1,2},M
= 2。 / p>
M
在这种情况下,我们将多次执行延迟周期。每次旋转结束时,我们都必须将所有剩余间隔延迟一圈,从而导致
[0, 3]
[1, 4]
[2, 5]
[3, 6]
是让您感动还是需要更多细节?
答案 2 :(得分:0)
我有一个主意,可能需要进一步改进。但是就这样:
假设硬盘具有以下结构:
5 4 1 2 3
我们想写出这个排列:
2 3 5 1 4
由于hdd是一个循环缓冲区,并且假设它只能沿一个方向旋转,因此我们可以使用以下移位来编写上述排列:
5 >> 2
4 >> 3
1 >> 1
2 >> 2
3 >> 2
因此,我们将其放置在一个数组中,由于我们知道它是一个圆形数组,所以让其镜像并排放置:
| 2 3 1 2 2 | 2 3 1 2 2| 2 3 1 2 2 | 2 3 1 2 2 |... Inf
由于我们希望支持顺序读取(或写入),因此可以将成本函数放入上述序列中。令成本函数为线性,即。 e:
0 1 2 3 4 5 6 7 8 9 10 ... Inf
现在,让我们将成本函数添加到上述系列中,但是如何选择起点?
想法是选择起点,以便获得最大的全等单调递增序列。
例如,如果您将0点选择为“ 3”,则会得到
(1) | - 3 2 4 5 | 6 8 7 9 10 | ...
如果选择0点位于“ 2”上,即“ 1”的右边,则会得到:
(2) | - - - 2 3 | 4 6 5 7 8 | ...
由于我们试图支持连续读取,因此请定义读写功能使其工作:
f():
现在,我们应该注意,如果满足以下条件:
shift amount <= n - 1 (n : available memory we can hold)
使用上述功能,我们可以一次遍历硬盘。例如:
current: 4 5 6 7 0 1 2 3
we want: 0 1 2 3 4 5 6 7
n : 5
我们可以从任何地方开始,例如从开头的“ 4”开始。我们依次读取4个项目,(现在n个有4个项目),我们从0 1 2 3开始放置(因为n = 5,总共使用4,所以使用了1。用于交换)。因此,总操作为4次连续读取,然后r-w操作为8次。
使用该类推,很显然,如果我们从等式(1)和(2)中减去“ n-1”,则值“ <= 0”的位置将更适合初始位置,因为高于零肯定会要求另一次通过。
因此,我们选择eq。 (2)并减去,例如“ n = 3”,我们从等式中减去2。 (2):
(2) | - - - 0 1 | 2 4 3 5 6 | ...
现在很明显,使用f()从0开始,假设n = 3,我们将具有如下启动操作:r,r,r-w,r-w,...
那么,我们如何做剩下的事情并找到最低成本?我们将放置一个具有最小初始成本的数组,该数组位于等式(2)下方。该数组中的位置将表示我们希望f()的执行位置。
| - - - 0 1 | 2 4 3 5 6 | ...
| - - - 1 1 | 1 1 1 1 1 | ...
第二个数组,带有1和0的数组告诉程序在哪里执行f()。请注意,如果我们假设这些位置错误,则f()将声明。
在我们开始将文件实际放入HDD之前,我们当然想看看f()位置是否正确。我们检查是否有断言,我们将尝试在删除所有断言的同时将成本降至最低。因此,例如:
(1) 1111000000000000001111
(2) 1111111000000000000000
(1)显然要比(2)高。因此,该问题简化了查找1-0数组的过程。
有关寻找最佳阵列的一些想法:
蛮力:编写一个如(2)所示的数组,并开始将1右移,以尝试可用的每个排列的顺序:
1111111100000000 1111111010000000 1111110110000000 ...
完全随机的方法:插入mt1997并开始置换。每当您发现成本急剧下降时,请停止执行并实施hdd复制粘贴。您不会找到全局最小值,但是会得到一个不错的权衡。
遗传算法:对于“移位计数远低于n-1”的置换,此答案中提供的方法应(?)提供全局最小和平滑梯度。这样一来,人们就可以使用遗传算法,而不必过于依赖突变。
我在这种方法中发现的一个优点是,由于OP提到这是一个现实问题,因此该方法提供了一种简便的方法来更改成本函数。与要复制一个大文件相比,要复制很多连续的小文件要容易得多。还是rrwwrrww比rrrrwwww更好?
这甚至有意义吗?我们将不得不尝试...