使用第二个字段排序时,qsort是否会保留原始订单?

时间:2017-06-16 17:09:57

标签: c qsort

假设您有一系列城市名称。与每个城市相关的是一个州。在构建列表时,您希望按城市名称按字母顺序对其进行排序。列表完成后,您希望按状态对其进行排序。我的问题是,一旦按州名称排序,特定州的城市是否仍按字母顺序排列?或者是否需要使用每个州的城市名单?还是有另一种方法可以做到这一点吗?

3 个答案:

答案 0 :(得分:4)

  

...一旦按州名称排序,特定州的城市是否仍然按字母顺序排列?

没有。 qsort()不一定是stable。当元素彼此相等时,顺序可能会改变。

  

或者还有另一种方法吗?

避免从比较函数返回0。 @Weather Vane

int fcmp_by_state_then_by_city(const void *a, const void *b) {
  const geo *ga = a; // assume array of geo
  const geo *gb = b; 
  int cmp = strcmp(ga->state, gb->state);
  if (cmp) return cmp;

  return strcmp(ga->city, gb->city);
}

int fcmp_by_city_then_by_state(void *a, void *b) {
  // like above with strcmp(ga->city, gb->city) first
}

一种简单的方法是将另一个成员添加到提供规范顺序的geo类型 - 最终的打破平局 - 这可能是原始数组中元素的原始索引。另一种方法是创建一个指向数组元素的指针数组,并使用指向原始数组的指针进行排序,使用该第二级指针作为决胜局。

int fcmp_by_state_then_by_index(const void *a, const void *b) {
  const geo *ga = a; // assume array of geo
  const geo *gb = b; 
  int cmp = strcmp(ga->state, gb->state);
  if (cmp) return cmp;
  return (ga->index > gb->index) - (ga->index < gb->index)
}

使用地址a,b作为最终的决胜局并不一定有效。 @chqrlie

  

如果两个元素相等,那么它们在生成的排序数组中的顺序是未指定的   C11§7.22.5.24

@Oliver Charlesworth

答案 1 :(得分:3)

不,qsort不一定是stable sort *

听起来你需要定义一个词典比较器 - 比如你的比较器首先比较状态,然后只有状态相等才比较城市。

  • 来自C99标准:
  

[7.20.5.2] 如果两个元素相等,那么它们在生成的排序数组中的顺序是未指定的。

答案 2 :(得分:0)

qsort本身不需要稳定,并且在许多实现中都不是,尤其是在使用快速排序算法实现时。

这是解决此问题的简单方法:如果您的系统有mergesort(),则此函数使用与qsort()相同的API实现稳定排序。

否则,您可以借用合并排序的实现并使用它。