Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对一个容器进行多次排序,使用哪种容器和哪种方法_C++_Sorting_Vector_Containers - Fatal编程技术网

C++ 对一个容器进行多次排序,使用哪种容器和哪种方法

C++ 对一个容器进行多次排序,使用哪种容器和哪种方法,c++,sorting,vector,containers,C++,Sorting,Vector,Containers,我有一些数据需要打印,为了简单起见,让我们假设它是一个容器(向量),其中包含一些参数。在程序的不同部分,我需要打印所有按不同参数排序的文件。我的问题是 1.)选择哪个容器?(我个人选择了vector) 2.)什么方法更好,每次对整个向量进行排序,还是最好复制该向量并将其保存排序?在我的解决方案中,我每次都对同一个向量进行排序,但由于速度的原因,这可能不是一个正确的方法 class Person { private: std::string name; std::string su

我有一些数据需要打印,为了简单起见,让我们假设它是一个容器(向量),其中包含一些参数。在程序的不同部分,我需要打印所有按不同参数排序的文件。我的问题是

1.)选择哪个容器?(我个人选择了vector)

2.)什么方法更好,每次对整个向量进行排序,还是最好复制该向量并将其保存排序?在我的解决方案中,我每次都对同一个向量进行排序,但由于速度的原因,这可能不是一个正确的方法

