【问题标题】:Preferred Sorting For People Based On Their Age基于年龄的人的首选排序
【发布时间】:2017-01-25 09:43:30
【问题描述】:

假设我们有一个对象“Person”的 100 万个条目,其中包含两个字段“姓名”和“年龄”。问题是根据人的“年龄”对条目进行排序。

我在一次采访中被问到这个问题。我回答说我们可以使用数组来存储对象并使用快速排序,因为这样可以避免我们使用额外的空间,但面试官告诉我们内存不是一个因素。

我的问题是决定使用哪种类型的因素是什么?

另外,存储它的首选方式是什么?

在这种情况下,任何排序算法是否都比另一种排序算法具有优势并且会导致更好的复杂性?

【问题讨论】:

  • 通常在这样的面试问题中,你的“问题”比你的答案更重要。例如,所有年龄都是整数吗?年龄可以取的值范围是多少?内存的限制是什么?数据多久被查询或更新一次?提示:可能有桶排序或计数排序。
  • 由于年龄将在 0 - 120 的范围内(或者甚至 150),您可以使用计数排序更快地做到这一点。
  • @greybeard 如果Name 是固定长度的,您可能会使用基数排序,否则首先使用任何基于比较的排序并将其传递给计数排序算法。由于它是稳定的,您的订单将被保留。
  • @greybeard 我从未肯定计数排序可以做到这一点,请再次阅读我的评论。我建议先按姓名排序,然后按年龄排序(使用计数排序)。如果你也想知道这两个步骤的“方法”,你可以很容易地用谷歌搜索。
  • @greybeard 你拉到那里的绝技,删除了所有以前的 cmets。如果你一直都知道方法,那你为什么不解释呢?吹嘘你的经历是没有意义的,如果在一天结束时,你无法帮助 OP 或任何阅读此主题的人。

标签: algorithm sorting


【解决方案1】:

This Stackoverflow 链接可能对你有用。

上面的答案已经足够了,但我想从上面的链接中添加更多信息。

我正在从上面的链接中的答案中复制一些信息。

我们应该注意,即使 Object 中的字段非常大(即长名称),您也不需要使用文件系统排序,您可以使用内存排序,因为

# elements * 8 ~= 762 MB (most modern systems have enough memory for that)
             ^
        key(age) + pointer to struct requires 8 bytes in 32 bits system

尽量减少磁盘访问很重要 - 因为磁盘不是随机访问,而且磁盘访问比 RAM 访问慢得多。

现在,使用您的选择 - 并避免在排序过程中使用磁盘。

这种情况下(在 RAM 上)的一些可能性是:

  • 标准快速排序或合并排序(您已经想到了)
  • Bucket sort 也可以在这里应用,因为愤怒被限制在 [0,150] (其他人在这里以名称计数排序)
  • Radix sort(出于同样的原因,基数排序需要 ceil(log_2(150)) ~= 8 次迭代

我想指出内存方面,以防您可能遇到相同的问题,但可能需要考虑内存限制来回答它。事实上,你的约束甚至更少(10^6 与另一个问题中的 10^8 相比)。

至于存放的事情——

最快的排序方法是分配 151 个链表/向量(我们称它们为桶或任何你喜欢的语言)并根据每个人的年龄将每个人的数据结构放入桶中(所有人的年龄都在 0 到 150 之间):

bucket[person->age].add(person)

正如其他人指出的那样,桶排序将是您更好的选择。

事实上,桶排序的美妙之处在于,如果您必须对年龄范围(例如 10 到 50 岁)执行任何操作,您可以根据您的要求划分您的桶大小(例如有不同的每个桶的桶范围)。

我再重复一遍,我已经从上面给出的链接中的答案中复制了信息,但我相信它们可能对你有用。

【讨论】:

    【解决方案2】:

    如果数组有 n 个元素,那么快速排序(或者实际上是任何基于比较的排序)是Ω(n log(n))

    不过,在这里,您似乎可以替代基于比较的排序,因为您只需要按年龄排序。假设有 m 个不同的年龄。在这种情况下,Counting Sort 将是 Θ(m + n)。对于您的问题的具体情况,假设年龄以年为单位,m 远小于 n,您可以在线性时间内做到这一点。

    实现很简单。只需创建一个包含 200 个条目的数组(200 是年龄的上限)。该数组是链表。扫描人员,并将每个人放在链表中的相应条目中。现在,只需根据数组中的位置连接列表即可。

    【讨论】:

      【解决方案3】:

      不同的排序算法执行不同的复杂性,是的。有些使用不同数量的空间。在实践中,具有相同复杂性的实际性能也会有所不同。 http://www.cprogramming.com/tutorial/computersciencetheory/sortcomp.html

      有不同的方法来设置快速排序的分区方法,这些方法可能会影响很长时间。 Shell 排序可以有不同的间隙设置,这些设置对于某些类型的输入表现更好。但也许你的面试官更感兴趣的是你考虑 100 万人有很多重复的年龄;这可能意味着您需要 3 路快速排序,或者按照 cmets 中的建议进行计数排序。

      【讨论】:

        【解决方案4】:

        这是一道面试题,所以我猜被面试者的回答比正确的排序算法更重要。您的问题是对 Object 的数组进行排序,其中字段年龄是整数。年龄有一些特殊的属性:

        1. 整数:有一些专门为整数设计的排序算法。
        2. 有限:你知道人的最大年龄,对吧?例如,这将是 200。

        我将列出一些针对这个问题的排序算法,其优点和缺点足以在一次面试中进行:

        1. 快速排序:复杂度为 O(NLogN),可应用于任何数据集。快速排序是在两个元素之间使用比较运算符的最快排序。快速排序的最大缺点是快速排序不稳定。这意味着两个年龄相等的对象在排序后不会保持顺序。

        2. 归并排序:复杂度为 O(NLogN)。比快速排序慢一点,但这是一种稳定的排序。该算法也可以应用于任何数据集。

        3. 基数排序:复杂度为 O(w*n),其中 n 是列表的大小,w 是列表中位数的最大长度数据集。例如:12的长度是3,154的长度是3。所以如果人的最大年龄是99,复杂度应该是O(2*n)。该算法只适用于整数或字符串。

        4. 计数排序复杂度为O(m+n)。 n 是列表的大小,m 是不同年龄的数量。该算法只适用于整数。

        因为我们正在对数百万个条目进行排序,并且所有值都是整数,位于0 .. 200 范围内,因此存在大量重复值。所以计数排序最适合复杂度O(200 + N),N ~= 1,000,000。 200不算多。

        【讨论】:

          【解决方案5】:

          如果您假设您有有限数量的不同年龄值(通常人们不超过 100 岁),那么您可以使用 计数排序 (https://en.wikipedia.org/wiki/Counting_sort)。您将能够按线性时间排序。

          【讨论】:

          • 请解释如何使用two fields 'Name', 'Age' 进行计数排序 - 如果对象一开始就按名称排序,您可以进行稳定排序吗?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-06-28
          • 2017-07-31
          • 2020-05-27
          • 2022-11-23
          • 1970-01-01
          • 2015-05-22
          相关资源
          最近更新 更多