多索引哈希表实现

时间:2014-10-03 06:40:48

标签: python c++ boost data-structures

我有一个需要快速查找的记录表,因此决定进行哈希表查找。

现在,最终出现的问题是我必须根据多个键查找记录。

例如,下面的所有4个键都应指向相同的记录。

key1 -> a,b,c,d,e
key2 -> a,b,d
key3 -> a,b,e
key4 -> c
问题#1 然后,此模式显示与数据库查找的相似性,其中指定了多个键。那么,B树数据结构比多哈希表设计更适合使用吗?

问题#2 一个特殊的特里是否更适合这个问题。默认实现将要求所有键a + b + c + d + e作为查找键。如果我必须查找+ b + d,那么从这个主密钥必须跳过c& e,一边抬头一边看。但那么这个想法会起作用还是已经存在?

问题#3 另一个想法是我是否将东西插入到我的表中,并行地建立另一个带有索引的查找表到每个记录。这样我就可以为每个键设置多个掩码,并扫描此查找表以查找匹配的记录。我想是类似于CAM表的东西。但是如果我必须扫描整个表格,性能会下降。是否可以将哈希表+索引逻辑混合在一起,提供速度和最佳内存使用?

到目前为止,我们尝试过使用boost multi index,uthash,trie等来尝试实现一个适合所有4个问题但到目前为止还没有成功的设计。我喜欢boost multi index,但它有自己的一些问题,禁止我使用。

虽然我使用C语言编程和测试设计,但我对其他任何语言都很好,比如java,php,python。

非常感谢解决这个问题的任何其他想法。

我想要实现的解决方案的伪代码:

/* Keys */
struct key1_s {
int src;
int dst;
char name[10];
int t1;
int t2;
};

struct key2_s {
int src;
int dst;
char name[10];
};

struct key3_s {
int src;
int dst;
int t1;
};


struct key4_s {
int src;
int dst;
int t2;
};


/* Record */
struct record_s {
int src;
int dst;
char name[10];
int t1;
int t2;
int age;
int sex;
int mobile;
}

struct record_s record[2] = {
{1, 2, "jack", 5, 6, 50, 1, 1234567890},
{3, 4, "john", 7, 8, 60, 2, 1122334455}
};
table.insert(record[0]);
table.insert(record[1]);

/* search using key1 */
struct key1_s key1;
key1.src = 1;
key1.dst = 2;
strncpy(key1.name, "jack", 10);
key1.t1 = 5;
key1.t2 = 6;
table.find(key1); // should return pointer to record[0]

/* search using key2 */
struct key2_s key2;
key2.src = 1;
key2.dst = 2;
strncpy(key1.name, "jack", 10);
table.find(key2); // should return pointer to record[0]

/* search using key3 */
struct key3_s key3;
key3.src = 1;
key3.dst = 2;
key3.t1  = 5;
table.find(key3); // should return pointer to record[0]

如果find()返回一个成功的指针,那么我想更新记录的字段,如年龄,性别,移动。

1 个答案:

答案 0 :(得分:0)

Boost Multi Index可以在这里提供帮助。

composite_keys.cpp示例包含一个引人注目的示例。您只需要使用ordered全局替换hashed以获取您正在处理的内容(在您的情况下,密钥配置中也会有更多重叠)。

关于表演问题,我认为没有一个明确的答案;它(总是)取决于使用模式。您需要分析和平衡花在优化上的工作量。

我个人认为,当关注方便和快速结果时,Boost Multi Index是最佳选择。请注意,这绝不意味着BMI未经过优化(我相信它已经过高度优化);然而,它将/始终/取决于使用模式。 (考虑最初批量插入大量数据的应用程序,然后只读取;这样的应用程序可以从显式构建索引中获益一次,而不是自动更新每次插入时的所有索引)。

查看 Live On Coliru

using namespace boost::multi_index;

/* A file record maintains some info on name and size as well
 * as a pointer to the directory it belongs (null meaning the root
 * directory.)
 */

struct file_entry
{
  file_entry(
    std::string name_,unsigned size_,bool is_dir_,const file_entry* dir_):
    name(name_),size(size_),is_dir(is_dir_),dir(dir_)
  {}

  std::string       name;
  unsigned          size;
  bool              is_dir;
  const file_entry* dir;

  friend std::ostream& operator<<(std::ostream& os,const file_entry& f)
  {
      os << f.name << "\t" << f.size;
      if (f.is_dir)os << "\t <dir>";
      return os;
  }
};

/* A file system is just a multi_index_container of entries with indices on
 * file and size (per directory). 
 */
struct dir_and_name_key:composite_key<
  file_entry,
  BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry*,dir),
  BOOST_MULTI_INDEX_MEMBER(file_entry,std::string,name)
>{};

struct dir_and_size_key:composite_key<
  file_entry,
  BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry* const,dir),
  BOOST_MULTI_INDEX_MEMBER(file_entry,unsigned,size)
>{};

typedef multi_index_container<
  file_entry,
  indexed_by<
    hashed_unique<dir_and_name_key>,
    hashed_non_unique<dir_and_size_key>
  >
> file_system;

/* typedef's of the two indices of file_system */
typedef nth_index<file_system,0>::type file_system_by_name;
typedef nth_index<file_system,1>::type file_system_by_size;

/* We build a rudimentary file system simulation out of some global
 * info and a map of commands provided to the user.
 */

static file_system fs;                 /* the one and only file system */
static file_system_by_name& fs_by_name=fs;         /* name index to fs */
static file_system_by_size& fs_by_size=get<1>(fs); /* size index to fs */
static const file_entry* current_dir=0;            /* root directory   */
相关问题