假设我们有一个名为data
3
2
4
5
2
此外,我们还有以下相同大小的数组info
1
4
0
2
3
info
的每个值表示第一个数组的索引。例如,第一个值是1
,这意味着在位置0
中,最终排序的数组将具有值data[info[0]]
。
通过遵循此逻辑,最终排序的数组将如下:
data[info[0]] => 2
data[info[1]] => 2
data[info[2]] => 3
data[info[3]] => 4
data[info[4]] => 5
我想对data
数组进行就地排序,而不使用任何大小为N
的额外内存,其中N
的大小为data
数组。另外,我希望总操作量尽可能小。
我一直试图想出解决问题的方法,但是我想不出任何不会使用额外内存的东西。请记住,这些是我自己对我正在实施的系统的限制,如果不能保留这些限制,那么我可能不得不考虑别的。
任何想法都会受到赞赏。
提前谢谢
答案 0 :(得分:2)
为什么不简单
for i in 0..n-1 :
info[i] := data[info[i]]
和info
现在保存已排序的数组。如果它必须在data
中,请将其复制回来,下一步:
for i in 0..n-1 :
data[i] := info[i]
总的来说, 2*n
份。
答案 1 :(得分:1)
如果info
数组不需要保持不变,您可以将其用作O(n)
中的附加存储和排序:
for(int i = 0; i < n; ++i) {
int where = info[i];
if (where == i) continue;
info[i] = data[i];
data[i] = i < where ? data[where] : info[where];
}
如果data
的元素已经在正确的位置,我们会跳过该索引。否则,请记住info
数组中的元素,并将正确的元素写入data
,如果它来自较大的索引则从data
获取,并从info
获取它来自较小的指数。
当然,这种简单的方法要求info
和data
数组的类型相同,并且通常3*n
个副本。
如果data
元素无法存储在info
数组中,我们可以按照info
中的周期进行操作:
for(int i = 0; i < n; ++i) {
// Check if this is already in the right place, if so mark as done
if (info[i] == i) info[i] = -1;
// Nothing to do if we already treated this index
if (info[i] < 0) continue;
// New cycle we haven't treated yet
Stuff temp = data[i]; // remember value
int j = info[i], k = i;
while(j != i) {
// copy the right value into data[k]
data[k] = data[j];
// mark index k as done
info[k] = -1;
// get next indices
k = j;
j = info[j];
}
// Now close the cycle
data[k] = temp;
info[k] = -1;
}
n - F + C
个data
元素的副本,其中F
是已经在正确位置的元素数量(排序排列的固定点)和{{1} }是排序排列中长度C
的循环数。这意味着副本数量最多为> 1
。