Construct a BTree from a sorted array

Viewed 589

I need to construct a BTree from a sorted array. Any pointers or how can i write such an algorithm? Is there any algoritm that can take advantage of the array being sorted?

I did search it on the google but could not find algorithm for BTree.

3 Answers

The way of @rossum is simple, but it is not efficient. His proposal don't use the information, that have a sorted list.
I think, that you have solved the problem of equal keys. (Nodes of the BTree or List in one Node of the BTree)

I understand your question in this way:

You want convert a sorted list/arry directly to a btree with the degree t. I have only a guess/idea. Detect the point of

  1. Step Detect the minimal height h for a given number of elements n be caclulation the range of min and max elements for the given height of a BTree.

    n(max) = sum(i=0,i<=h){Res += t^i*(t-1)}

    n(min) = sum(i=0,i<h){Res += ceil(t/2)^i*(ceil(t/2)-1))} // ceil the result of the divisions

  2. Step Minimize the range between t and t/2 to t>=x(high) and x(Low)>=(t/2), while n is in the range of x(low) and x(max) 3.Step calculation rekursive the node, where you have to change vorm x(high) to x(Low)

  3. step Construct your BTree, which contains internal nodes with degree (x(high)) and which contains leaves with (x(High)-1) internal keys until you reach your reference node. After reaching your reference node all internal nodes have x(low)=x(high)-1 degrees and all leaf-nodes habe x(low) keys.

But this is only an idea. I havn't programmed it.

@padina Your pretty right. I build something in python for my work. I shrinked it down to the minimum code. Maybe you want to take a look at dbis-btree-git

So it's more pseudocode:

def valuesInFullTree(self):
        '''
        Determine the number of int-values for corresponding 
        valuesCountInOneNode, and height value

        self   : BTree_Creator
        return : int
        '''
        if self.height < 0 or self.valuesCountInOneNode < 0:
            return 0

        count = self.valuesCountInOneNode
        curHeight = 1
        for _ in range(0,self.height):
            count += pow(self.valuesCountInOneNode+1,curHeight)*self.valuesCountInOneNode
            curHeight += 1
        return count
    

def buildTree(self):
        '''
        This method builds first a full BTree. 
        
        self : BTree_Creator
        '''
        neededValuesCount = self.valuesInFullTree()
        if neededValuesCount >  self.maxValueInTree:
            raise ValueError('Please use a bigger values for self.maxValueInTree, at least bigger than '+str(neededValuesCount))
        
        valuesInTree = random.sample(range(1, self.maxValueInTree), neededValuesCount)
        valuesInTree.sort()
        # build a BTree with only values from valuesInTree
        stackForRecursion = [(0,None,valuesInTree,0)]
        self.rekursivSplitArray(stackForRecursion)

def rekursivSplitArray(self, stackForRecursion):
        '''
        Split Array and generate from new Splitpoints a Node in the Tree
        stackForRecursion = [(nodeName, parentNode, values, currentHeight), ( ... ]

        stackForRecursion                             : array with tupels
        (nodeName, parentNode, values, currentHeight) : (int, int/None, int-array, int)
        '''
        if len(stackForRecursion) == 0:
            return
        (nodeName, parentNode, values,
         currentHeight) = stackForRecursion.pop(0)
        
        # self.height must be defined
        if currentHeight > self.height:
            return

        valuesForNode = values

        if currentHeight < self.height:
            # there are children for the current node
            firstSplitIdx = len(values)/(self.valuesCountInOneNode+1)
            splitPointIdx = firstSplitIdx
            previousSplitIdx = 0
            valuesForNode = []
            nextNodeName = nodeName * (self.valuesCountInOneNode + 1)


            for i in range(0,self.valuesCountInOneNode+1):
                if i < self.valuesCountInOneNode:
                    valuesForNode.append(values[int(splitPointIdx)])
                
                nextNodeName += 1
                nodeTupel = (nextNodeName, nodeName,
                            values[int(previousSplitIdx):int(splitPointIdx)],
                            currentHeight + 1)

                stackForRecursion.append(nodeTupel)

                previousSplitIdx = splitPointIdx + 1
                splitPointIdx += firstSplitIdx
        else:
            if len(valuesForNode) != self.valuesCountInOneNode:
                raise ValueError('The rekursiv tree build algo doesnt work')

        
        # add Node to myBBaum
# pay ATTENTION this add_node, and add_edge lwad to an error...
         self.myBBaum.add_node(BTree_Creator.getNodeName(nodeName), valuesForNode)
        # add Edge to myBBaum
        if parentNode != None:
            thisNodeIsChildNumber = (nodeName % (self.valuesCountInOneNode + 1))
            if thisNodeIsChildNumber == 0:
                thisNodeIsChildNumber = self.valuesCountInOneNode + 1

            self.myBBaum.add_edge(BTree_Creator.getNodeName(parentNode),
                                  BTree_Creator.getNodeName(nodeName),
                                  thisNodeIsChildNumber)
        
        
        
    
        # rekursiv call
        for _ in range(0, self.valuesCountInOneNode + 1):
            self.rekursivSplitArray(stackForRecursion)

# insert a number and it return the letter combination
    # for ex: 2=B,3=C,27=AA
    @staticmethod
    def getNodeName(num):
        numOfA_s = num // 26
        nodeName = ''
        for _ in range(0, numOfA_s):
            nodeName += 'A'

        return nodeName + str(chr((num % 26) + ord('A')))

    # insert a number and it return the letter combination
    # for ex: B=2,C=3,AA=27
    @staticmethod
    def convertNodeNameInNumber(name):
        number = -ord('A')
        for char in name:
            number += ord(char)

        return number

Here’s a simple and efficient algorithm for building the B-tree. First, an observation. If you insert all the values in the sorted sequence in order, then each newly-inserted element will end up being placed in the rightmost leaf node of the tree. From there, you may have too many keys in the rightmost leaf, and you can then use the regular B-tree insertion algorithm to split the node and kick keys higher up in the tree.

So here’s the algorithm: maintain a pointer to the rightmost leaf node. For each element in the sorted sequence, place that item as the largest item in the rightmost leaf. If the leaf overflows, use the regular B-tree insertion fix up logic to split the node and kick a key higher in the tree.

Intuitively, almost all of the insertions you do will not require a split and will run in time O(1) - just follow a pointer and place the key. A small fraction will require one split and kick a key higher up in the tree. An even smaller fraction will require two splits, an even smaller will require three, etc. By either counting exactly how many inserts will require splitting multiple keys or using an amortized analysis, you can show that the total work required here is O(n), which is as fast as you’re going to be able to get things in an asymptotic sense.

Related