0

I wrote a simple implementation of a b-tree, and the problem is that it is too slow (tl9 on codeforces). What should i change to speed up this tree?

The memory limit problem can be easily fixed by increasing the constant b, but then there are time limit problems.

    class BtreeSimple
    {
        public Bnode root = new Bnode(true);
        private static int counter;
 
        public void Add(int key)
        {
            var (overkey, overflow, overvalue) = root.Insert(key, counter);
            counter++;
            if (overflow == null)
                return;
            root = new Bnode(false) {Count = 1, Keys = {[0] = overkey}, Vals = {[0] = overvalue}, Kids = {[0] = root, [1] = overflow}};
        }
    }
 
    class Bnode
    {
        const int b = 16;
        public int Count;
        public int[] Keys = new int[2 * b + 1];
        public Bnode[] Kids;
        public Bnode(bool leaf) => Kids = leaf ? null : new Bnode[2 * b + 2];
        public int[] Vals = new int[2 * b + 1];
 
        public (int, Bnode, int) Insert(int key, int value)
        {
            var i = GetKeyPosition(key);
            if (Kids == null) return InsertAt(i, key, null, value);
            var (overkey, overflow, overvalue) = Kids[i].Insert(key, value);
            return overflow == null ? (0, null, 0) : InsertAt(i, overkey, overflow, overvalue);
        }
 
        private int GetKeyPosition(int key)
        {
            var i = 0;
            while (i < Count && Keys[i] < key)
                i++;
            return i;
        }
 
        private (int, Bnode, int) InsertAt(int i, int key, Bnode keyNode, int value)
        {
            Array.Copy(Keys, i, Keys, i + 1, Count - i);
            Keys[i] = key;
            Vals[i] = value;
            if (keyNode != null)
            {
                Array.Copy(Kids, i + 1, Kids, i + 2, Count - i);
                Kids[i + 1] = keyNode;
            }
            return ++Count <= 2 * b ? (0, null, 0) : Split();
        }
 
        private (int, Bnode, int) Split()
        {
            var split = new Bnode(Kids == null) { Count = b };
            Array.Copy(Keys, b + 1, split.Keys, 0, b);
            Array.Copy(Vals, b + 1, split.Vals, 0, b);
            if (Kids != null)
                Array.Copy(Kids, b + 1, split.Kids, 0, b + 1);
            Count = b;
            return (Keys[b], split, Vals[b]);
        }
 
        public int FindNearest(int key)
        {
            var i = GetKeyPosition(key);
            if (Keys[i] == key)
                return Vals[i];
            if (Kids != null)
                return Kids[i].FindNearest(key);
            if (i >= Count)
                return Vals[i - 1]+1;
            if (Keys[i] < key)
                return Vals[i] + 1;
            return Vals[i];
        }
    }

We have a sorted array (for example arr = [8, 9, 10, 11, 15, 17, 20]) and keys (for example keys = [7, 10, 21, 20]). The task is to tell how many keys from arr are less than keys[i] for each i. For this purpose I made a methdod "FindNearest". Everything else in the code is just pure b-tree.

niripsa
  • 1
  • 1
  • Start by measuring. How long does a lookup take? Use Benchmark.Net to get accurate numbers. A profiler can also help. Can you estimate how many instructions such a lookup takes? Does your problem seem to be that you are using to many instructions or that they take to long to run? – JonasH Mar 23 '22 at 08:46
  • @JonasH the problem is that i can't get access to tests and check what does work slowly. i tried to write my own tests, with 200~ elements in array, but its not enought to test the time of each function. on my tests in works for <=o(nlogn), as it should – niripsa Mar 23 '22 at 10:21
  • Why not generate say 10^6 random values as test-data? Having the ability to benchmark and profile the code yourself would be essential to getting good performance since optimizing often involves lots of trial and error. Also, is performance graded only on lookup, or also for creating the tree? – JonasH Mar 23 '22 at 10:43
  • @JonasH the idea with random variables is good, i don't know why u didn't try iy before (maybe because i wasn't sure my tree works correctly and with big data i won't be able to check the correctness, but now i'm sure it works fine). Perfomance is graded on everything: on lookup, on values insertion etc – niripsa Mar 23 '22 at 10:53
  • My typical approach when dealing with complex algorithms is to . a) test with one or small data sets designed to identify specific problems. b) test with a large data set, ideally comparing results to a reference implementation that does the same thing in the simplest possible way. – JonasH Mar 23 '22 at 11:03

0 Answers0