Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 查找字数的最快方法,从指定的字符串开始(字数存储在AVL树中)_Algorithm_Avl Tree - Fatal编程技术网

Algorithm 查找字数的最快方法,从指定的字符串开始(字数存储在AVL树中)

Algorithm 查找字数的最快方法,从指定的字符串开始(字数存储在AVL树中),algorithm,avl-tree,Algorithm,Avl Tree,我已经实现了自己的AVL树,并将其用作字典。我在想,什么是计算所有以字符串开头的单词的最快方法 例如: 我已经开始工作了,但是,我听说可以做得更快。 当然,我可以在节点中保存其他信息,例如下面的节点和其他类似的信息。如果您想要更改数据结构,您可以从一个数据库中获得优异的性能。如果trie包含静态数据,则可以通过使用动态编程生成的子树计数大小来注释分支,从而获得更好的性能 e、 g代表[竖琴,帽子,嗨] h(3) a(2) i() r(1) t(

我已经实现了自己的AVL树,并将其用作字典。我在想,什么是计算所有以字符串开头的单词的最快方法

例如:

我已经开始工作了,但是,我听说可以做得更快。
当然,我可以在节点中保存其他信息,例如下面的节点和其他类似的信息。

如果您想要更改数据结构,您可以从一个数据库中获得优异的性能。如果trie包含静态数据,则可以通过使用动态编程生成的子树计数大小来注释分支,从而获得更好的性能

e、 g代表[竖琴,帽子,嗨]

           h(3)
      a(2)     i()
  r(1)    t()
p()

如果您打算更改数据结构,您可以从一个数据库中获得优异的性能。如果trie包含静态数据,则可以通过使用动态编程生成的子树计数大小来注释分支,从而获得更好的性能

e、 g代表[竖琴,帽子,嗨]

           h(3)
      a(2)     i()
  r(1)    t()
p()

可以修改AVL树,以便每个节点也知道其索引1。如果集合是排序数组,则索引是元素编号

您现在需要做的就是:

搜索FA,得到最接近但更大或相等的索引i1 在树中为它添加元素 搜索FB,获取树中最接近但较小的元素的索引i2。 找出i1和i2之间存在差异的元素数量,区分在1中发现FA的情况和未发现FA的情况。 这两个1,2都是Ologn-3是常量,因此总复杂度实际上是Ologn*| S |,因为每个比较都是O | S |本身,并且有Ologn比较


1这是通过让每个节点记住它有多少子节点来完成的,您可以使用此信息最终提取索引。

可以修改AVL树,以便每个节点也知道其索引1。如果集合是排序数组,则索引是元素号

您现在需要做的就是:

搜索FA,得到最接近但更大或相等的索引i1 在树中为它添加元素 搜索FB,获取树中最接近但较小的元素的索引i2。 找出i1和i2之间存在差异的元素数量,区分在1中发现FA的情况和未发现FA的情况。 这两个1,2都是Ologn-3是常量,因此总复杂度实际上是Ologn*| S |,因为每个比较都是O | S |本身,并且有Ologn比较


1这是通过让每个节点记住它有多少子节点来完成的,您可以使用此信息最终提取索引。

如果您希望在保持相同的渐近时间界限的同时尽可能减少内存占用,您可以满足每个节点一个整数的要求,并且仍然可以实现Olog n time(假定时间键比较为常数)

与每个节点一起存储其子树的大小。这可以在树修改期间轻松更新

要查找具有给定范围的键数,请执行以下操作:

查找此范围内的顶部元素。也就是说,位于范围内但其祖先节点均不在范围内的唯一节点。调用元素top。 如果不存在这样的元素,则返回0 初始化sum=1表示顶部。 在top的左子树中查找范围的起点: 如果从节点向左下降,则将其整个右子树的大小添加到总和,然后添加一个。 如果向右下降,则不添加任何内容。 在top的右子树中查找范围的结尾: 如果从节点向右下降,则将其整个左子树的大小添加到总和,然后添加一个。 如果向左下降,则不添加任何内容。 返回总数。 给定前缀的范围包含具有该前缀的所有元素。需要注意的是,具有给定前缀的字符串集是连续的w.r.t。它的排序顺序——也就是说,它确实是一个范围

前缀范围的起点是前缀本身之前的位置

前缀范围的末尾是在这一个FA=>FB之后的第一个不相交前缀之前的位置;FZ=>GA,当字母表中只有A-Z时


Unicode通过引入一个实际上可能不会出现在文本中的“top”字符来简化这一过程,并将其与所有其他字符进行比较。也就是说,end=prefix+\uFFFF。

如果您希望在保持相同的渐近时间界限的同时尽可能减少内存占用,那么每个节点只需一个整数就足够了,并且在假设恒定时间键比较的情况下仍然可以实现Olog n time

与每个节点一起存储其子树的大小。这可以在树修改期间轻松更新

要查找具有给定范围的键数,请执行以下操作:

查找此范围内的顶部元素。也就是说,位于范围内但其祖先节点均不在范围内的唯一节点。调用元素top。 如果不存在这样的元素,则返回0 初始化sum=1表示顶部。 在top的左子树中查找范围的起点: 如果从节点向左下降,请添加其整个右侧子节点的大小 将树添加到总和,然后添加一个。 如果向右下降,则不添加任何内容。 在top的右子树中查找范围的结尾: 如果从节点向右下降,则将其整个左子树的大小添加到总和,然后添加一个。 如果向左下降,则不添加任何内容。 返回总数。 给定前缀的范围包含具有该前缀的所有元素。需要注意的是,具有给定前缀的字符串集是连续的w.r.t。它的排序顺序——也就是说,它确实是一个范围

前缀范围的起点是前缀本身之前的位置

前缀范围的末尾是在这一个FA=>FB之后的第一个不相交前缀之前的位置;FZ=>GA,当字母表中只有A-Z时


Unicode通过引入一个实际上可能不会出现在文本中的“top”字符来简化这一过程,并将其与所有其他字符进行比较。也就是说,end=prefix+\uFFFF。

AVL树不是实现所需的正确数据结构。还有另一种称为基数树的数据结构,它可以回答Olg N复杂度的前缀计数查询。基数树中的每个节点n都有0到26个子节点。它还有一个辅助变量prefix_count,它告诉我们基数树中有多少单词以前缀n开头。例如,这里是单词abbaba和abbacba的根树

prefix_count函数的实现类似于插入过程

prefix-count( rt, x ) :
  cn := 1; // root
  foreach i in x :
    if rt.array[ cn ].child[ i ] = null :
      return 0; // 0 prefixes found
    else :
      cn := rt.array[ cn ].child[ i ];
  return rt.array[ cn ].pc;

AVL树不是实现所需的正确数据结构。还有另一种称为基数树的数据结构,它可以回答Olg N复杂度的前缀计数查询。基数树中的每个节点n都有0到26个子节点。它还有一个辅助变量prefix_count,它告诉我们基数树中有多少单词以前缀n开头。例如,这里是单词abbaba和abbacba的根树

prefix_count函数的实现类似于插入过程

prefix-count( rt, x ) :
  cn := 1; // root
  foreach i in x :
    if rt.array[ cn ].child[ i ] = null :
      return 0; // 0 prefixes found
    else :
      cn := rt.array[ cn ].child[ i ];
  return rt.array[ cn ].pc;


你能储存多少信息?如果你储存的足够多,它在Olog n中是微不足道的。如果你知道O1,在Olog n时间内仍然有可能。到目前为止,我正在寻找第一个以'fa'开头的单词,这是Olog n,然后我计算示例中的所有fak,然后从这里开始递归函数,找到这些单词。我可以存储很多数据。你可以通过在每个节点中只存储一个以上的整数来实现Olog n。这样的整数包含什么?它的子树的大小-这足以一次性获得Olog n。你可以存储多少信息?如果你储存的足够多,它在Olog n中是微不足道的。如果你知道O1,在Olog n时间内仍然有可能。到目前为止,我正在寻找第一个以'fa'开头的单词,这是Olog n,然后我计算示例中的所有fak,然后从这里开始递归函数,找到这些单词。我可以存储很多数据。您可以通过在每个节点中只存储一个以上的整数来实现Olog n。这样的整数会包含什么?它的子树的大小-这足以获得Olog n时间。如果集合不是按数组排序的呢?我是从随机化器中得到这些单词的。在插入和删除过程中,索引很难更新。@Patryk:我的意思是:假设FAB在集合中。现在假设您有另一个具有相同内容的排序数组,数组[i]==FAB,然后indexFAB==i。实际上,你并不需要数组,它只是解释索引是什么的一种方式。@JanDvorak不需要,它只是一种添加到卷中的东西,几年前我作为一个非常精确的人做过它,我不记得我花了太长时间才将此功能添加到标准AVL树中。@amit那么我认为我们描述的是相同的算法,只是您从根搜索两个边界。如果集合不是排序数组呢?我是从随机化器中得到这些单词的。在插入和删除过程中,索引很难更新。@Patryk:我的意思是:假设FAB在集合中。现在假设您有另一个具有相同内容的排序数组,数组[i]==FAB,然后indexFAB==i。实际上,你并不需要数组,它只是解释索引是什么的一种方式。@JanDvorak不需要,它只是一种添加到卷中的东西,几年前我作为一个非常精确的人做过它,我不记得我花了太长时间才将此功能添加到标准AVL树。@amit那么我认为我们描述的是相同的算法,只是从根开始搜索两个边界
struct node :
  let child -> array of 26 characters;
  let pc -> integer prefix counter;

struct radix-tree :
  node array[ MAXN ];
  let size -> integer size of the trie

init( rt ) :
  size := 1; // add the root

insert( rt, x ) :
  cn := 1; // root
  foreach i in x :
    if rt.array[ cn ].child[ i ] = null : // node doesn't exist
      rt.array[ cn ].child[ i ] := ++rt.size;
      cn := rt.size;
    else : // node exists
      cn := rt.array[ cn ].child[ i ];
    tr.array[ cn ].pc += 1;
prefix-count( rt, x ) :
  cn := 1; // root
  foreach i in x :
    if rt.array[ cn ].child[ i ] = null :
      return 0; // 0 prefixes found
    else :
      cn := rt.array[ cn ].child[ i ];
  return rt.array[ cn ].pc;