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
。因此,在末尾排序可能比每次更新aY
时排序更快。此外,如果您只需要跟踪最大的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';
}