C++ 寻找一个高效的数据结构来进行快速搜索
我有一个大约1000个元素的列表。包含4个变量的每个元素(我从文件中读取的对象,因此我可以在开始时有效地排列它们)。所以现在我在做以下事情,这在大计划中是非常低效的:C++ 寻找一个高效的数据结构来进行快速搜索,c++,c,algorithm,C++,C,Algorithm,我有一个大约1000个元素的列表。包含4个变量的每个元素(我从文件中读取的对象,因此我可以在开始时有效地排列它们)。所以现在我在做以下事情,这在大计划中是非常低效的: void func(double value1, double value2, double value3) { fooArr[1000]; for(int i=0;i<1000; ++i) { //they are all numeric
void func(double value1, double value2, double value3)
{
fooArr[1000];
for(int i=0;i<1000; ++i)
{
//they are all numeric! ranges are < 1000
if(fooArr[i].a== value1
&& fooArr[i].b >= value2;
&& fooArr[i].c <= value2; //yes again value2
&& fooArr[i].d <= value3;
)
{
/* yay found now do something!*/
}
}
}
void func(双值1、双值2、双值3)
{
fooArr[1000];
对于(int i=0;i=value2;
&&fooArr[i].c如果空间不是太重要,那么最简单的方法就是根据“a”上的冲突数量创建一个基于“a”的哈希表。让哈希表中的每个节点都指向一个基于“b”的二叉树可能是有意义的。如果b有很多冲突,那么对c也一样
第一个索引到散列中,这取决于有多少冲突,将为您节省大量时间,只需很少的编码或数据结构工作。如果空间不是太重要,最简单的方法是根据“a”创建一个基于“a”的散列,这取决于您在“a”上得到的冲突数量让哈希表中的每个节点都指向一个基于“b”的二叉树可能是有意义的。如果b有很多冲突,那么对c也一样
第一个索引到散列中,取决于有多少冲突,这将为您节省大量时间,只需很少的编码或数据结构即可工作。看,这只是一个线性搜索。如果您可以做一个更好的搜索,那会很好,但您复杂的匹配要求让我不清楚是否有可能,比如,保持排序并使用二进制搜索
话虽如此,也许有一种可能性是生成一些索引。主索引可能是键入a
属性的字典,将其与该属性具有相同值的元素列表相关联。假设该属性的值分布均匀,它将立即消除绝大多数索引比较
如果属性值有限,则可以考虑添加一个附加的索引,该项通过“代码> B <代码>排序,甚至可能是按代码< C>代码>排序的另一个索引(但按相反的顺序排序)。.
看,这只是一个线性搜索。如果你能做一个更好的搜索,那就太好了,但是你复杂的匹配要求让我不清楚是否有可能,比如说,保持排序并使用二进制搜索
话虽如此,也许有一种可能性是生成一些索引。主索引可能是键入a
属性的字典,将其与该属性具有相同值的元素列表相关联。假设该属性的值分布均匀,它将立即消除绝大多数索引比较
如果属性值有限,则可以考虑添加一个附加的索引,该项通过“代码> B <代码>排序,甚至可能是按代码< C>代码>排序的另一个索引(但按相反的顺序排序)。.
由于您只有三个要匹配的属性,因此可以使用哈希表。在执行搜索时,您使用哈希表(它为a属性编制索引)要查找a与某个常量匹配的所有条目,请检查b和c是否与常量匹配。这样可以减少比较次数。我认为这将大大加快搜索速度
除此之外,您还可以构建三个二进制搜索树。其中一个按每个属性排序。搜索完所有三个树后,您可以对每个树中与您的值匹配的树执行操作。因为您只有三个属性要匹配,所以可以使用哈希表。执行搜索时,您可以使用哈希表(对a属性进行索引)以查找a与SomeConstant
匹配的所有条目。然后检查b和c是否也与常量匹配。这样可以减少比较次数。我认为这将大大加快搜索速度
除此之外,您还可以构建三个二进制搜索树。其中一个按每个属性排序。在搜索完所有三个树后,您可以对每个树中与您的值匹配的树执行操作。如果您的应用程序已经在使用数据库,则只需将它们放在一个表中并使用查询来查找。我在一些应用程序中使用mysql,并将重新编译结束它。如果你的应用程序已经在使用数据库,那么就把它们放在一个表中,然后使用查询来查找它。我在我的一些应用程序中使用mysql,我会推荐它。首先,按增加a和减少b对列表进行排序。然后在a上建立一个索引(值是从0到999的整数。因此,我们得到了
int a_index[1001]; // contains starting subscript for each value
a_index[1000] = 1000;
for (i = a_index[value1]; i < a_index[value1 + 1] && fooArr[i].b >= value2; ++i)
{
if (fooArr[i].c <= value2 && fooArr[i].d <= value3) /* do stuff */
}
int a_index[1001];//包含每个值的起始下标
a_指数[1000]=1000;
对于(i=a_索引[value1];i=value2;++i)
{
如果(fooArr[i].c首先,对增加a和减少b的列表进行排序。然后在a上建立索引(值是从0到999的整数。因此,我们得到
int a_index[1001]; // contains starting subscript for each value
a_index[1000] = 1000;
for (i = a_index[value1]; i < a_index[value1 + 1] && fooArr[i].b >= value2; ++i)
{
if (fooArr[i].c <= value2 && fooArr[i].d <= value3) /* do stuff */
}
int a_index[1001];//包含每个值的起始下标
a_指数[1000]=1000;
对于(i=a_索引[value1];i=value2;++i)
{
如果(fooArr[i].c您可以使用标准模板库(STL)中的hash_集,这将为您提供非常高效的实现。搜索的复杂性将是O(1)
以下是链接:
--编辑--
声明新结构,该结构将保存变量,重载比较运算符并生成此新结构的哈希集。每次要搜索时,使用变量创建新对象并将其传递给哈希集方法“find”
似乎哈希_集对于STL不是必需的,因此您可以使用set,它将为您的搜索提供O(LogN)复杂度。
下面是一个例子:
#include <cstdlib>
#include <iostream>
#include <set>
using namespace std;
struct Obj{
public:
Obj(double a, double b, double c, double d){
this->a = a;
this->b = b;
this->c = c;
this->d = d;
}
double a;
double b;
double c;
double d;
friend bool operator < ( const Obj &l, const Obj &r ) {
if(l.a != r.a) return l.a < r.a;
if(l.b != r.b) return l.a < r.b;
if(l.c != r.c) return l.c < r.c;
if(l.d != r.d) return l.d < r.d;
return false;
}
};
int main(int argc, char *argv[])
{
set<Obj> A;
A.insert( Obj(1,2,3,4));
A.insert( Obj(16,23,36,47));
A.insert(Obj(15,25,35,43));
Obj c(1,2,3,4);
A.find(c);
cout << A.count(c);
system("PAUSE");
return EXIT_SUCCESS;
}
#包括
#包括
#包括
使用名称空间std;
结构对象{
公众:
Obj(双a、双b、双c、双d){
这->a=a;
这->b=b;
这个->c=c;
std::vector<foo *> const &values = index[value1];
for (int i=0; i<values.size(); i++) {
if (value2 <= values[i]->b
&& value2 >= values[i]->c
&& value3 >= values[i]->d) {
// yay, found something
}
}
b = 96 46 47 27 40 82 9 67 1 15
c = 76 23 91 18 24 20 15 43 17 10
d = 44 30 61 33 21 52 36 70 98 16
idx[a].bc[50] = 0000010100
idx[a].d[50] = 1101101001
idx[a].bc[20] = 0001010000
idx[a].d[20] = 0000000001
g = idx[a].bc[20] & idx[a].d[50];
tg = g
n = 0
while (tg > 0){
if(tg & 1){
// do your stuff
}
tg = tg >>> 1;
n++;
}
std::vector<Bucket1> myTable(1001, /*MAGIC_1*/); // suspense
&& fooArr[i].b >= value2
&& fooArr[i].c <= value2 //yes again value2
&& fooArr[i].d <= value3
typedef std::vector<Bucket2> Bucket1;
/*MAGIC_1*/ <-- Bucket1(1001, /*MAGIC_2*/) // suspense ?
typedef std::vector< std::vector<YourObject*> > Bucket2;
/*MAGIC_2*/ <-- Bucket2(1001)
class Collection:
{
public:
Collection(size_t aMaxValue, size_t bMaxValue, size_t dMaxValue);
// prefer to use unsigned type for unsigned values
void Add(const YourObject& i);
// Pred is a unary operator taking a YourObject& and returning void
template <class Pred>
void Apply(int value1, int value2, int value3, Pred pred);
// Pred is a unary operator taking a const YourObject& and returning void
template <class Pred>
void Apply(int value1, int value2, int value3, Pred pred) const;
private:
// List behaves nicely with removal,
// if you don't plan to remove, use a vector
// and store the position within the vector
// (NOT an iterator because of reallocations)
typedef std::list<YourObject> value_list;
typedef std::vector<value_list::iterator> iterator_vector;
typedef std::vector<iterator_vector> bc_buckets;
typedef std::vector<bc_buckets> a_buckets;
typedef std::vector<a_buckets> buckets_t;
value_list m_values;
buckets_t m_buckets;
}; // class Collection
Collection::Collection(size_t aMaxValue, size_t bMaxValue, size_t dMaxValue) :
m_values(),
m_buckets(aMaxValue+1,
a_buckets(bMaxValue+1, bc_buckets(dMaxValue+1))
)
)
{
}
void Collection::Add(const YourObject& object)
{
value_list::iterator iter = m_values.insert(m_values.end(), object);
a_buckets& a_bucket = m_buckets[object.a];
for (int i = object.c; i <= object.b; ++i)
{
bc_buckets& bc_bucket = a_bucket[i];
for (int j = 0; j <= object.d; ++j)
{
bc_bucket[j].push_back(index);
}
}
} // Collection::Add
template <class Pred>
void Collection::Apply(int value1, int value2, int value3, Pred pred)
{
index_vector const& indexes = m_buckets[value1][value2][value3];
BOOST_FOREACH(value_list::iterator it, indexes)
{
pred(*it);
}
} // Collection::Apply<Pred>
template <class Pred>
void Collection::Apply(int value1, int value2, int value3, Pred pred) const
{
index_vector const& indexes = m_buckets[value1][value2][value3];
// Promotion from value_list::iterator to value_list::const_iterator is ok
// The reverse is not, which is why we keep iterators
BOOST_FOREACH(value_list::const_iterator it, indexes)
{
pred(*it);
}
} // Collection::Apply<Pred>