【问题标题】:How can a B-tree node be represented?B树节点如何表示?
【发布时间】:2012-02-26 07:47:02
【问题描述】:

我们正在课堂上学习 B 树,并被要求在代码中实现它们。老师把编程语言的选择留给了我们,我想尝试用 C# 来做。我的问题是以下结构在 C# 中是非法的,

unsafe struct BtreeNode
        {
            int key_num;        // The number of keys in a node
            int[] key;          // Array of keys
            bool leaf;          // Is it a leaf node or not?
            BtreeNode*[] c;     // Pointers to next nodes
        }

具体来说,不允许创建指向结构本身的指针。我可以使用一些解决方法或替代方法吗?我相当确定在托管代码中必须有一种方法可以做到这一点,但我无法弄清楚。

编辑: 埃里克的回答为我指明了正确的方向。这是我最终使用的,

class BtreeNode
{
        public List<BtreeNode> children;       // The child nodes
        public static int MinDeg;               // The Minimum Degree of the tree
        public bool IsLeaf { get; set; }        // Is the current node a leaf or not?
        public List<int> key;                   // The list of keys 
...
}

【问题讨论】:

  • 为什么要使用结构体而不是类?
  • 当然B树也可以使用C#
  • 除非您是专家,否则不要尝试在 C# 中使用不安全的代码;你会弄错的,这将是痛苦和困难的。相反,首先要学习安全的做事方式; C# 的设计使得安全的做事方式几乎总是比不安全的方式更容易。
  • @HenkHolterman 这只是一个学术练习,可以基本了解 B 树的功能,对于带有类和引用的 C# 来说很好。如果 OP 的任务是使用 B-tree 为数据库引擎实现索引,那么我会告诉他使用指针/结构,并使用 C++ 工作。
  • @Henk Holterman,正如上面提到的 Servy,这是一个学术练习,目的是让我们熟悉 B 树的工作。具体来说,我们的老师希望我们实现课本算法来插入/删除/搜索节点。在概念层面上,我理解(我认为)文本中写的内容,但在 C# 中实现相同的内容让我很难过。如果我想不通,我打算转向 VC++,但这也意味着要从头开始学习另一种语言...... :(

标签: c# .net b-tree


【解决方案1】:

巧合的是,我实际上只是在 C# 中实现了一个 btree,用于个人项目。好玩。我构建了一个按字典顺序排列的可变大小(最多 64 字节)键的 btree,这带来了许多挑战,尤其是在确定存储页面何时太满或太空时。

我的建议是构建一个抽象层,以最抽象的形式捕获 btree 算法,作为抽象基类。一旦我以这种形式捕获了所有 btree 规则,我就以几种不同的方式专门化了基类:作为常规的固定键大小 2-3 btree,作为我喜欢的可变大小键 btree 之一,等等.

首先,在任何情况下都不应使用指针来执行此操作。不安全的代码很少需要,也不容易。只有最高级的 C# 程序员才应该关闭安全系统;当您这样做时,您要对程序的类型和内存安全负责。如果您不愿意这样做,请让安全系统保持开启状态。

其次,没有理由让它成为一个结构。在 C# 中,结构是按值复制的; btree 节点不是

第三,您不需要保留节点中的键数;键数组知道其中有多少键。

第四,我会使用List&lt;T&gt; 而不是数组;它们更灵活。

第五,你需要决定key是在node还是在parent。无论哪种方式都可以工作;我的偏好是密钥存在于节点中,因为我认为密钥与节点相关联。

第六,知道一个btree节点是否是根是有帮助的;您可能会考虑使用两个布尔值,一个“这是一片叶子吗?”还有一个“这是根吗?”当然,只有一个项目的 btree 有一个节点,它既是叶子节点,又是根节点。

第七,你可能会构建这个东西是可变的;通常不会在 C# 类上创建公共可变字段。您可以考虑将它们设为属性。此外,子列表可以增长缩小,但它的身份不会改变,因此将其设为只读: p>

