如何实现以下OrderElements
功能?
char chars[] = {'a', 'b', 'c', 'd', 'e'};
int want_order[] = {2, 4, 3, 0, 1};
int length = 5;
OrderElements(chars, want_order, length);
// chars now contains: c, e, d, a, b
当您可以使用线性额外空间时很容易,但是只能使用恒定的额外空间,即直接对chars
元素进行原位排序吗?
P.S。:这不是考试题目;我实际上需要这个功能。
澄清:似乎对所需的最终元素顺序存在误解。示例中的结果数组应具有以下元素,引用原始chars
数组:
{chars[2], chars[4], chars[3], chars[0], chars[1]}
是
{'c', 'e', 'd', 'a', 'b'}.
答案 0 :(得分:6)
严格来说,需要O(lg length)
内存来表示列表索引;但是,我将在本次讨论中忽略这一点,因为使用64位i
可能足以支持我们实际可以重新排序的任何内容。
for (int i = 0; i < length; i++) {
int t = want_order[i];
while (t < i) {
// t has been moved already; we need to find out where the value that started there
// went. Since we must've put it at want_order[t] before, resume looking there
t = want_order[t];
// once t >= i, we know we've not touched that slot more than once, and so our
// value is there
}
swap(chars[i], chars[t]);
}
直观的解释:对于数组中的每个项目,我们将目标值放入其中,将旧值存储在包含目标值的插槽中。我们必须注意处理我们的目标价值被取代的情况;通过注意给定的插槽最多只交换两次来处理;一旦当其中的值被另一个值(这个迭代不会发生,因为这个迭代将会这样做)或当值被移位以插入最终值(仅发生在较低的索引)时。/ p>
说明样本数据的显示方式:
i | want_order | chars | t
0 | 2 4 3 0 1 | a b c d e | 2 (swap)
1 | 2 4 3 0 1 | c b a d e | 4 (swap)
2 | 2 4 3 0 1 | c e d a b | 3 (swap)
3 | 2 4 3 0 1 | c e d a b | 0 (follow)
3 | 2 4 3 0 1 | c e d a b | 3 (swap - no-op)
4 | 2 4 3 0 1 | c e d a b | 1 (follow)
4 | 2 4 3 0 1 | c e d a b | 4 (swap - no-op)
此算法仅使用O(lg n)
内存(对于索引),但我没有尝试完全分析其运行时间。很明显,它是最糟糕的O(n^2)
,但我怀疑它会比实际情况更好。但是,它可能必须遵循的链的长度没有实际限制,因此原则上它最终可能会使用O(n^2)
时间与最坏情况输入。
答案 1 :(得分:1)
不可能。
您至少需要O(log(列表大小))才能知道已排序元素的索引。
答案 2 :(得分:0)
这将在O(n²)
中完成。在外部循环的每次迭代中,当前需要的元素被交换到其正确的位置(第一个内部循环),然后调整剩余元素的所需顺序以反映新情况(第二个内部循环)。
for (int i = 0; i < length; i++)
{
for (int j = wantedOrder[i]; j > i; j--)
{
Swap(chars, j, j - 1);
}
for (int j = i + 1; j < length; j++)
{
if (wantedOrder[j] < wantedOrder[i])
{
wantedOrder[j]++;
}
}
}
这当然需要销毁所需的订单数组。如果不允许这样做,我不知道如何解决问题(至少在目前)。
答案 3 :(得分:0)
可以这样做如果允许你改变want_order数组。该算法相当简单,因为置换可以分解成循环。当您迭代一个周期时,只需标记每个被访问的周期。时间复杂度为O(N)。伪代码:
char chars[] = {'a', 'b', 'c', 'd', 'e'};
int want_order[] = {2, 4, 3, 0, 1};
int length = 5;
OrderElements(chars, want_order, length) {
int i, j, k;
for(i = 0; i < length; ++i) {
if (want_order[i] == -1) continue;
j = startPos = want_order[i];
c = chars[i];
do {
swap(c, chars[j]);
k = want_order[j];
want_order[j] = -1;
j = k
} while(j != startPos);
}
}
答案 4 :(得分:0)
上面的帖子有一个错误(它无意中覆盖了一个索引)。这是一个更正版本:
char chars[] = {'a', 'b', 'c', 'd', 'e'};
int want_order[] = {2, 4, 3, 0, 1};
int length = 5;
OrderElements(chars, want_order, length) {
int i, j, k;
for(i = 0; i < length; ++i) {
if (want_order[i] == -1) continue;
j = startPos = want_order[i];
c = chars[i];
do {
swap(c, chars[j]);
k = want_order[j];
want_order[j] = -1;
j = k
} while(j != startPos);
}
}
答案 5 :(得分:-1)
使用存储器排序操作O(1)是Bubblesort,但它具有性能O(n²)