我们如何使用 stl 容器有效地存储对象? (即根据字段值进行搜索)[关闭]
Posted
技术标签:
【中文标题】我们如何使用 stl 容器有效地存储对象? (即根据字段值进行搜索)[关闭]【英文标题】:How can we efficiently store objects using stl containers? (viz. for searching based on values of their fields) [closed] 【发布时间】:2019-06-26 05:04:55 【问题描述】:我有类似这样的对象:
struct stStudents
int roll_number; // Can be think as unique key
std::string name;
// There could be more fields here
我需要使用 stl 容器以这样一种方式存储这些对象,以便我应该能够根据字段尽快搜索它们,例如上面示例中的 roll_number
或 name
(或两者)。
我已经尝试/想到的:
尽可能简单,如果我只是将它们存储在std::vector
(可能使用std::find_if
)中,搜索将是 O(n)。
使用 std::set
和 std::map
需要 O(log N),但是为此,对象的重载比较运算符需要基于特定字段(或者可以使用 @ 设置字段987654329@)
具有指向这些对象的各种std::unordered_set
指针(在结构内部)。并根据搜索条件在结构中定义比较运算符(就像我们在数据库中定义多个索引一样)。这将是 O(1) 搜索,但仅限于预定义的搜索条件。
问题:
这些方法如何?我们还能想到哪些更好的替代方案?
【问题讨论】:
您试图解决的真正问题是什么?为什么你需要这个“高效”?你对“高效”的定义是什么?您是否使用例如向量和std::find_if
不是“足够好”(几乎总是是足够好)?
@Someprogrammerdude .. 没有真正描述。它目前处于 PoC 级别。因此,在设计时,请确保从最有效的数据结构开始。是的,vector 和 std::find_if
可能是最佳候选者,所以在这种情况下,只需寻找验证即可。
您忘记定义一个同样重要的属性:roll_number
是唯一的吗?并且:name
是唯一的吗?根据该问题的答案,您最终可能会选择 std::multimap
、std::multiset
和 std::copy_if
。
@user23573 有效点。谢谢。将相应地更新问题
boost::multi_index 你可能会感兴趣。
【参考方案1】:
Map
和 set
在搜索方面是最好的。
因此,如果我们真的只想要搜索速度,那么为名称和滚动制作地图。
但我们正在放弃空间效率。
示例代码:
用 Visual Studio 2012 编写
search
的两个函数都可以达到 O(log(N))。
typedef struct _tagStudent
int m_nRoll;
std::string m_strName;
_tagStudent(): m_nRoll(0)
_tagStudent( int nRoll, std::string strName): m_nRoll( nRoll ),
m_strName(strName)
bool operator<( _tagStudent x) const
return x.m_nRoll > m_nRoll;
Student;
class Students
std::map< int, Student > m_mapStudent;
std::map< std::string, std::set<Student> > m_mapStudentIndexName;
public:
Students();
~Students();
//Adding students Index
void Add( const Student & );
//Searching Students by Roll
Student Search( const int& ) const;
//Searching Students by Name
std::set<Student> Search( const std::string&) const;
;
Students::Students()
Students::~Students()
void Students::Add( const Student& oStudent )
m_mapStudent[oStudent.m_nRoll] = oStudent;
m_mapStudentIndexName[oStudent.m_strName].insert(oStudent);
Student Students::Search( const int& nRoll ) const
if( m_mapStudent.find( nRoll ) != m_mapStudent.end() )
return m_mapStudent.at( nRoll );
return Student();
std::set<Student> Students::Search( const std::string& strName) const
std::set<Student> oStudents;
if( m_mapStudentIndexName.find( strName ) != m_mapStudentIndexName.end() )
return m_mapStudentIndexName.at(strName);
return std::set<Student>();
int _tmain(int argc, _TCHAR* argv[])
Students oStudents;
oStudents.Add( Student(1, "Tom") );
oStudents.Add( Student(2, "Jerry") );
oStudents.Add( Student(15, "Jerry") );
oStudents.Add( Student(3, "Tim") );
auto search1 = oStudents.Search( 1 );
auto search3 = oStudents.Search( "Jerry" );
return 0;
【讨论】:
"Map
和 set
在搜索方面是最好的。"定义“最佳”。可能是最方便的界面,但肯定不是最快的。
是的。如果您关心性能,则始终使用std::vector<>
、std::unordered_set<>
或std::unordered_map<>
。如果你想要一个堆栈,你使用std::vector<>
,如果你不关心顺序,你使用std::vector<>
。从性能的角度来看,很少有链表有意义,而有序的std::set<>
和std::map<>
与它们的无序对应物相比太慢了。基本上是:如果 std::vector<>
能解决问题,请使用它。
您不能将 typedef
设置为 C++ 类型。 typedef 用于 C 编译器,重载运算符用于 C++!
@Ajay 说你“不能”拥有它是错误的。它是有效的 C++,只是愚蠢且毫无意义。
@JonathanWakely,我没有说它不会编译,只是建议它一定没有(不应该更轻)。我已经看到很多模板代码隐藏在“typedef'ed”类下!因此,我讨厌它。以上是关于我们如何使用 stl 容器有效地存储对象? (即根据字段值进行搜索)[关闭]的主要内容,如果未能解决你的问题,请参考以下文章