微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

适合快速检索两个不同参数的数据结构

如何解决适合快速检索两个不同参数的数据结构

我有一些对std::pair<X,Y>X 是独一无二的,永远不会改变,Y 会定期更新。需要根据 Y 对这些对进行排序,但我也希望快速检索 X 以更新 Y

到目前为止,我使用 std::set<std::pair<X,Y>,CustomCompare>获取基于 Y 的排序列表。但是现在更新很慢,我认为在最坏的情况下我需要遍历整个集合才能找到正确的 X。我说得对吗?

是否有任何数据结构支持使用 Y快速(O(logn) 或更少)检索 X 进行排序?我对使用支持数据结构或拆分 XY 的想法持开放态度。

编辑: 也许一个例子可以解决问题。假设 X 是一个名字,Y 是月薪。所以一对可以是 ("John",5000)。现在我需要一个按最高薪水排序的人员列表/集合,例如 [("Mary",8000),("John",5000),("Chris",2000)]。另外,我需要一种方法来查找一个人(在 O(1) 或 O(logn) 中),以便我可以从列表/集合中删除姓名-薪水对,更新薪水,然后重新插入姓名-工资对进入排序列表/集合。更新非常频繁。

解决方法

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

但我确实认为 STL 容器的组合可以满足您的要求。在我的建议中,我基本上将数据存储 2 倍冗余并将它们与某种 ID 连接起来。就像在数据库中建立一个 m:n 关系和一个额外的辅助表一样。

请看下面的源代码。它只是一个骨架,需要使其可迭代,但您可能会明白。

整体性能很大程度上取决于散列算法的单个性能。对于 std::unordered_map 的操作,我假设 O(1) 和 std::map 的 o(log n)。

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

#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';
}

不适用于双重姓名/薪水。那将需要重新设计。还有,更新慢。 . .

如果这不是您所期望的,请发表评论。在这种情况下,我将删除答案。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。