【问题标题】:generating key for AVL tree为 AVL 树生成密钥
【发布时间】:2012-04-18 08:59:16
【问题描述】:

我有一个使用 AVL 树快速搜索 IP 地址的大型系统:

struct avl_node
{
   struct avl_node *left;
   struct avl_node *right;
   ...
   void *info; /* point to nhlfe_entry describing nexthop */
}

struct nhlfe_entry
{
  u_int32_t nhlfe_ix;
  u_char opcode;
  ...
  struct nhlfe_key key;
}

/* defines a search key. */
struct nhlfe_key
{
  struct in_addr nh_addr;
  u_int32_t oif_ix;
  u_int32_t out_label;
}

所以搜索是基于'struct nhlfe_key',即比较函数在 AVL 树如下所示:

static int
mpls_cmp_nhlfe_ipv4_key (void *data1, void* data2)
{
   struct nhlfe_entry *nh1, *nh2;
   struct nhlfe_key *key1, *key2;
   int ret;

   nh1 = (struct nhlfe_entry *) data1;
   nh2 = (struct nhlfe_entry *) data2;

   key1 = (struct nhlfe_key *) nh1->nkey;
   key2 = (struct nhlfe_key *) nh2->nkey;

   ret = memcmp (&key1->nh_addr, &key2->nh_addr, sizeof (struct in_addr));
   if (ret != 0)
     return ret;

   if (key1->oif_ix > key2->oif_ix)
     return 1;
   else if (key1->oif_ix < key2->oif_ix)
     return -1;

   if (key1->out_label > key2->out_label)
     return 1;
   else if (key1->out_label < key2->out_label)
     return -1;

   return 0;
}

现在,我要做的是添加对多个下一跃点的支持,即 我在 nhlfe_entry 中添加了一个链表:

struct nhlfe_entry
{
  u_int32_t nhlfe_ix;
  u_char opcode;
  ...
  struct list *nhkey_list;
}

每个 'struct list' 都是 struct listnode 嵌入 'void *data' 指针 调用者的私人数据,这是'struct nhlfe_key'。

所以我的问题是——如何根据多个元素生成密钥 列表以存储/搜索树中的节点(因为否则现在之后 引入一个列表,就不可能有一个仅基于 one 的键 下一跳地址)。此外,他们同样的问题 申请搜索。

另外,在列表中添加新节点后,是否需要重新构建树, 因为我认为这个操作会改变密钥,因此树可能 变得不平衡? (或自然正确实现的 AVL 树 不需要重建?)

我正在考虑在每个列表节点上生成 CRC,然后进行总结。这可以保证密钥的唯一性吗? (缺点是每当我添加/删除列表节点时,我必须重新生成密钥,从树中删除节点并使用新密钥重新添加。

谢谢!

【问题讨论】:

    标签: c data-structures avl-tree


    【解决方案1】:

    我有一个使用 AVL 树快速搜索 IP 地址的大型系统:

    对于大量 IP 地址,您通常需要一个基数树。二叉树可以工作,但您无法使用前缀存储地址范围,例如10.*。如果您没有将它用于类似路由的任何东西,或者您不需要节省空间将整个子网映射到某个东西。

    所以我的问题是——如何根据列表中的多个元素生成密钥以存储/搜索树中的节点(因为否则现在在引入列表后,将不可能拥有密钥仅基于一个下一跳地址)。此外,他们同样的问题也适用于搜索。

    您的mpls_cmp_nhlfe_ipv4_key 函数只需比较可能是地址列表的键。显然(1 2 3) 比较等于(1 2 3)。此外,(1 2 3) 比较大于(1 2),但小于(1 3)(1 2 4)

    另外,在列表中添加新节点后,是否需要重新构建树...

    如果要更新平衡搜索树中的节点以使键发生变化,最好的办法可能是将其删除并重新插入。

    可能有一些方法可以优化它。例如,假设一个键发生了变化,但它在树中仍然具有完全相同的后继者和前驱者。在这种情况下,它可以就地完成。或者密钥可以以这样的方式改变,即节点只需要与前任或后继者交换。在尝试这样的技巧之前我会做对的。

    [a CRC] 能否保证密钥的唯一性?

    不,CRC 是一个散列函数。它比被散列的对象具有更少的位,因此多个对象可以散列到相同的 CRC。 (例外情况是为一组元素找到“完美散列函数”,但动态数据很少发生这种情况:完美散列函数是为某些静态数据集设计的。)使用散列方法,您可能会很好地使用哈希表。 CRC 上的排序关系可能毫无意义。当必须通过键上的排序关系对集合进行排序时,使用二叉搜索树。

    【讨论】:

    • 但是,我不清楚如何生成密钥——现在我有一个 IP 地址列表,而不是以前的一个。我正在考虑的一个解决方案是始终拥有基于列表的第一个元素的键(但每当列表更改时,在树中重新插入节点)。是否有意义?或者可能在列表中存储了一个 IP 哈希...
    • 我帮不了你。您正在尝试确定两个键相等意味着什么。密钥相等性是否包括列表中的所有 IP 地址,还是仅基于第一个(其他是补充数据)?对象相等性的定义是任意的(在任何相等性必须满足的规则范围内)。选择是由应用程序所需的语义驱动的。如果您只将主 IP 地址视为密钥,而不是其他地址,那么只有您现在会破坏什么(如果有的话)。
    猜你喜欢
    • 2017-10-15
    • 2020-08-27
    • 1970-01-01
    • 2013-06-22
    • 1970-01-01
    • 2013-11-06
    • 2015-04-01
    • 2013-02-26
    • 1970-01-01
    相关资源
    最近更新 更多