我试图理解如何考虑在B树中获取第k个键/元素。即使它的步骤而不是代码,它仍然会有很大帮助。感谢
编辑:要清理,我要求B树中的第k个最小的密钥。
答案 0 :(得分:4)
使用标准B树没有有效的方法。从广义上讲,我看到了两个选项:
将B树转换为order statistic tree 以允许在O(log n)中执行此操作。
也就是说,对于每个节点,保留一个变量,该变量表示以该节点为根的子树的大小(元素数)(该节点,其所有子节点,所有子节点的子节点等)。
每当您执行插入或删除操作时,都会相应地更新此变量。您只需更新已访问过的节点,因此不会改变这些操作的复杂性。
获取k
- 元素会增加孩子的大小,直到我们到达k
,选择适当的孩子来访问并适当减少k
。伪代码:
select(root, k) // initial call for root
// returns the k'th element of the elements in node
function select(node, k)
for i = 0 to t.elementCount
size = 0
if node.child[i] != null
size = node.sizeOfChild[i]
if k < size // element is in the child subtree
return select(node.child[i], k)
else if k == size // element is here
&& i != t.elementCount // only equal when k == elements in tree, i.e. k is not valid
return t.element[i]
else // k > size, element is to the right
k -= size + 1 // child[i] subtree + t.element[i]
return null // k > elements in tree
将child[i]
视为直接位于element[i]
左侧。
Wikipedia上提供的二叉搜索树(非B树)的伪代码可以比上面更好地解释基本概念。
请注意,节点子树的大小应该存储在其父节点中(请注意,我没有使用上面的node.child[i].size
)。将它存储在节点本身效率要低得多,因为读取节点被认为是B树用例的非平凡或昂贵的操作(节点通常必须从磁盘读取),因此您希望最小化读取的节点数,即使这会使每个节点略大。
在您看到k
元素之前执行in-order traversal - 这将需要O(n)。
的伪代码:
select(root, *k) // initial call for root
// returns the k'th element of the elements in node
function select(node, *k) // pass k by pointer, allowing global update
if node == null
return null
for i = 0 to t.elementCount
element = select(node.child[i], k) // check if it's in the child's subtree
if element != null // element was found
return element
if i != t.elementCount // exclude last iteration
if k == 0 // element is here
return t.element[i]
(*k)-- // only decrease k for t.element[i] (i.e. by 1),
// k is decreased for node.child[i] in the recursive call
return null
答案 1 :(得分:0)
您可以使用新的平衡二叉搜索树(如Splay或仅使用std :: set)来记录B树中当前的元素。这将允许每个操作在O(logn)中完成,并且它很容易实现(当使用std :: set时)但是会使空间成本加倍。
答案 2 :(得分:-1)
好吧,经过几个不眠时,我设法做到了,对于任何想知道怎么做的人来说,这里是伪代码(第一个元素为k = 0):
get_k-th(current, k):
for i = 0 to current.number_of_children_nodes
int size = size_of_B-tree(current.child[i])
if(k <= size-1)
return get_k-th(current.child[i], k)
else if(k == size && i < current.number_of_children_nodes)
return current.key[i]
else if (is_leaf_node(current) && k < current.number_of_children_nodes)
return node.key[k]
k = k - size - 1;
return null
我知道这可能看起来有点奇怪,但这是我想出来的,幸好它有效。可能有一种方法可以使这些代码更清晰,并且可能更有效,但我希望它能够帮助那些可能遇到与我相同的障碍的其他人。