【问题标题】:Unsorting a sorted array and preserving the original order of the array elements in C取消排序的数组并保留 C 中数组元素的原始顺序
【发布时间】:2017-06-29 20:39:32
【问题描述】:

我有我的初始数组(允许随机或重复),首先需要对其进行排序,然后需要将排序后的数组重新排序为原始数组,并保留顺序。

Ex:
    orig_array: char[512] = { 1, 2, 4, 1,3,5,a,b,c,........}

    Sorted array: char[512] = { 1, 1, 2,2,3.....)  ( using sorting algorithms )

    Unsorting back to original order: { 1, 2,4,1,3,......}

我被困在如何将取消排序返回到它们创建的原始顺序的路上。

我为什么要问的一些背景:

对数组进行排序完全在不同的系统上完成。排序后的数组被发送到网络并被主机接收。必须保留原始数据。

我在两端都有一个压缩模块来压缩和解压缩数据。压缩模块是 CPU 昂贵的。我的想法是对排序的数据序列进行压缩不应该消耗太多 CPU,并且应该非常快地在两端加密和解密,从而减少整体延迟

【问题讨论】:

  • 对数组的副本进行排序
  • 一个有趣的问题。
  • 一种有趣的方法是,在排序过程中,跟踪您所做的每个元素移动/交换。然后当你完成后,按照这个过程倒退。 :)
  • 变得更有趣了 :) 你想加密网络流量吗?它看起来像一个疯狂的 XY 问题。
  • 测量它。压缩速度显着提高的机会很小,除非数据集很小,否则撤消排序的成本会很大。压缩未排序的数据并将其发送,您可以节省排序和取消排序的时间。

标签: c algorithm sorting data-structures


【解决方案1】:

如果您对"in-place" 进行排序 - 即对实际数组中的元素重新排序,则无法取消排序。对不起。

您可以改为“异地”排序,或对指向数组中元素的指针数组进行排序(使用数组数据进行比较) - 保持原始数组不变。

另见:In-place algorithms 维基百科

【讨论】:

  • 您可以通过跟踪排序排列来提供反转就地排序。当然,这需要一种能够合作的排序算法。例如,除了要排序的数据之外,您还创建了一个并行索引数组,最初的顺序是从 0 到 n。每次排序移动数据的一个元素时,它都会在索引数组中执行相应的移动。由于最终的索引数组跟踪每个元素的去向,您可以使用它来反转排序。
  • @JohnBollinger:很公平,+1,但看起来 OP 并没有跟踪排序排列。
【解决方案2】:

如果不保留其他数据,您将无法反转排序。一种简单的方法是按原始顺序保留数据的副本,例如通过执行异地排序。这既快速又简单,但不是唯一的选择。

您可以提供用于反转过程的另一种方法(每个@lurker)是按照执行顺序列出对数组执行的更改(交换/排列),并通过向后遍历来进行反转列出并反转每个单独的步骤。这相当简单,大约与原始排序一样快,但在平均情况下,它需要更多的内存,而不是仅仅保留一份副本。

还有一种方法是跟踪排序执行的元素排列。您可以通过创建一个元素索引的辅助数组来做到这一点,每个要排序的元素一个,最初是按顺序排列的。随着排序的进行,它会将每个元素的移动与辅助数组中的相应移动进行镜像。排序完成后,辅助数组会告诉您每个元素的 original 索引是什么,您可以使用该信息将元素返回到原始顺序。这样的内存效率不亚于保留原始数据的副本,并且可以在线性时间内执行顺序恢复。

或者,您可以完全避免对原始数据进行排序。如果您改为对指向数据的指针数组或数据的索引进行排序,那么您可以在不丢失原始顺序的情况下找到排序顺序。

【讨论】:

    【解决方案3】:

    您说您想要排序和取消排序是因为数据需要在通过网络发送之前进行压缩(这需要时间),并且压缩已排序的数据“应该”比压缩未排序的数据更快。

    这听起来像是过早优化的情况。 “应该”更快听起来像是猜测。您应该测试压缩排序的数据与压缩未排序的数据,看看是否有任何区别。您还需要考虑排序和未排序的时间。很有可能,排序的成本会比压缩排序列表的任何可能收益高得多。

    即使您发现压缩排序的数据更快,也可能无关紧要。

    这是取消排序的问题。

    暂时忘记软件。假设我给你以下排序列表:

    2 7 9 10 15 18 19 20 26 29

    现在取消排序。

    你会怎么做?没有任何附加信息,就无法知道“正确”的顺序是什么。它很可能一开始就已经排序,在这种情况下它已经“未排序”。

    至少,您需要知道列表未排序时每个值的位置。因此,如果未排序的列表如下所示:

    10 9 26 29 18 2 20 7 19 15

    您需要另一个列表,给出排序列表中每个值的原始索引:

    5 7 1 0 9 4 8 6 2 3

    但是现在您有两个数字列表,因此您需要压缩和发送的数据大小增加了一倍。最重要的是,其中一个列表是未排序的。所以你又回到了你开始的地方。

    获得任何东西的唯一可能方法是,如果原始列表中的项目不仅是数字,而且是大型聚合数据类型,因此索引列表与原始列表相比要小。在这种情况下,您可以将原始列表索引添加到数据类型以简化对其的跟踪。然后,您将不得不再次测试压缩排序列表是否比未排序列表快。但同样,压缩排序列表更快的可能性很小,如果列表包含复杂的数据类型,则更是如此。

    我的建议:压缩并发送未排序的列表。

    【讨论】:

      【解决方案4】:

      您可以在排序之前创建原始数组的副本,也可以创建另一个指针数组并对指针进行排序... 内存不是问题,时间是的,不要再浪费时间去寻找不存在的神奇功能了……

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-12
        • 2021-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多