【问题标题】:How to know if an array is sorted?如何知道数组是否已排序?
【发布时间】:2012-11-11 04:49:30
【问题描述】:

我已经阅读了这篇文章,但答案并不让我满意Check if Array is sorted in Log(N)

假设我有一个超过 1,000,000 个double 数字(正数和/或负数)的大型数组,我想知道数组是否“排序”以避免最大比较次数因为比较双精度和浮点数需要太多时间。是否可以对它使用统计数据?如果它是:

  1. 真正的程序员看得见?
  2. 我应该取样吗?
  3. 我应该采集多少个样本
  4. 它们应该是随机的还是按顺序排列的?
  5. %error 允许说多少 "the array sorted"

谢谢。

【问题讨论】:

  • 这可能更适合cstheory.stackexchange.com
  • 嗯,它是 O(n) 并且您链接到的答案很好。你真正需要了解的是为什么这个答案不能让你满意。问题不是答案。

标签: c arrays algorithm sorting statistics


【解决方案1】:

决定数组是否排序的最大比较次数是N-1,因为有N-1个相邻的数对要比较。但为简单起见,我们会说 N,因为我们看 N 或 N+1 个数字并不重要。

此外,从哪里开始并不重要,所以让我们从头开始吧。 比较#1(A[0] 与 A[1])。如果失败,则数组未排序。如果成功了,很好。

由于我们只是比较,我们可以将其归约为邻居,以及左侧是否小于或等于 (1) 或不 (0)。所以我们可以把数组看成一个0和1的序列,表示两个相邻的数字是否有序。

