哪个更快,对向量进行排序,然后将其放入AVL树中,或直接输入
Which is faster, sorting a vector, then putting it into an AVL tree, or inputting it directly?
所以情况是这样的:
我有数百万个,可能数十亿个字符串,我正在尝试解析并放入排序结构中,假设我有 5,000,000 个字符串。我正在尝试编写一个快速程序,可以将所有这些来自未排序向量的字符串放入有序数据结构中,该结构也可以快速搜索结构,因此 AVL 树的推理(最终我计划使用 a-z 的哈希表进行更快的查找,但稍后再说)。我首先将所有字符串放入一个向量中,但它们都是混乱的,未排序的和不同的长度。我不希望我的树中有任何重复的字符串,所以如果程序找到字符串"hello"和"hello",它将只有一个 AVL 条目,并且会根据该字符串出现的频率增加一个整数持有者。
所以我的问题是:在所有单词与其他相同单词排序在一起之后,先对向量进行排序(使用多线程快速排序或其他快速的东西)然后将其输入到 AVL 树中会更快,还是将所有数据从未排序的向量放入 AVL 树中更快, 并不断检查 AVL 树是否已经存在一个单词,然后递增它。
因此,为了按操作顺序来描述它,这里有两种情况:
CASE A:
> Get input/parse strings
> Put strings into vector (unsorted)
> Put vector into array or linked-list
> Quicksort that array/llist
> Input that sorted array into the AVL Tree
CASE B:
> Get input/parse strings
> Put strings into vector (unsorted)
> Insert vector data into AVL tree
> During insertion, check if there are duplicate words, if so, increment the counter
哪种情况更快??
--编辑-- 因此,在听到一些评论后,从一开始就将排序数组插入 AVL 树将是一个坏主意,这是有道理的,因为需要进行多少次旋转。似乎直接插入到 AVL 树中可能是一个好主意,但是当单词已经在树中的某个地方时,有效插入的最佳方法是什么?我怎样才能确保我找到它?这就是我的排序可以进来的地方吗?
想想平衡对 AVL 树的工作方式。如果"中间值"排在第一位,效果最好。对于排序的输入,您将需要大量的重新平衡,因此预排序可能弊大于利。
例如,考虑以下保存值 1-6 的 AVL 树:
4
/
2 5
/
1 3 6
如果输入顺序是 4, 2, 5, 1, 3, 6
,则永远不需要平衡树。 相反,对于排序的输入1, 2, 3, 4, 5, 6
,您将需要许多重新平衡操作:
1 +3 2 +4 2 +5 2 +6 3
---> / ---> / ---> / ---> /
2 1 3 1 3 1 4 2 5
/ / /
4 3 5 1 4 6
更新 最初的问题是,在插入到 AVL 树之前对数据进行排序是否会提高性能。 现在OP编辑了这个问题,转向了他的具体问题。
但是,当单词已经在树中的某个地方时,有效插入的最佳方法是什么?我怎样才能确保我找到它? 这就是我的排序可以进来的地方吗?
AVL树的全部意义在于有效地查找数据,所以我不明白这个问题。 如何遍历二叉搜索树以查找值应该是显而易见的。 为什么要为此对数据进行排序?
请注意,二叉搜索树是存储键的良好数据结构,但它也可以管理与这些键关联的任意数据。 在您的情况下,您希望将计数与密钥一起存储。 因此,您不需要单词/字符串树,而是表示单词及其计数的对树(字符串、整数)。 对于树顺序,只需考虑字符串键,即单词。
对于要插入的每个单词,请在树中查找它。 如果已存在,请更新字数统计。 否则,插入字数为 1 的新对。
最后一点:C++标准库带有一个map
类型,通常(总是?)使用平衡树(AVL或红黑)实现。 仅使用此实现,您将节省大量工作和错误修复。 自C++11以来,还有un unordered_map
,通常(总是?)使用哈希表实现。
我会将我的评论转换为答案。
如果字符串集是预定义的,也就是说,在初始加载后您不会向其添加更多字符串,那么最快的可能是根本不使用 AVL 树(或任何其他树)。
只需将字符串加载到std::vector
中,对其进行排序(O(N*logN),删除唯一(std::uniq
,O(N)),然后用于查找使用std::lower_bound
(O(logN))。
具有与 AVL 树相同的复杂性,实际上它很可能会更快,因为缓存友好性增加。
在现实世界中,以下内容可能不会更快。
将排序后的向量插入 AVL 树时,请像插入树本身一样插入它。首先插入中间,然后递归插入左半部分的中间和右半部分的中间,依此类推。如果向量中的所有值都均匀分布,则不必重新平衡树。(理论上。
更好的是,你可以用排序的向量构建你自己的树(如果你控制内部存储器),或者首先使用二叉搜索。
获得客观答案的唯一方法是测试和测量。
AVL 树中的 1-插入是 O(Log n)。排序是 O(nLogN),因此在插入之前排序会降低性能。2-出于计数目的,您可以使用哈希表来查找每个单词的出现次数。遍历所有单词,更新哈希表中每个单词的计数,然后使用哈希表在 AVL 树中插入单词,以检查单词是否已插入,如果没有插入其关联的计数。
"但是当一个单词已经在树中的某个地方时,有效插入的最佳方法是什么?我怎样才能确保我找到它?这就是我的分拣可以进来的地方吗?
在以下情况下,为什么不使用地图:键=单词,值=单词索引
这样,只要单词存在,您就可以获得访问权限,并且您将拥有操作它的索引
- 如何正确地将分支添加到已存在的树中
- 为什么我们要为avl树实现返回一个指向节点的指针,而不是void函数
- 在递归二叉搜索树中搜索
- 从 AVL 树中删除指向 1 个或多个值的键
- 如何在 c++ 中实现 avl 树,每个节点都是另一个 avl 树
- 按顺序遍历 AVL 树,将值保存在数组中
- AVL 树是否可以对不同节点中的键具有相同的值?
- 如何在这个哈希映射中实现 AVL 树
- 在 avl 树中实现删除过程
- AVL树中的删除
- 解析大型文本文件并使用C++将其存储在树(二进制或 AVL)中
- 如何识别AVL树中的干扰节点
- 正在尝试在avl树中实现find
- 从AVL树中删除父级
- AVL树代码中的错误,数据结构c++
- 在 C++ 中将字符串插入到 AVL 树中
- 哪个更快,对向量进行排序,然后将其放入AVL树中,或直接输入
- 在 AVL 树中的节点下保存叶子的数量
- 如何在c++中使用向量实现一个简单的树,没有二进制或avl树
- AVL树中节点删除值异常