C++使用多个元素对数据进行双重排序

C++ double sorting data with multiple elements

本文关键字:排序 数据 元素 C++      更新时间:2023-10-16

我有多个数据条目,其中包含以下信息:id编号名称1日期名称2

可以将其放入这样的结构中:

struct entry {
  int id_number;
  string name1;
  int date;
  string name2;
}

在我的数据中,我有很多这样的条目,我想排序。首先,我想根据名称1按字母顺序排序,然后按日期排序。然而,按日期排序是字母排序的子集,例如,如果我有两个名称相同的条目1,那么我想按日期对这些条目进行排序。此外,当我排序时,我希望条目的元素保持在一起,所以所有四个值都在一起。

我的问题如下:

1) 我应该使用什么类型的数据结构来保存这些数据,这样当我按四个元素中的任何一个进行排序时,我就可以将它们放在一起了?

2) 进行排序的最快方法是什么(就编写代码的时间而言)。理想情况下,我想在算法.h中使用类似排序的东西,因为它已经内置在中了

3) STL是否有一些内置的数据结构,可以有效地处理我所描述的双重排序?

您拥有的结构很好,只是您可能想添加operator<的重载来进行比较。在这里,我正在进行"按名称,然后按日期进行比较"比较:

// Add this as a member function to `entry`.
bool operator<(entry const &other) const {
    if (name1 < other.name1)
        return true;
    if (name1 > other.name1)
        return false;
    // otherwise name1 == other.name1
    // so we now fall through to use the next comparator.
    if (date < other.date)
        return true;
    return false;
}

[编辑:所需的被称为"严格弱排序"。如果你想详细了解这意味着什么,以及可能的替代方案,Dave Abrahams在C++Next上写了一篇相当详细的文章。

在上面的例子中,我们首先比较两者的name1字段。如果a<b,那么我们立即返回true。否则,我们检查a>b,如果是,则返回false。在这一点上,我们已经消除了a<ba>b,所以我们确定了a==b,在这种情况下,我们测试日期——如果a<b,我们返回true。否则,我们返回false——要么是日期相等,要么是b>a,这两者都意味着a<b的测试为false。如果排序需要排序(并非双关语),那么它可以在交换参数的情况下再次调用函数。名字仍然是相等的,所以它仍然会归结为日期——如果我们得到假,那么日期是相等的。如果我们在交换的日期上是真的,那么从第二个日期开始的日期实际上更大。]

您在结构中定义的operator<定义了默认情况下将使用的顺序。如果需要,您可以指定另一个排序顺序:

struct byid { 
    bool operator<(entry const &a, entry const &b) { 
        return a.id_number < b.id_number;
    }
};
std::vector<entry> entries;
// sort by name, then date
std::sort(entries.begin(), entries.end());
// sort by ID
std::sort(entries.begin(), entries.end(), byid());

那里的数据结构应该可以正常工作。您应该做的是覆盖小于运算符,然后您可以将它们全部插入到映射中,然后对它们进行排序。以下是关于地图的比较运算符的更多信息

更新:经过进一步思考,我会使用集合,而不是地图,因为不需要值。但这里有证据表明它仍然有效

证明这一点:

#include<string>
#include<map>
#include<stdio.h>
#include <sstream>

using namespace std;
struct entry {
  int m_id_number;
  string m_name1;
  int m_date;
  string m_name2;
  entry(  int id_number, string name1, int date, string name2) :
      m_id_number(id_number),
      m_name1(name1),
      m_date(date),
      m_name2(name2)
  {
  }
  // Add this as a member function to `entry`.
  bool operator<(entry const &other) const {
      if (m_name1 < other.m_name1)
          return true;
      if (m_name2 < other.m_name2)
          return true;
      if (m_date < other.m_date)
          return true;
      return false;
  }
  string toString() const
  {
      string returnValue;
      stringstream out;
      string dateAsString;
      out << m_date;
      dateAsString = out.str();
      returnValue = m_name1 + " " + m_name2 + " " + dateAsString;
      return returnValue;
  }
};

int main(int argc, char *argv[])
{
    string names1[] = {"Dave", "John", "Mark", "Chris", "Todd"};
    string names2[] = {"A", "B", "C", "D", "E", "F", "G"};
    std::map<entry, int> mymap;
    for(int x = 0; x < 100; ++x)
    {
        mymap.insert(pair<entry, int>(entry(0, names1[x%5], x, names2[x%7]), 0));
    }
    std::map<entry, int>::iterator it = mymap.begin();
    for(; it != mymap.end() ;++it)
    {
        printf("%sn ", it->first.toString().c_str());
    }
    return 0;
}

实际上,您可以使用函数对象来实现您的排序标准

假设您想将条目存储在设置的中

//EntrySortCriteria.h
class EntrySortCriteria
{
    bool operator(const entry &e1, const entry &e2) const
    {
         return e1.name1 < e2.name1 || 
                (!(e1.name1 < e2.name1) && e1.date < e2.date))
    }
}
//main.cc
#include <iostream>
#include "EntrySortCriteria.h"
using namespace std;
int main(int argc, char **argv)
{
    set<entry, EntrySortCriteria> entrySet;
    //then you can put entries into this set, 
    //they will be sorted automatically according to your criteria
    //syntax of set:
    //entrySet.insert(newEntry);
    //where newEntry is a object of your entry type    
}