class Person
{
private:
    std::string name;
    std::string surname;
    int age;
public:
    Person(std::string name, std::string surname, int age) : name{ name }, surname{ surname }, age{ age } {};
    void print() { std::cout << name << " " << surname << " " << age << std::endl; };
    static bool sortName(Person const &A, Person const &B) { return A.name < B.name; };
    static bool sortSurname(Person const &A, Person const &B) { return A.surname < B.surname; };
    static bool sortAge(Person const &A, Person const &B) { return A.age < B.age; };
};
班级人员
{
私人:
std::字符串名;
std::字符串姓氏;
智力年龄;
公众:
Person(std::string name,std::string姓氏,int-age):姓名{name},姓氏{姓氏},年龄{age}{};

作废打印(){std::coutIMO,您现在使用的方法很好,即在运行时需要时进行排序。对于较大的数据集,您需要首先评估内存和处理能力方面的需求。例如,对于非常大的数据集,您将无法在内存中对其进行排序。并且,在y情况下会出现同步问题您决定采用多线程解决方案。因此,您需要一些专门的解决方案,如DBMS,您可以在运行时根据需要查询已排序的数据。您将拥有索引等功能来优化查询时间。

在许多解决方案中,这主要取决于3个因素-
1.数据大小
2.你在看什么样的表演
3.可以用#2交换的空间(内存)量

通常,
std::sort()
在nlogn-

平均复杂度,第一次和第二次之间的距离为线性 最后:执行大约N*log2(N)(其中N是该距离) 元素的比较,以及多达那么多的元素交换(或移动)

现在,如果您的用例涉及到太多调用的排序方法,预排序和保存向量可能是有意义的——在这种情况下,您将获得相当大的性能增益。现在,在这个设计中,你必须对集合“强”>可修改的< /强>进行判断吗?如果是,那么多久?那么你必须考虑AVG案例。演出成功


因此,总之,它取决于

而不是对象的排序向量(对于具有多个字段的复杂对象来说,这相当昂贵),您应该为存储在主向量中的对象构建多个索引向量,并根据各种条件对其排序

#include <algorithm>
...

::std::vector< Person > persons;
//  add persons...

::std::vector< ::std::size_t > sorted_indexes;
sorted_indexes.reserve(persons.size());
{
    ::std::size_t index{};
    ::std::generate
    (
        sorted_indexes.begin()
    ,   sorted_indexes.end()
    ,   [&index]{return index++;}
    );
}
::std::sort
(
    sorted_indexes.begin()
,   sorted_indexes.end()
,   [&persons](::std::size_t const left, ::std::size_t const right)
    {
        return Person::sortSurname(persons[left], persons[right]);
    }
);
for(auto person_index: sorted_indexes)
{
    persons[person_index].print();
}
#包括
...
:std::vectorPerson;
//添加人员。。。
::std::vector<::std::size\u t>已排序的索引;
已排序的索引.reserve(persons.size());
{
::std::大小索引{};
::std::生成
(
已排序的索引。begin()
,已排序的索引。end()
,[&index]{return index++;}
);
}
::std::排序
(
已排序的索引。begin()
,已排序的索引。end()
,[&人](::标准::大小常数左,::标准::大小常数右)
{
返回人::sortSurname(人[左]、人[右]);
}
);
for(自动人员索引:已排序的索引)
{
人员[人员索引].print();
}
此外,sortSurname应采用常量引用以避免复制:

static bool sortSurname(Person const & left, Person const & right) { return left.surname < right.surname; };
static bool-sortSurname(Person-const&left,Person-const&right){return left.name
如果向量很小或元素复制成本很低,您可以在需要时对其重新排序,而不会出现任何问题

如果向量的元素较大且复制成本较高,则可以按需要的方式对向量进行一次排序,然后创建第二个s向量并以不同的方式进行排序,以创建原始向量的第二个“视图”,该视图既不会修改原始向量,也不会将元素复制到第二个向量

至于容器选择,只需使用
std::vector
,除非您特别需要其他容器的某些特殊属性


在任何情况下,在设置不同的解决方案之前,对不同的解决方案进行基准测试(使用优化的构建),并测量不同解决方案的性能。

boost::multi_index_container
允许您定义具有任意数量的不同索引或视图的任何类型的容器

在插入和删除索引时,容器会自动使索引保持最新

这是一个庞大的模板库,需要一点时间来适应,但是文档很好,有很多示例

下面是一个以这种方式表示的实现:

#include <iostream>
#include <string>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/mem_fun.hpp>

class Person {
private:
    std::string name;
    std::string surname;
    int age;
public:
    Person(std::string name, std::string surname, int age) : name{name}, surname{surname}, age{age} {};

    auto get_name() const -> const std::string& { return name; }
    auto get_surname() const -> const std::string& { return surname; }
    auto get_age() const -> int { return age; }

    void print() const { std::cout << name << " " << surname << " " << age << std::endl; };
};

namespace bmi = boost::multi_index;

struct by_name {};
struct by_surname {};
struct by_age;
using PersonTable = boost::multi_index_container<Person,
        bmi::indexed_by<
                bmi::ordered_non_unique<bmi::tag<by_name>, bmi::const_mem_fun<Person,std::string const&,&Person::get_name>>,
                bmi::ordered_non_unique<bmi::tag<by_surname>, bmi::const_mem_fun<Person,std::string const&,&Person::get_surname>>,
                bmi::ordered_non_unique<bmi::tag<by_age>, bmi::const_mem_fun<Person,int,&Person::get_age>>
        >
>;

int main()
{
    PersonTable people;
    people.insert(Person("John", "Smith", 30));
    people.insert(Person("Mark", "Cooper", 28));
    people.insert(Person("George", "Orwell", 19));

    std::cout << "by name" << std::endl;
    for (auto&& person : people.get<by_name>())
    {
        person.print();
    }
    std::cout << "\nby surname" << std::endl;
    for (auto&& person : people.get<by_surname>())
    {
        person.print();
    }
    std::cout << "\nby age" << std::endl;
    for (auto&& person : people.get<by_age>())
    {
        person.print();
    }
}

此处的文档:

我将使用3个
std::set
实例,每个实例按
std::shared\u ptr
人员的相应字段排序:

int main()
{
    std::shared_ptr<Person> person1 = std::make_shared<Person>("John", "Smith", 30);
    std::shared_ptr<Person> person2 = std::make_shared<Person>("Mark", "Cooper", 28);
    std::shared_ptr<Person> person3 = std::make_shared<Person>("George", "Orwell", 19);

    std::set<std::shared_ptr<Person>> persons1([](std::shared_ptr<Person> a, std::shared_ptr<Person> b) {
        return a->name < b->name;
    });
    std::set<std::shared_ptr<Person>> persons2([](std::shared_ptr<Person> a, std::shared_ptr<Person> b) {
        return a->surname < b->surname;
    });
    std::set<std::shared_ptr<Person>> persons3([](std::shared_ptr<Person> a, std::shared_ptr<Person> b) {
        return a->age < b->age;
    });

    persons1.insert(person1);
    persons1.insert(person2);
    persons1.insert(person3);

    persons2.insert(person1);
    persons2.insert(person2);
    persons2.insert(person3);

    persons3.insert(person1);
    persons3.insert(person2);
    persons3.insert(person3);

    return 0;
}
intmain()
{
std::shared_ptr person1=std::make_shared(“约翰”,“史密斯”,30岁);
std::shared_ptr person2=std::make_shared(“马克”,“库珀”,28);
std::shared_ptr person3=std::make_shared(“乔治”、“奥威尔”,19);
std::set persons1([](std::shared_ptr a,std::shared_ptr b){
返回a->namename;
});
std::set persons2([](std::shared_ptr a,std::shared_ptr b){
返回a->姓氏姓氏;
});
std::set persons3([](std::shared_ptr a,std::shared_ptr b){
返回a->ageage;
});
人员1.插入(人员1);
人员1.插入(人员2);
人员1.插入(人员3);
人员2.插入(人员1);
人员2.插入(人员2);
人员2.插入(人员3);
人员3.插入(人员1);
人员3.插入(人员2);
人员3.插入(人员3);
返回0;
}
  • 通过使用
    std::shared_ptr
    存储时不会浪费内存 多个容器中的对象
  • std::set
    已对容器进行排序,因此您无需排序 每次使用它时,只需从头到尾枚举元素 结束

考虑用指向Person的指针的向量替换Person的向量。有了它,只需交换两个人就可以了
by name
George Orwell 19
John Smith 30
Mark Cooper 28

by surname
Mark Cooper 28
George Orwell 19
John Smith 30

by age
George Orwell 19
Mark Cooper 28
John Smith 30
int main()
{
    std::shared_ptr<Person> person1 = std::make_shared<Person>("John", "Smith", 30);
    std::shared_ptr<Person> person2 = std::make_shared<Person>("Mark", "Cooper", 28);
    std::shared_ptr<Person> person3 = std::make_shared<Person>("George", "Orwell", 19);

    std::set<std::shared_ptr<Person>> persons1([](std::shared_ptr<Person> a, std::shared_ptr<Person> b) {
        return a->name < b->name;
    });
    std::set<std::shared_ptr<Person>> persons2([](std::shared_ptr<Person> a, std::shared_ptr<Person> b) {
        return a->surname < b->surname;
    });
    std::set<std::shared_ptr<Person>> persons3([](std::shared_ptr<Person> a, std::shared_ptr<Person> b) {
        return a->age < b->age;
    });

    persons1.insert(person1);
    persons1.insert(person2);
    persons1.insert(person3);

    persons2.insert(person1);
    persons2.insert(person2);
    persons2.insert(person3);

    persons3.insert(person1);
    persons3.insert(person2);
    persons3.insert(person3);

    return 0;
}