我尝试找到一个 B 树的实现,尽管这个东西十分简单,但是依然网上有很多不同的版本。我在 justcoding121 的版本上魔改了一下,就是本文可以用来给大家的版本
基本上很难有啥需求需要用到 B 树,在 dotnet 里面提供了默认的 SortedList 可以解决快速搜寻的问题,在 SortedList 的实现原理是一个搜寻二叉树。当然本文不是来吹 SortedList 的实现了,继续回到 B 树的实现
因为这个 B 树也许只有在教科书上面才有用,因此比较难会用到真实的需求上,因此大部分对他的实现也仅仅是能实现出来。包括 https://github.com/justcoding121/Advanced-Algorithms 这个比较有名的项目
本文是从 https://github.com/justcoding121/Advanced-Algorithms 魔改的,最大的更改是修复命名错误问题,以及导入了 IValueComparer 接口,开放了 Find 方法
以下是使用方法,使用方法包含测试性能和对比
    internal class Program    {        private static void Main(string[] args)        {            var random = new Random();
            var stopwatch = new Stopwatch();            stopwatch.Start();
            var nairqearjojaJemjaremkes = new BTree<NairqearjojaJemjaremke>();            for (var i = 0; i < 100000; i++)            {                nairqearjojaJemjaremkes.Insert(new NairqearjojaJemjaremke                {                    WaleawhalharWogerjedearwhel = random.Next()                });            }
            stopwatch.Stop();
            Console.WriteLine(stopwatch.ElapsedTicks);
            stopwatch.Restart();
            var find = 0;            for (var i = 0; i < 1000000; i++)            {                var f = i;                if (nairqearjojaJemjaremkes.Find(n =>                    f.CompareTo(n.WaleawhalharWogerjedearwhel)) != null)                {                    find++;                }            }
            stopwatch.Stop();
            Console.WriteLine(stopwatch.ElapsedMilliseconds);            Console.WriteLine($"Find {find}");
            stopwatch.Restart();
            find = 0;
            for (var i = 0; i < 1000000; i++)            {                if (nairqearjojaJemjaremkes.Find(new NairqearjojaJemjaremke                {                    WaleawhalharWogerjedearwhel = i                }) != null)                {                    find++;                }            }
            stopwatch.Stop();
            Console.WriteLine(stopwatch.ElapsedMilliseconds);            Console.WriteLine($"Find {find}");
            stopwatch.Restart();
            find = 0;            var nairqearjojaJemjaremkeComparer = new NairqearjojaJemjaremkeComparer();
            for (var i = 0; i < 1000000; i++)            {                nairqearjojaJemjaremkeComparer.NairqearjojaJemjaremke = i;                if (nairqearjojaJemjaremkes.Find(nairqearjojaJemjaremkeComparer) != null)                {                    find++;                }            }
            stopwatch.Stop();
            Console.WriteLine(stopwatch.ElapsedMilliseconds);            Console.WriteLine($"Find {find}");
            stopwatch.Restart();            var list = new SortedList<int, NairqearjojaJemjaremke>();
            for (var i = 0; i < 100000; i++)            {                var nairqearjojaJemjaremke = new NairqearjojaJemjaremke                {                    WaleawhalharWogerjedearwhel = i                };                list.Add(nairqearjojaJemjaremke.WaleawhalharWogerjedearwhel,nairqearjojaJemjaremke);            }            stopwatch.Stop();
            Console.WriteLine(stopwatch.ElapsedMilliseconds);
            stopwatch.Restart();
            find = 0;
            for (var i = 0; i < 100000; i++)            {                if (list.TryGetValue(i,out _))                {                    find++;                }            }
            stopwatch.Stop();
            Console.WriteLine(stopwatch.ElapsedMilliseconds);            Console.WriteLine($"Find {find}");        }
        private class NairqearjojaJemjaremkeComparer : IValueComparer<NairqearjojaJemjaremke>        {            public int NairqearjojaJemjaremke { set; get; }
            /// <inheritdoc />            public int CompareTo(NairqearjojaJemjaremke value)            {                return NairqearjojaJemjaremke.CompareTo(value.WaleawhalharWogerjedearwhel);            }        }
        private class NairqearjojaJemjaremke : IComparable<NairqearjojaJemjaremke>, IComparable        {            public int WaleawhalharWogerjedearwhel { set; get; }
            /// <inheritdoc />            public int CompareTo(object? obj)            {                return CompareTo((NairqearjojaJemjaremke)obj);            }
            /// <inheritdoc />            public int CompareTo(NairqearjojaJemjaremke other)            {                if (ReferenceEquals(this, other)) return 0;                if (ReferenceEquals(null, other)) return 1;                return WaleawhalharWogerjedearwhel.CompareTo(other.WaleawhalharWogerjedearwhel);            }        }    }下面是 B 树的实现,大概可以直接复制粘贴到你的项目里面
下面代码放在 github 欢迎小伙伴访问
    /// <summary>    /// 值比较方法    /// </summary>    /// <typeparam name="T"></typeparam>    public interface IValueComparer<in T>    {        /// <summary>        /// 传入的 <paramref name="t"/> 就是存放在树里面的数据        /// <para></para>        /// 采用 <code>x.CompareTo(<paramref name="t"/>)</code> 的方法,注意判断顺序不能相反        /// </summary>        /// <param name="t"></param>        /// <returns>如果存根 x 比 <paramref name="t"/> 大,返回 1 等于返回 0 的值</returns>        int CompareTo(T t);    }
    /// <summary>    /// A B-tree implementation.    /// </summary>    /// https://github.com/justcoding121/Advanced-Algorithms    public class BTree<T> : IEnumerable<T> where T : IComparable    {        /// <summary>        /// 创建 B树        /// </summary>        /// <param name="maxKeysPerNode">默认一个 Node 有多少个数据,默认值是 3 个,注意不能传入小于3个</param>        public BTree(int maxKeysPerNode = 3)        {            if (maxKeysPerNode < 3)            {                throw new ArgumentException(                    $"Max keys per node should be atleast 3. Current value is {maxKeysPerNode}");            }
            _maxKeysPerNode = maxKeysPerNode;            _minKeysPerNode = maxKeysPerNode / 2;        }
        /// <summary>        /// 总共有多少数据        /// </summary>        public int Count { get; private set; }
        /// <summary>        /// Time complexity: O(log(n)).        /// </summary>        public T Max        {            get            {                if (Root == null) return default;
                var maxNode = FindMaxNode(Root);                return maxNode.Keys[maxNode.KeyCount - 1];            }        }
        /// <summary>        /// Time complexity: O(log(n)).        /// </summary>        public T Min        {            get            {                if (Root == null) return default;
                var minNode = FindMinNode(Root);                return minNode.Keys[0];            }        }
        public T Find(IValueComparer<T> comparer)        {            return Find(Root, comparer);        }
        public T Find(T value)        {            return Find(Root, value);        }
        public T Find(Func<T, int> comparer)        {            return Find(Root, new DelegateComparer(comparer));        }
        /// <summary>        /// Time complexity: O(log(n)).        /// </summary>        public void Insert(T newValue)        {            if (Root == null)            {                Root = new BTreeNode<T>(_maxKeysPerNode, null) { Keys = { [0] = newValue } };                Root.KeyCount++;                Count++;                return;            }
            var leafToInsert = FindInsertionLeaf(Root, newValue);            InsertAndSplit(ref leafToInsert, newValue, null, null);            Count++;        }
        /// <summary>        /// Time complexity: O(log(n)).        /// </summary>        public void Delete(T value)        {            var node = FindDeletionNode(Root, value);
            if (node == null)            {                throw new Exception("Item do not exist in this tree.");            }
            for (var i = 0; i < node.KeyCount; i++)            {                if (value.CompareTo(node.Keys[i]) != 0)                {                    continue;                }
                //if node is leaf and no underflow                //then just remove the node                if (node.IsLeaf)                {                    RemoveAt(node.Keys, i);                    node.KeyCount--;
                    Balance(node);                }                else                {                    //replace with max node of left tree                    var maxNode = FindMaxNode(node.Children[i]);                    node.Keys[i] = maxNode.Keys[maxNode.KeyCount - 1];
                    RemoveAt(maxNode.Keys, maxNode.KeyCount - 1);                    maxNode.KeyCount--;
                    Balance(maxNode);                }
                Count--;                return;            }        }
        IEnumerator IEnumerable.GetEnumerator()        {            return GetEnumerator();        }
        public IEnumerator<T> GetEnumerator()        {            return new BTreeEnumerator<T>(Root);        }
        private readonly int _maxKeysPerNode;        private readonly int _minKeysPerNode;
        private BTreeNode<T> Root { set; get; }
        private static T Find(BTreeNode<T> node, IValueComparer<T> comparer)        {            //if leaf then its time to insert            if (node.IsLeaf)            {                for (var i = 0; i < node.KeyCount; i++)                {                    var value = node.Keys[i];                    if (comparer.CompareTo(value) == 0)                    {                        return value;                    }                }            }            else            {                //if not leaf then drill down to leaf                for (var i = 0; i < node.KeyCount; i++)                {                    var value = node.Keys[i];                    if (comparer.CompareTo(value) == 0)                    {                        return value;                    }
                    //current value is less than new value                    //drill down to left child of current value                    if (comparer.CompareTo(value) < 0)                    {                        return Find(node.Children[i], comparer);                    }                    //current value is grearer than new value                    //and current value is last element
                    if (node.KeyCount == i + 1)                    {                        return Find(node.Children[i + 1], comparer);                    }                }            }
            return default;        }
        /// <summary>        /// Find the value node under given node.        /// </summary>        private static T Find(BTreeNode<T> node, T value)        {            return Find(node, new DefaultComparer(value));        }
        /// <summary>        /// Find the leaf node to start initial insertion        /// </summary>        private static BTreeNode<T> FindInsertionLeaf(BTreeNode<T> node, T newValue)        {            //if leaf then its time to insert            if (node.IsLeaf)            {                return node;            }
            //if not leaf then drill down to leaf            for (var i = 0; i < node.KeyCount; i++)            {                //current value is less than new value                //drill down to left child of current value                if (newValue.CompareTo(node.Keys[i]) < 0)                {                    return FindInsertionLeaf(node.Children[i], newValue);                }                //current value is grearer than new value                //and current value is last element
                if (node.KeyCount == i + 1)                {                    return FindInsertionLeaf(node.Children[i + 1], newValue);                }            }
            return node;        }
        /// <summary>        /// Insert and split recursively up until no split is required        /// </summary>        private void InsertAndSplit(ref BTreeNode<T> node, T newValue,            BTreeNode<T> newValueLeft, BTreeNode<T> newValueRight)        {            //add new item to current node            if (node == null)            {                node = new BTreeNode<T>(_maxKeysPerNode, null);                Root = node;            }
            //newValue have room to fit in this node            //so just insert in right spot in asc order of keys            if (node.KeyCount != _maxKeysPerNode)            {                InsertToNotFullNode(ref node, newValue, newValueLeft, newValueRight);                return;            }
            //if node is full then split node            //and  then insert new median to parent.
            //divide the current node values + new Node as left and right sub nodes            var left = new BTreeNode<T>(_maxKeysPerNode, null);            var right = new BTreeNode<T>(_maxKeysPerNode, null);
            //median of current Node            var currentMedianIndex = node.GetMedianIndex();
            //init currentNode under consideration to left            var currentNode = left;            var currentNodeIndex = 0;
            //new Median also takes new Value in to Account            var newMedian = default(T);            var newMedianSet = false;            var newValueInserted = false;
            //keep track of each insertion            var insertionCount = 0;
            //insert newValue and existing values in sorted order            //to left and right nodes            //set new median during sorting            for (var i = 0; i < node.KeyCount; i++)            {                //if insertion count reached new median                //set the new median by picking the next smallest value                if (!newMedianSet && insertionCount == currentMedianIndex)                {                    newMedianSet = true;
                    //median can be the new value or node.keys[i] (next node key)                    //whichever is smaller                    if (!newValueInserted && newValue.CompareTo(node.Keys[i]) < 0)                    {                        //median is new value                        newMedian = newValue;                        newValueInserted = true;
                        if (newValueLeft != null)                        {                            SetChild(currentNode, currentNode.KeyCount, newValueLeft);                        }
                        //now fill right node                        currentNode = right;                        currentNodeIndex = 0;
                        if (newValueRight != null)                        {                            SetChild(currentNode, 0, newValueRight);                        }
                        i--;                        insertionCount++;                        continue;                    }
                    //median is next node                    newMedian = node.Keys[i];
                    //now fill right node                    currentNode = right;                    currentNodeIndex = 0;
                    continue;                }
                //pick the smaller among newValue and node.Keys[i]                //and insert in to currentNode (left and right nodes)                //if new Value was already inserted then just copy from node.Keys in sequence                //since node.Keys is already in sorted order it should be fine                if (newValueInserted || node.Keys[i].CompareTo(newValue) < 0)                {                    currentNode.Keys[currentNodeIndex] = node.Keys[i];                    currentNode.KeyCount++;
                    //if child is set don't set again                    //the child was already set by last newValueRight or last node                    if (currentNode.Children[currentNodeIndex] == null)                    {                        SetChild(currentNode, currentNodeIndex, node.Children[i]);                    }
                    SetChild(currentNode, currentNodeIndex + 1, node.Children[i + 1]);                }                else                {                    currentNode.Keys[currentNodeIndex] = newValue;                    currentNode.KeyCount++;
                    SetChild(currentNode, currentNodeIndex, newValueLeft);                    SetChild(currentNode, currentNodeIndex + 1, newValueRight);
                    i--;                    newValueInserted = true;                }
                currentNodeIndex++;                insertionCount++;            }
            //could be that thew newKey is the greatest            //so insert at end            if (!newValueInserted)            {                currentNode.Keys[currentNodeIndex] = newValue;                currentNode.KeyCount++;
                SetChild(currentNode, currentNodeIndex, newValueLeft);                SetChild(currentNode, currentNodeIndex + 1, newValueRight);            }
            //insert overflow element (newMedian) to parent            var parent = node.Parent;            InsertAndSplit(ref parent, newMedian, left, right);        }
        /// <summary>        /// Insert to a node that is not full        /// </summary>        private static void InsertToNotFullNode(ref BTreeNode<T> node, T newValue,            BTreeNode<T> newValueLeft, BTreeNode<T> newValueRight)        {            var inserted = false;
            //insert in sorted order            for (var i = 0; i < node.KeyCount; i++)            {                if (newValue.CompareTo(node.Keys[i]) >= 0)                {                    continue;                }
                InsertAt(node.Keys, i, newValue);                node.KeyCount++;
                //Insert children if any                SetChild(node, i, newValueLeft);                InsertChild(node, i + 1, newValueRight);
                inserted = true;                break;            }
            //newValue is the greatest            //element should be inserted at the end then            if (inserted)            {                return;            }
            node.Keys[node.KeyCount] = newValue;            node.KeyCount++;
            SetChild(node, node.KeyCount - 1, newValueLeft);            SetChild(node, node.KeyCount, newValueRight);        }
        /// <summary>        /// return the node containing max value which will be a leaf at the right most        /// </summary>        private static BTreeNode<T> FindMinNode(BTreeNode<T> node)        {            //if leaf return node            return node.IsLeaf ? node : FindMinNode(node.Children[0]);        }
        /// <summary>        /// return the node containing max value which will be a leaf at the right most        /// </summary>        private static BTreeNode<T> FindMaxNode(BTreeNode<T> node)        {            //if leaf return node            return node.IsLeaf ? node : FindMaxNode(node.Children[node.KeyCount]);        }
        /// <summary>        /// Balance a node which is short of Keys by rotations or merge        /// </summary>        private void Balance(BTreeNode<T> node)        {            if (node == Root || node.KeyCount >= _minKeysPerNode)            {                return;            }
            var rightSibling = GetRightSibling(node);
            if (rightSibling != null                && rightSibling.KeyCount > _minKeysPerNode)            {                LeftRotate(node, rightSibling);                return;            }
            var leftSibling = GetLeftSibling(node);
            if (leftSibling != null                && leftSibling.KeyCount > _minKeysPerNode)            {                RightRotate(leftSibling, node);                return;            }
            if (rightSibling != null)            {                Sandwich(node, rightSibling);            }            else            {                Sandwich(leftSibling, node);            }        }
        /// <summary>        ///  merge two adjacent siblings to one node        /// </summary>        private void Sandwich(BTreeNode<T> leftSibling, BTreeNode<T> rightSibling)        {            var separatorIndex = GetNextSeparatorIndex(leftSibling);            var parent = leftSibling.Parent;
            var newNode = new BTreeNode<T>(_maxKeysPerNode, leftSibling.Parent);            var newIndex = 0;
            for (var i = 0; i < leftSibling.KeyCount; i++)            {                newNode.Keys[newIndex] = leftSibling.Keys[i];
                if (leftSibling.Children[i] != null)                {                    SetChild(newNode, newIndex, leftSibling.Children[i]);                }
                if (leftSibling.Children[i + 1] != null)                {                    SetChild(newNode, newIndex + 1, leftSibling.Children[i + 1]);                }
                newIndex++;            }
            //special case when left sibling is empty            if (leftSibling.KeyCount == 0 && leftSibling.Children[0] != null)            {                SetChild(newNode, newIndex, leftSibling.Children[0]);            }
            newNode.Keys[newIndex] = parent.Keys[separatorIndex];            newIndex++;
            for (var i = 0; i < rightSibling.KeyCount; i++)            {                newNode.Keys[newIndex] = rightSibling.Keys[i];
                if (rightSibling.Children[i] != null)                {                    SetChild(newNode, newIndex, rightSibling.Children[i]);                }
                if (rightSibling.Children[i + 1] != null)                {                    SetChild(newNode, newIndex + 1, rightSibling.Children[i + 1]);                }
                newIndex++;            }
            //special case when left sibling is empty            if (rightSibling.KeyCount == 0 && rightSibling.Children[0] != null)            {                SetChild(newNode, newIndex, rightSibling.Children[0]);            }
            newNode.KeyCount = newIndex;            SetChild(parent, separatorIndex, newNode);            RemoveAt(parent.Keys, separatorIndex);            parent.KeyCount--;
            RemoveChild(parent, separatorIndex + 1);
            if (parent.KeyCount == 0                && parent == Root)            {                Root = newNode;                Root.Parent = null;
                if (Root.KeyCount == 0)                {                    Root = null;                }
                return;            }
            if (parent.KeyCount < _minKeysPerNode)            {                Balance(parent);            }        }
        /// <summary>        /// do a right rotation        /// </summary>        private static void RightRotate(BTreeNode<T> leftSibling, BTreeNode<T> rightSibling)        {            var parentIndex = GetNextSeparatorIndex(leftSibling);
            InsertAt(rightSibling.Keys, 0, rightSibling.Parent.Keys[parentIndex]);            rightSibling.KeyCount++;
            InsertChild(rightSibling, 0, leftSibling.Children[leftSibling.KeyCount]);
            rightSibling.Parent.Keys[parentIndex] = leftSibling.Keys[leftSibling.KeyCount - 1];
            RemoveAt(leftSibling.Keys, leftSibling.KeyCount - 1);            leftSibling.KeyCount--;
            RemoveChild(leftSibling, leftSibling.KeyCount + 1);        }
        /// <summary>        /// do a left rotation        /// </summary>        private static void LeftRotate(BTreeNode<T> leftSibling, BTreeNode<T> rightSibling)        {            var parentIndex = GetNextSeparatorIndex(leftSibling);            leftSibling.Keys[leftSibling.KeyCount] = leftSibling.Parent.Keys[parentIndex];            leftSibling.KeyCount++;
            SetChild(leftSibling, leftSibling.KeyCount, rightSibling.Children[0]);
            leftSibling.Parent.Keys[parentIndex] = rightSibling.Keys[0];
            RemoveAt(rightSibling.Keys, 0);            rightSibling.KeyCount--;
            RemoveChild(rightSibling, 0);        }
        /// <summary>        /// Locate the node in which the item to delete exist        /// </summary>        private static BTreeNode<T> FindDeletionNode(BTreeNode<T> node, T value)        {            //if leaf then its time to insert            if (node.IsLeaf)            {                for (var i = 0; i < node.KeyCount; i++)                {                    if (value.CompareTo(node.Keys[i]) == 0)                    {                        return node;                    }                }            }            else            {                //if not leaf then drill down to leaf                for (var i = 0; i < node.KeyCount; i++)                {                    if (value.CompareTo(node.Keys[i]) == 0)                    {                        return node;                    }
                    //current value is less than new value                    //drill down to left child of current value                    if (value.CompareTo(node.Keys[i]) < 0)                    {                        return FindDeletionNode(node.Children[i], value);                    }                    //current value is grearer than new value                    //and current value is last element
                    if (node.KeyCount == i + 1)                    {                        return FindDeletionNode(node.Children[i + 1], value);                    }                }            }
            return null;        }
        /// <summary>        /// Get next key separator index after this child Node in parent        /// </summary>        private static int GetNextSeparatorIndex(BTreeNode<T> node)        {            var parent = node.Parent;
            if (node.Index == 0)            {                return 0;            }
            if (node.Index == parent.KeyCount)            {                return node.Index - 1;            }
            return node.Index;        }
        /// <summary>        /// get the right sibling node        /// </summary>        private static BTreeNode<T> GetRightSibling(BTreeNode<T> node)        {            var parent = node.Parent;
            return node.Index == parent.KeyCount ? null : parent.Children[node.Index + 1];        }
        /// <summary>        /// get left sibling node        /// </summary>        private static BTreeNode<T> GetLeftSibling(BTreeNode<T> node)        {            return node.Index == 0 ? null : node.Parent.Children[node.Index - 1];        }
        private static void SetChild(BTreeNode<T> parent, int childIndex, BTreeNode<T> child)        {            parent.Children[childIndex] = child;
            if (child == null)            {                return;            }
            child.Parent = parent;            child.Index = childIndex;        }
        private static void InsertChild(BTreeNode<T> parent, int childIndex, BTreeNode<T> child)        {            InsertAt(parent.Children, childIndex, child);
            if (child != null)            {                child.Parent = parent;            }
            //update indices            for (var i = childIndex; i <= parent.KeyCount; i++)            {                if (parent.Children[i] != null)                {                    parent.Children[i].Index = i;                }            }        }
        private static void RemoveChild(BTreeNode<T> parent, int childIndex)        {            RemoveAt(parent.Children, childIndex);
            //update indices            for (var i = childIndex; i <= parent.KeyCount; i++)            {                if (parent.Children[i] != null)                {                    parent.Children[i].Index = i;                }            }        }
        /// <summary>        /// Shift array right at index to make room for new insertion        /// And then insert at index        /// Assumes array have atleast one empty index at end        /// </summary>        private static void InsertAt<TS>(TS[] array, int index, TS newValue)        {            //shift elements right by one indice from index            Array.Copy(array, index, array, index + 1, array.Length - index - 1);            //now set the value            array[index] = newValue;        }
        /// <summary>        /// Shift array left at index        /// </summary>        private static void RemoveAt<TS>(TS[] array, int index)        {            //shift elements right by one indice from index            Array.Copy(array, index + 1, array, index, array.Length - index - 1);        }
        private class DelegateComparer : IValueComparer<T>        {            public DelegateComparer(Func<T, int> comparer)            {                _comparer = comparer;            }
            /// <inheritdoc />            public int CompareTo(T t)            {                return _comparer(t);            }
            private readonly Func<T, int> _comparer;        }
        private class DefaultComparer : IValueComparer<T>        {            public DefaultComparer(T compareObject)            {                CompareObject = compareObject;            }
            /// <inheritdoc />            public int CompareTo(T t)            {                return CompareObject.CompareTo(t);            }
            private T CompareObject { get; }        }    }
    /// <summary>    /// abstract node shared by both B and B+ tree nodes    /// so that we can use this for common tests across B and B+ tree    /// </summary>    internal abstract class BNode<T> where T : IComparable    {        internal BNode(int maxKeysPerNode)        {            Keys = new T[maxKeysPerNode];        }
        /// <summary>        /// Array Index of this node in parent's Children array        /// </summary>        internal int Index { set; get; }
        internal T[] Keys { get; }        internal int KeyCount { get; set; }
        //for common unit testing across B and B+ tree        internal abstract BNode<T> GetParent();        internal abstract BNode<T>[] GetChildren();
        internal int GetMedianIndex()        {            return (KeyCount / 2) + 1;        }    }
    internal class BTreeNode<T> : BNode<T> where T : IComparable    {        internal BTreeNode(int maxKeysPerNode, BTreeNode<T> parent)            : base(maxKeysPerNode)        {            Parent = parent;            Children = new BTreeNode<T>[maxKeysPerNode + 1];        }
        internal BTreeNode<T> Parent { get; set; }        internal BTreeNode<T>[] Children { get; }
        internal bool IsLeaf => Children[0] == null;
        /// <summary>        /// For shared test method accross B and B+ tree        /// </summary>        internal override BNode<T> GetParent()        {            return Parent;        }
        /// <summary>        /// For shared test method accross B and B+ tree        /// </summary>        internal override BNode<T>[] GetChildren()        {            return Children;        }    }
    internal class BTreeEnumerator<T> : IEnumerator<T> where T : IComparable    {        internal BTreeEnumerator(BTreeNode<T> root)        {            _root = root;        }
        public bool MoveNext()        {            if (_root == null)            {                return false;            }
            if (_progress == null)            {                _current = _root;                _progress = new Stack<BTreeNode<T>>(_root.Children.Take(_root.KeyCount + 1).Where(x => x != null));                return _current.KeyCount > 0;            }
            if (_current != null && _index + 1 < _current.KeyCount)            {                _index++;                return true;            }
            if (_progress.Count > 0)            {                _index = 0;
                _current = _progress.Pop();
                foreach (var child in _current.Children.Take(_current.KeyCount + 1).Where(x => x != null))                {                    _progress.Push(child);                }
                return true;            }
            return false;        }
        public void Reset()        {            _progress = null;            _current = null;            _index = 0;        }
        object IEnumerator.Current => Current;
        public T Current => _current.Keys[_index];
        public void Dispose()        {            _progress = null;        }
        private readonly BTreeNode<T> _root;
        private BTreeNode<T> _current;        private int _index;        private Stack<BTreeNode<T>> _progress;    } 
   本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。 欢迎转载、使用、重新发布,但务必保留文章署名 林德熙 (包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我 联系。