C++ 适用于快速检索两个不同参数的数据结构

C++ 适用于快速检索两个不同参数的数据结构,c++,data-structures,C++,Data Structures,我有几双std::pairX是唯一的,永远不会更改,Y将定期更新。需要根据Y对这些对进行排序,但我还需要快速检索X以更新Y 到目前为止,我使用std::set获取基于Y的排序列表。但是现在更新速度很慢,我认为在最坏的情况下,我需要运行整个集合以找到正确的X。我说得对吗 是否有任何数据结构支持使用Y加上X的快速(O(logn)或更少)检索进行排序?我接受使用支持数据结构或拆分X和Y的想法 编辑: 也许举个例子可以澄清问题。假设X是一个名字,Y是月薪。所以一对可能是(“约翰”,5000)。现在我需要

我有几双
std::pair
<代码>X是唯一的,永远不会更改,
Y
将定期更新。需要根据
Y
对这些对进行排序,但我还需要快速检索
X
以更新
Y

到目前为止,我使用
std::set
获取基于
Y
的排序列表。但是现在更新速度很慢,我认为在最坏的情况下,我需要运行整个集合以找到正确的
X
。我说得对吗

是否有任何数据结构支持使用
Y
加上
X
的快速(O(logn)或更少)检索进行排序?我接受使用支持数据结构或拆分
X
Y
的想法

编辑:
也许举个例子可以澄清问题。假设X是一个名字,Y是月薪。所以一对可能是(“约翰”,5000)。现在我需要一个名单/一组按最高工资排序的人,例如[(“玛丽”,8000),(“约翰”,5000),(“克里斯”,2000)]。另外,我需要一种查找人员的方法(在O(1)或O(logn)中),这样我就可以从列表/集合中删除名称salary对,更新salary,然后将名称salary对重新插入排序后的列表/集合中。更新非常频繁。

我认为一个STL容器或一些嵌套的STL容器不能满足您的要求

但我确实认为STL容器的组合可以满足您的需求。在我的建议中,我基本上将数据存储为冗余的2倍,并使用某种ID连接它们。就像在数据库中,您可以使用一个附加的helper表构建m:n关系

请参阅下面的源代码。这只不过是一个骷髅,需要使它变得易于携带,但你可能会有这个想法

总体性能在很大程度上取决于哈希算法的单一性能。对于带有
std::unordered_map
的操作,我假设O(1),对于
std::map
的操作,假设O(logn)

次优散列当然会导致O(n)

#包括
#包括
#包括
#包括
#包括
//为便于理解,请使用一些别名
使用工资=无符号整数;
使用Name=std::string;
使用ID=size\u t;
使用name和salary=std::pair;
//符合给定需求的新数据结构
结构员工{
std::无序映射查找{};//O(1)
std::无序映射名称{};//O(1)
std::map{};//O(logn)
无效添加(姓名和编号、薪资和s){
ID newID=lookup.size();
名称[n]=newID;//O(1)
工资[s]=newID;//O(日志n)
查找[newID]={n,s};//O(1)
}
Salary getSalaryViaName(const Name&n){return lookup[names[n]].second;}//O(1)O(1)
Name getNamebySalary(const Salary&s){return lookup[salaries[s]].first;}//O(1)O(logn)
};
//一些测试代码
int main(){
雇员{};
//填充结构
添加(“John”,456);
添加(“Paul”,345);
添加(“Ringo”,234);
添加(“乔治”,123);
//迭代
对于(const auto&[salary,id]:employees.salaries)

我不确定我是否理解了你的问题,但是我想说你可以用一个集合(一棵树)来表示Y和一个映射(一个散列)对于X,因为
X
是唯一的,所以可以使用
map
。但是,由于要按
Y
对列表进行排序,因此必须将
Y
保存在可以排序的不同容器中。您可能需要将
X
和/或
Y
包装在另一个数据结构中,以便从
X
开始>对相应的
Y
(或反之亦然)执行O(1)操作。但我不确定我是否理解了您问题的所有细节。@JackLilhammers@icepp也许可以举个例子来说明问题。假设
X
是一个名称,
Y
是月薪。所以一对可以是
(“约翰,5000”)
。现在我需要一个按最高工资排序的人员列表/集合,例如
[(“玛丽”,8000),(“约翰”,5000),(“克里斯”,2000)]
。此外,我需要一种查找人员的方法(在O(1)或O(logn)中),这样我就可以从列表/集中删除姓名-薪资对,更新薪资,然后将姓名-薪资对重新插入排序后的列表/集中。@JackLilhammers@ice谢谢你的回答。我将测试这两个选项,以检查哪一个更快。很高兴知道,我需要更新
Y
s的频率比查找最大值的频率要高得多
Y
。因此,在末尾排序可能比每次更新a
Y
时排序更快。此外,如果您只需要跟踪最大的Y,您可以使用带有X的无序映射作为键,并使用最大的Y保存X。这将使访问、插入和提升最大Y的复杂性为O(1),但O(n)用于删除或降低当前最大Y。此结构的实际性能将在很大程度上取决于您的用例。如果很少减少或删除最大Y,则摊销复杂性将为O(1)如何更新一个人的工资?例如,Paul加薪到500。我还有一个问题。非唯一工资会发生什么情况?在这个软件示例中,它不会起作用。这只是第一个想法。一个解决方案可能是使用
std::map palaries{}如果你真的对这样的解决方案感兴趣,我会修改我的答案。有什么类似的帮助吗?注意它是一个非常天真、不安全和未优化的实现。把它看作是概念的证明,而不是一个完整的解决方案。
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <unordered_map>

// Some aliases for easier understanding
using Salary = unsigned int;
using Name = std::string;
using ID = size_t;
using NameAndSalary = std::pair<Name, Salary>;

// New data structure according to given requirements
struct Employees {
    std::unordered_map<ID, NameAndSalary> lookup{}; // O(1)

    std::unordered_map<Name, ID> names{};           // O(1)
    std::map<Salary, ID> salaries{};                // O(log n)

    void add(Name&& n, Salary&& s) {
        ID newID = lookup.size();
        names[n] = newID;                           // O(1)
        salaries[s] = newID;                        // O(log n)
        lookup[newID] = { n,s };                    // O(1)
    }
    Salary getSalaryViaName(const Name& n)  { return lookup[names[n]].second; } // O(1) O(1)
    Name getNamebySalary(const Salary& s) { return lookup[salaries[s]].first; } // O(1) O(log n)
};
// Some test code
int main() {

    Employees employees{};
    // Populate struct
    employees.add("John", 456);
    employees.add("Paul", 345);
    employees.add("Ringo", 234);
    employees.add("George", 123);

    // Iterate
    for (const auto& [salary, id] : employees.salaries)  
        std::cout << "Salary: " << salary << "\t\t Name: " << employees.getNamebySalary(salary) << '\n';
    std::cout << '\n';
    for (const auto& [name, id] : employees.names)  
        std::cout << "Name: " << name << "\t\t Salary: " << employees.getSalaryViaName(name) << '\n';
}