为什么排序功能会更改相同值的顺序?

时间:2018-12-01 15:14:10

标签: c++ sorting programming-languages

我的向量类型为std::vector<std::pair<int, std::string>>。我只是想按降序排列(通过使用std::pair对象的第一个int值),同时保持它的稳定,以便按插入顺序保留相等的数字。

Fe:
如果我有 :。 5,3a,4,3b,6
我希望将其排序:6,5,4,3a,3b

但是它似乎无法正常工作。排序功能按升序对其进行排序。所以我想做的是排序,然后以相反的顺序进行处理。但是后来我又得到了相反的值,这很不稳定,对我也不好。因此,我尝试先反转整个向量,然后再对其进行排序,然后以相反的顺序进行处理,但我不知道为什么它不起作用? 看起来即使我先反转向量,排序函数也会按插入顺序更改它。

无论如何,我如何实现自己的目标。递减的向量,同时保持其稳定。

编辑:对所有说使用稳定排序的人。这也无济于事。我尝试过这个。我的问题不只是稳定的顺序,而是递减的顺序并且稳定。他们中没有一个能做到这一点。

2 个答案:

答案 0 :(得分:5)

  

std::sort

     

按升序对[first,last)范围内的元素进行排序。   相等元素的顺序不能保证得到保留。

因此,相等元素的顺序可能会或可能不会更改。您正在寻找的是std::stable_sort

  

按升序对[first,last)范围内的元素进行排序。   保证保留等效元素的顺序。

如果要对向量进行降序稳定排序,则可以选择使用rbeginrend。顺序将相反;这是一个示例实现:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

class A {
 public:
  A(int d = 0, const std::string& n = "a"): data(d), name(n) {}
  friend bool operator< (const A& par1, const A& par2) {
    return par1.data < par2.data;
  }
  A& operator= (const A& other) {
    data = other.getData();
    name = other.getName();
    return *this;
  }
  std::string getName() const {
    return name;
  }

  int getData() const {
    return data;
  }

 private:
  int data = 0;
  std::string name;
};

int main()
{
  A a(7, "a"), b(2, "b"), c(3, "c"), d(2, "d"), e(3, "e"), f(6, "f");
  std::vector<A> iv {a, b, c, d, e, f};
  std::stable_sort(iv.rbegin(), iv.rend());

  for (const auto e : iv) {
    std::cout << e.getName() << " ";
  }

  std::cout << std::endl;
  return 0;
}

输出:

a f c e b d 

可以看出,相同元素的顺序被保留,向量以相反的顺序排序。

另一个选择是使用std::greater。它在<functional>标头中定义,您将需要operator>。这是一个示例实现:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>


class A {
 public:
  A(int d = 0, const std::string& n = "a"): data(d), name(n) {}
  friend bool operator< (const A& par1, const A& par2) {
    return par1.data < par2.data;
  }
  friend bool operator> (const A& par1, const A& par2) {
    return par1.data > par2.data;
  }
  A& operator= (const A& other) {
    data = other.getData();
    name = other.getName();
    return *this;
  }
  std::string getName() const {
    return name;
  }

  int getData() const {
    return data;
  }

 private:
  int data = 0;
  std::string name;
};

int main()
{
  A a(7, "a"), b(2, "b"), c(3, "c"), d(2, "d"), e(3, "e"), f(6, "f");
  std::vector<A> iv {a, b, c, d, e, f};
  std::stable_sort(iv.begin(), iv.end(), std::greater<A>());

  for (const auto e : iv) {
    std::cout << e.getName() << " ";
  }
  std::cout << std::endl;
  return 0;
}

输出:

a f c e b d 

编辑:

如果您要基于第一个元素对std::vector<std::pair<int, std::string>>类型的对象进行反向和稳定排序(如此处所示),则可以使用lambda

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <utility>
#include <functional>

using pis = std::pair<int, std::string>;


int main()
{
  pis a{5, "a"}, b{3, "b"}, c{4, "c"}, d{3, "d"}, e{3, "e"};
  std::vector<pis> iv {a, b, c, d, e};
  std::stable_sort(iv.begin(), iv.end(), [](const pis p1, const pis p2) {return p1.first > p2.first;});




  for (const auto e : iv) {
    std::cout << e.second << "(" << e.first << ")" << " ";
  }
  std::cout << std::endl;
  return 0;
}

输出:

a(5) c(4) b(3) d(3) e(3) 

要点
1.请注意,pisstd::pair<int, std::string>的{​​{3}}
2.在lambda中使用>代替<是导致向量反转的原因。

答案 1 :(得分:3)

  

为什么排序功能会更改相同值的顺序?

因为std::sort()的{​​{3}}这样说:

  

按升序对[first,last)范围内的元素进行排序。 不能保证相等元素的顺序被保留。

重点是我的。如果您需要保留订单,请使用documentation

  

按升序对[first,last)范围内的元素进行排序。 保证等同元素的顺序得到保留。

注意:

  

Sort函数按升序对其进行排序。所以我想做的是排序,然后以相反的顺序进行处理。

这是一种错误的方法-您放空顺序不是因为std::stable_sort()“不起作用”,而是因为您在排序之后反转了向量,只需使用std::stable_sort()即可接受自定义比较器并提供一个(最佳)使用lambda的选项),以降序对其进行排序。然后std::stable_sort()将保留相等元素的顺序,并且您无需反转向量。