如何使用 O(1) 辅助空间将数组排列成给定顺序?

发布于 2024-08-05 18:40:04 字数 587 浏览 2 评论 0原文

如何实现以下 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 元素进行排序吗?

PS:这不是一道考试题;我确实需要这个功能。

澄清:对于所需的元素最终顺序似乎存在误解。示例中的结果数组应具有以下元素,引用原始 chars 数组

{chars[2], chars[4], chars[3], chars[0], chars[1]}

{'c', 'e', 'd', 'a', 'b'}. 

How do I implement the following OrderElements function?

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

It's easy when you can use linear extra space, but can it be done with only constant extra space, i.e., directly sorting the chars elements in-place?

P.S.: This was not an exam question; I actually need this function.

CLARIFICATION: There seems to be a misunderstanding about the desired final order of elements. The resulting array in the example should have the following elements, referring to the original chars array:

{chars[2], chars[4], chars[3], chars[0], chars[1]}

which is

{'c', 'e', 'd', 'a', 'b'}. 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

上课铃就是安魂曲 2024-08-12 18:40:04

但严格来说,表示列表索引需要 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]);
}

直观的解释:对于数组中的每个项目,我们将目标值放入其中,将旧值存储在包含目标值的槽中。我们必须小心处理我们的目标价值被错位的情况;这是通过注意给定插槽最多只能交换两次来处理的;一旦其中的值被另一个值窃取(这不可能发生,因为本次迭代将执行此操作),或者当该值被替换以插入最终值时(这只发生在较低的索引中)。

示例数据上的示例:

 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) 时间。

Strictly speaking, though, O(lg length) memory is needed to represent the list index; I'm going to ignore this for this discussion, however, since using a 64-bit i is probably big enough for anything that we can actually reorder.

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]);
}

An intuitive explanation: For each item in the array, we put the goal value in it, storing our old value in the slot that contained our goal value. We have to take care to deal with the case that our goal value was displaced; this is handled by noting that a given slot is only swapped up to twice; once when the value in there is stolen by another value (which couldn't have happened, since this iteration is going to do that) or when the value is displaced to insert the final value (which only happens to lower indices).

An illustration of how this looks on your sample data:

 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)

This algorithm uses only O(lg n) memory (for the indices), but I have not attempted to fully analyze its running time. It's obvious that it's at worst O(n^2), however I suspect it will fare better than that in practice. However, there is no real bound on the length of the chains it might have to follow, so in principle it may in fact end up using O(n^2) time with worst-case input.

暗藏城府 2024-08-12 18:40:04

不可能的。

您至少需要 O(log (列表大小)) 才能知道已排序元素的索引。

Impossible.

You need at least O(log (list size)) to know the index of the sorted element.

我是有多爱你 2024-08-12 18:40:04

这将在 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]++;
        }
    }
}

这当然需要销毁想要的订单数组。如果这是不允许的,我不知道如何解决问题(至少目前如此)。

This will do the job in O(n²). In each iteration of the outer loop the currently wanted element is swapped down to its correct position (first inner loop) and then the wanted order of the remaining elements is adjusted to reflect the new situation (second inner loop).

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]++;
        }
    }
}

This of course requires destroying the wanted order array. If this is not allowed, I have no idea how to solve the problem (at least at the moment).

£冰雨忧蓝° 2024-08-12 18:40:04

上面的帖子有一个错误(它无意中覆盖了索引)。这是一个更正的版本:

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);
  }
}

The post above has an error (it inadvertantly overwrites an index). Here is a corrected version:

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);
  }
}
想你的星星会说话 2024-08-12 18:40:04

如果允许更改 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);
  }
}

It can be done If you are allowed to change the want_order array. The algorithm is rather simple as the permutation can be decomposed into cycles. When you iterating one cycle, just mark each one being visited. And the time complexity is O(N). Pseudo code:

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);
  }
}
只是在用心讲痛 2024-08-12 18:40:04

使用内存的排序操作 O(1) 是冒泡排序,但它的性能为 O(n²)

http:// en.wikipedia.org/wiki/Bubble_sort

Sort Operation with Memory O(1) is Bubblesort, but it have an Performance O(n²)

http://en.wikipedia.org/wiki/Bubble_sort

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文