【问题标题】:Sort an array which is sorted in a different way对以不同方式排序的数组进行排序
【发布时间】:2015-08-31 10:10:41
【问题描述】:

我有一个类型为 (int, char) 的元组数组。它按字典顺序排序:

[(0, 'a'), (0, 'b'), (0, 'c'), (1, 'a'), (1, 'b'), (1, 'c') ...]

我需要先按第二个元素再按第一个元素排序:

[(0, 'a'), (1, 'a'), ..., (0, 'b'), (1, 'b'), ..., (0, 'c'), (1, 'c'), ...]

哪种排序算法最适合这种情况?

【问题讨论】:

  • 您能详细说明一下要求吗? (例如非常快,无论如何)数字和字符集的性质? (例如,它们是固定大小且连续的吗?)

标签: algorithm sorting


【解决方案1】:

简答:只需stable-sortsecond element 即可完成。

更长的答案:
使用stable 排序算法,首先按您的first element 排序,然后按您的second element

stable sorting 保证相等的元素保持相同的顺序。

但是,如果您的输入已经按您的first element 排序,那么您不必再次对其进行排序。只需按您的second element 对其进行稳定排序,您就完成了。

最著名的稳定排序算法很可能是MergeSort

【讨论】:

  • +1 根据 Lazin 所说的“字典顺序”,元组可能已经按照第一个元素排序。在这种情况下,只需要第二个排序,是的,需要一个稳定的排序。当然,我不知道这是否比仅仅定义一个新订单和使用任何旧算法更有价值。
  • @Patrick87:就目前的答案而言,它绝对不会给您带来任何好处-您要排序两次,一次是针对first,然后是针对second 元素。如果您只按第二个元素排序,您可能会节省一点(因为 OP 说它已经在开始时按第一个元素排序)。在实践中,这可能会对您有所帮助(如果您保证输入按字典顺序排序)。拥有自定义订单(因此是通用解决方案)的开销是一个常数因子(2),因此,渐近地说,仅按第二个元素排序不会给您带来任何好处。
  • @Patrick87 当然,当它已经按first element 排序时,就不必再做一次了。我编辑了我的答案。许多像 MergeSort 这样的“旧”算法是稳定的。作为一个稳定的排序算法,这并不是什么“特别”或“新”的东西。 :)
  • 我想过没有合并阶段的合并排序(因为数组已经合并)。当然,这将根据需要起作用。
  • 您在理解排序的工作原理时遇到了根本性的错误。 MergeSort 中的所有排序都是在合并阶段完成的。没有合并阶段的 MergeSort 根本没有意义。您使用的数组或列表等有序数据结构并不重要。这与 alg 本身无关。除此之外,我不建议您自己实施。只需在您的库中使用现有的稳定排序,例如 stable_sort()
【解决方案2】:

渐近地,无论您是否以不同的方式对其进行排序都没有区别。因此,如果您不关心常数因子,您可以使用任何您喜欢的排序算法。这项任务重要的不是您使用哪个算法,而是如何应用它。所以为了这个例子(在 C++ 中,我猜其他语言会提供类似的东西),我们将只使用 sort() 中提供的 <algorithm>

为了明确说明:

//the tuple
struct intChar{
    int i;
    char c;
};

//define how our struct evaluates under '<'
bool operator<(const intChar &lhs, const intChar &rhs){
    if(lhs.c == rhs.c){
        return lhs.i < rhs.i;
    }
    return lhs.c < rhs.c;
}

这里我们说我们只想按照int排序,如果字符相同的话。否则按char 排序。

那么你可以只使用常规排序算法:http://www.cplusplus.com/reference/algorithm/sort/ 即:

#include <algorithm>

vector<intChar> toSort;

/*... fill vector ...*/
sort(toSort.begin(), toSort.end());

注意:您实际上可以定义其他比较并将要使用的比较方法传递给排序方法。这里我们只是重载了&lt;

现在,如果您关心性能并想挤出最后一点,正如其他解决方案中所建议的那样,您应该在第二个条目上使用稳定排序。但是,上述解决方案的好处是它也适用于完全无序的数组。如果您不需要通用解决方案并希望减少开销并从您获得的有关输入的信息中获利,则可以删除该部分:

if(lhs.c == rhs.c){
    return lhs.i < rhs.i;
}

然后使用stable_sort() 而不是sort()。这将为您节省一个常数因子,正如我在一开始所说的那样,在任何情况下,它对于 O(n*log(n)) 的渐近运行时都没有任何区别。

【讨论】:

    【解决方案3】:

    一个简单的方法是:

    1. 创建一个集合,将元组元素放在一起,但“反转”:{1,'a'} => "a1" (根据具体情况,您可能需要允许插入合适的空格和/或零,例如 {1,'a'} => "a01" 如果字符始终为单个但数字可能有两位数)。

    2. 排序

    3. 再次解压。

    打包/解包步骤是O(n),排序是决定性能的步骤:O(nLogn)

    【讨论】:

      猜你喜欢
      • 2019-06-24
      • 2023-02-24
      • 1970-01-01
      • 2015-05-16
      • 1970-01-01
      • 1970-01-01
      • 2016-07-12
      • 2012-04-12
      • 2016-01-02
      相关资源
      最近更新 更多