计算错误率或概率(拼写正确?)我们必须查看 0/1 序列的所有组合。 我会这样看:我们有一个数组的 2^n 个组合(即对的顺序,其中只有一个被排序(所有元素都是 1,表示每个 A[i] 小于或等于 A[ i+1])。

现在这似乎很简单: 最初的错误是 1/2^N。在第一次比较之后,可能的组合(所有未排序)的一半被淘汰。所以错误率应该是1/2^n + 1/2^(n-1)。

我不是数学家,但计算达到错误率需要多少元素应该很容易(找到 x 使得 ERROR >= sum of 1/2^n + 1/2^(n -1)... 1/^(2-x) )

对不起,令人困惑的英语。我来自德国..

【讨论】:

  • 这是一个很好的答案,但我不认为这个问题想要满足错误率;相反,它想确定错误的可能性。无论如何+1。
  • 嗯,我刚下班回来......你是对的,并不是问题的真正答案。但是按照我的想法,还是可以确定X比较后的错误率:错误率= Sum (1/2^n + 1/2^(n-1)... 1/2^(nx))...或 x-1 左右...
  • 我会这样处理:如果所有数字 ai 都是不同的并且所有排列的概率相同,那么随机选择的对 (ai,aj) 的概率是有序的(即ai < aj ) 是1/2。现在,如果数组未排序并且您进行k 这样的配对测试,那么所有检查都正常(并且您没有检测到数组未排序)的概率是(大约)(1/2)^k。只是大约,因为一段时间后检查不再需要独立:如果您检查了ai1 < ai2ai2 < ai3,那么您应该不会惊讶地发现ai1 < ai3 成立...
  • 无论如何,对于 k (1/2)^k应该足够好。因此,为了确保您的错误率低于eps,您需要-ld(eps) 对检查。要将错误率降至 1% 以下,您需要进行 7 对检查。
【解决方案2】:

作为示例,您可能不应该使用但演示了采样大小:

统计上有效的样本量可以为您提供合理的排序估计。如果你想 95% 确定 eerything 被排序,你可以通过创建一个真正随机的采样点列表来做到这一点,可能是 ~1500。

如果值列表在一个地方乱序会破坏后续算法或数据要求,这基本上是完全没有意义的。

如果这是一个问题,请在您的代码运行之前对列表进行预处理,或者在您的代码中使用一个非常快速的排序包。大多数排序包也有一个验证模式,它只是告诉你是,列表符合你的排序标准 - 或者不。其他建议(例如使用线程并行化检查)是个好主意。

【讨论】:

    【解决方案3】:

    这是一个经典的高中概率问题。考虑this question

    批次被拒绝的概率是多少? 在 8,000 个批次中,有 7% 的时钟有缺陷。从 8,000 个样本中随机抽取 10 个样本(无替换)进行测试。如果至少有一个有缺陷,则整个批次将被拒绝。

    所以你可以从你的大数组中随机抽取一些样本,看看它是否已排序,但你必须注意,你需要知道样本乱序的概率。由于您没有这些信息,因此概率方法在这里不会有效。

    (但是,您可以检查 50% 的数组,然后天真地得出结论,它有 50% 的机会正确排序。)

    【讨论】:

    • 感谢您的回答,我没想到计算被排序的概率。
    • 如果所有数字都是不同的并且所有排列的可能性相同,那么大小为 2 的样本被排序的机会是 50%。因此,如果您随机选择 k 对并检查它们是否按预期顺序排列,则应该错误地假设未排序的数组仅以大约 (1/2)^k 的概率进行排序。
    【解决方案4】:

    老式的方式。打印出来看看是否有顺序。真的,如果你的排序是错误的,你可能很快就会看到它。如果您对 100 多件物品进行分类,则不太可能只看到一些错误。每当我处理它时,我的整个事情都完全关闭或有效。

    【讨论】:

      【解决方案5】:

      就像其他人所说的那样,100% 确定它已排序的唯一方法是遍历每个元素,即 O(N)。

      但是,在我看来,如果您非常担心它会被排序,那么开始排序可能比将数组元素存储在内存中的连续部分中更重要?

      我的意思是,您可以使用map,其元素的定义遵循strict weak ordering。换句话说,地图中的元素总是被排序的。你也可以使用set 来达到同样的效果。

      例如:std::map<int,double> collectoin; 几乎可以让您像使用数组一样使用它:collection[0]=3.0; std::cout<<collection[0]<<std:;endl;。当然存在差异,但如果排序如此重要,那么数组是存储数据的错误选择。

      【讨论】:

        【解决方案6】:

        您的问题 5 是您需要回答以确定其他答案的问题。为确保数组完美排序,您必须遍历每个元素,因为其中任何一个元素都可能不合适。

        【讨论】:

          【解决方案7】:

          如果您使用多处理(真正的并行性,因此仅适用于多核 CPU)运行分而治之算法,您可以检查数组是否在 Log(N) 中排序。

          如果您有 GPU 多处理,则可以非常轻松地实现 Log(N),因为现代显卡能够并行运行数千个进程。

          【讨论】:

          • 这不是真正的 O(Log(N)),因为您只有有限数量的处理器。
          • 你是对的,但是你大大减少了执行时间。
          • 对于 P 处理器,我能做的最好的事情是 O(N/P)。见Amdahl's law
          【解决方案8】:

          由于每一个元素都可能是一个外线元素,因此您必须遍历所有元素,因此您的算法的运行时间为 O(n)。

          如果您对“已排序”的理解不那么严格,则需要指定“已排序”的确切含义。通常,“排序”意味着相邻元素满足较少或较少或相等的条件。

          【讨论】:

            【解决方案9】:

            这取决于您的要求。如果您可以说如果 1.000.000 中的 100 个随机样本就足够了,那么假设它已排序 - 那么就是这样。但可以肯定的是,您将始终必须检查每一个条目。只有你才能回答这个问题,因为只有你知道你需要对它进行排序有多大把握。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-08-09
              • 1970-01-01
              • 2012-04-08
              • 2017-04-28
              • 2019-12-20
              • 2021-06-22
              • 2012-06-28
              • 1970-01-01
              相关资源
              最近更新 更多