所以我可能会将我的基本节点构造为:

class Node
{
    public int Key { get; set; }
    public bool IsRoot { get; set; }
    public bool IsLeaf { get; set; }
    private List<Node> children = new List<Node>();
    public List<Node> Children { get { return this.children; } }
}

有意义吗?

【讨论】:

  • struct 节点放入支持基于 btree 的集合的单个数组中作为性能优化仍然是一个好主意。但是,在这种情况下,当然会使用索引而不是指针。当然这个问题主要是关于学习 btrees 是如何工作的,所以这里最好使用更清晰的类代码。
  • @Eric Lippert,说真的? “列表”的想法对我来说是新的。我现在快去上课了,但我会在当天晚些时候尝试你的建议并报告回来。关于您的第三点-我保留节点中的键数只是因为这就是我的文本(Cormen,Leiserson ..et al 的算法简介)显示的方式。没错,数组也有这些信息,但我认为我的老师希望明确提及它。
  • @chronodekar:请记住,CLR 中呈现的算法假定了一种非常类似于 C 的方法。在更现代的语言中,存在比数组更高级别的抽象,并且对象更具自描述性。还要记住:数据结构中的每个冗余不仅是对内存的浪费,也是一个等待发生的错误。必须与其他字段完全相同的字段可能会导致它们不同步。
  • @chronodekar:您可以拥有一个明确显示子项数量的属性,但您不必为其存储单独的值:public int ChildrenCount { get { return children.Count; } } - 这样您就不会拥有数据冗余,但Node 类的公共接口仍然会有一些冗余。
  • @Eric Lippert:更新:我听取了您的建议并删除了 key_num 字段。虽然,列表(或集合)很棘手。我认为我的“BtreeSplitChild()”函数已正确完成,但在我完成所有操作之前,我无法确定。过几天再更新。
【解决方案2】:

使用类而不是结构。并抛出指针。

class BtreeNode
{
    int key_num;        // The number of keys in a node
    int[] key;          // Array of keys
    bool leaf;          // Is it a leaf node or not?
    BtreeNode[] c;      // Pointers to next nodes
}

当你声明一个类类型的变量时,它是隐含的引用(非常类似于 c 中的指针),因为每个类都是引用类型。

【讨论】:

    【解决方案3】:

    您只需要意识到 C 中的指针与 C# 中的引用“有些相似”。 (存在各种差异,但就本问题而言您可以专注于相似之处。)两者都允许一定程度的间接:价值不是数据本身,而是一种获取数据。

    上面的等价物是这样的:

    class BtreeNode
    {
        private int keyNumber;
        private int[] keys;
        private bool leaf;
        private BtreeNode[] subNodes;
    
        // Members (constructors etc)
    }
    

    (我不太记得B-trees,但是如果这里的“keys”数组对应每个子节点的“keyNumber”值,你可能根本不需要keys变量。)

    【讨论】:

    • 只是一个注释(尽管它与问题完全无关),单独使用 keys[] 可以在按键查找时减少缓存未命中。键[] 可能占用单个(?,取决于大小)缓存行,比 BtreeNode 的间接速度快得多。同样,这与 OP 的问题完全无关。
    • @bestsss:另一方面,这意味着总共有更多的对象,因此您很可能最终会在更高级别出现更多的缓存未命中。我肯定会先在没有优化的情况下实现它,然后在性能有问题时对其进行基准测试。
    • 当然.. 没有键[] 开始。无论如何,这种优化大多是不必要的。它指出拥有显式键可以提高性能。
    • @Jon Skeet:是的,keyNumber 确实对应于键的数量。我将这些数据留在其中,因为我觉得我的老师(和非 .NET 同学)会以这种方式更好地理解我的代码。
    猜你喜欢
    • 2011-01-14
    • 2011-02-10
    • 2013-04-24
    • 1970-01-01
    • 2020-08-10
    • 1970-01-01
    • 1970-01-01
    • 2017-03-04
    • 2012-04-24
    相关资源
    最近更新 更多