在一个B中键

我试图理解我应该如何考虑在B树中获得第k个键/元素。 即使它是步骤而不是代码,它仍然会有很大的帮助。 谢谢

编辑:为了清理,我要求B树中第k个最小的键。


使用标准的B-tree没有有效的方法。 一般来说,我看到2个选项:

  • 将B-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]的左边。

    维基百科上提供的二叉搜索树(不是B树)的伪代码可能比上述更好地解释这里的基本概念。

    请注意,节点的子树的大小应该存储在它的父级(注意,我没有使用node.child[i].size )。 将它存储在节点本身的效率会低得多,因为读取节点对B树用例而言被认为是不平凡或昂贵的操作(节点通常必须从磁盘读取),因此您希望将节点读取次数最小化即使这会使每个节点稍大一些。

  • 按顺序遍历,直到看到k元素 - 这将花费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
    

  • 您可以使用新的平衡二叉搜索树(如Splay或仅使用std :: set)来记录B树中当前的元素。 这将允许每个操作在O(logn)中完成,并且它很容易实现(当使用std :: set时),但会使空间成本增加一倍。


    好吧,在几个不眠之余,我设法做到了这一点,对于任何想知道如何的人来说,这里都是伪代码(第一个元素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
    

    我知道这可能看起来有点奇怪,但这是我想出来的,幸好它有效。 可能有一种方法可以使代码更加清晰,并且效率可能更高,但我希望能够帮助其他任何可能陷入与我一样的障碍的人。

    链接地址: http://www.djcxy.com/p/40017.html

    上一篇: th key in a B

    下一篇: Big O notation Log Base 2 or Log Base 10