580 likes | 1.13k Views
Chapter 10. Multiway Trees. An m -way tree is a search tree where nodes can have 0 to m (where m = order) sub-trees A Binary Search Tree is an m -way tree of order 2 Properties: Each node has 0 to m sub-trees
E N D
Chapter 10 Multiway Trees
An m-way tree is a search tree where nodes can have 0 to m (where m = order) sub-trees A Binary Search Tree is an m-way tree of order 2 Properties: Each node has 0 to m sub-trees A node with k < m sub-trees contains k sub-tree pointers, some of which may be null, and k – 1 data entries Key values in first sub-tree are all less than key value in the first entry; key values in other sub-trees are all greater than or equal to key value in their parent entry Keys of data entries are ordered key1 <= key2 <= ... <=keyk All sub-trees are themselves multi-way trees m-way trees
There is always one more pointer than there are entries in each node First pointer identifies all sub-trees that contain keys less than first entry in the node An entry count field tracks number of entries in each node Each entry has a data field and a pointer to its right sub-tree, that has keys greater than or equal to the entry Observations
A B-tree is an m-way search tree with these additional properties: The root is either a leaf or it has 2...m sub-trees All internal nodes have at least upper limit of [m/2] non-null sub-trees and at most m non-null sub-trees All leaf nodes are at the same level (perfectly balanced) A leaf node has at least upper limit of [m/2] - 1 and at most m - 1 entries A B-tree is a perfectly balanced m-way tree where each node (with exception of root) is at least half full B-Trees
Insertions take place at a leaf node, after a searching for the correct insert location A B-Tree grows from the bottom up (from leaves to root) An overfull occurs when a leaf node is full; this requires node to be split into two nodes: New memory is allocated for a parent node Half of the node values are split on the left, and half on the right (this excludes median value node) The node with the median value will become the parent B-Tree Insertion
algorithm BTreeInsert (ref tree <pointer>, val data <record>) if (tree null) Empty tree. Insert first node. allocate (newPtr) if (allocate successful) newPtr->firstPtr = null newPtr->numEntries = 1 newPtr->entries[0].data = dataIn newPtr->entries[0].rightPtr = null tree = newPtr return true else abort program (Out of memory) end if end if taller = insertNode (tree, data, upEntry) Algorithm 10-1 B-tree insert
if (taller true) Tree has grown. Create new root allocate (newPtr) if (allocate successful) newPtr->entries[0] = upEntry newPtr->firstPtr = tree newPtr->numEntries = 1 tree = newPtr else abort program (Out of Memory) endif end if return end BTreeInsert Algorithm 10-1 B-tree insert (Cont'd)
algorithm insertNode (ref root <pointer>, val dataIn <data type>, ref upEntry <entry>) if (root null) upEntry.data = dataIn upEntry.rightPtr = null taller = true return taller end if entryNdx = searchNode (root, data.key) newEntryLow = dataIn.key < root->entries[entryNdx].data.key if (entryNdx equal 0 and newEntryLow) subTree = root->firstPtr else subTree = root->entries[entryNdx].rightPtr endif Algorithm 10-2 B-tree insert node
taller = insertNode (subTree, data, upEntry) if (taller) if (node full) splitNode (root, entryNdx, newEntryLow, upEntry) taller = true else if (newEntryLow) insertEntry (root, entryNdx, upEntry) else insertEntry (root, entryNdx + 1, upEntry) end if root->numEntries = root->numEntries + 1 taller = false end if end if return taller end insertNode Algorithm 10-2 B-tree insert node (cont'd)
Figure 10-7 Build B-tree, first overflow 3 4 7 minEntries = 2 entryNdx = 0 newEntryLow = false root = {21, 57, 78} subTree = {42, 45, 63, 74} 0 entryNdx = 1 newEntryLow = false root = {42, 45, 63, 74} subTree = Null (rightPtr of 45) fromNdx = 2 toNdx = 2 splitNode(root, 1, false, upEntry) 1 entryNdx = 1 root = Null taller = true dataIn = 57 1
algorithm searchNode (val nodePtr <pointer>, val target <key>) if (target < nodePtr->entry[0].data.key) walker = 0 else Sequential searching from end to beginning walker = nodePtr->numEntries – 1 loop (walker > 0 AND target < nodePtr->entries[walker].data.key) walker = walker – 1 end loop end if return walker end searchNode Algorithm 10-3 B-tree search node
algorithm splitNode (ref node <pointer>, val entryNdx <index>, val newEntryLow <Boolean>, ref upEntry <entry>) minEntries = minimum number of entries allocate (rightPtr) Build right subtree node if (entryNdx < minEntries) fromNdx = minEntries else fromNdx = minEntries + 1 end if toNdx = 0 rightPtr->numEntries = node->numEntries – fromNdx loop (fromNdx < node->numEntries) rightPtr->entries[toNdex] = node->entries[fromNdx] toNdx = toNdx + 1 fromNdx = fromNdx + 1 end loop node->numEntries = node->numEntries – rightPtr->numEntries Algorithm 10-4 B-tree split node
if (entryNdx < minEntries) Insert in original (lower) node if (newEntryLow) insertEntry (node, entryNdx, upEntry) else insertEntry (node, entryNdx + 1, upEntry) end if else Insert in new (right node) insertEntry(rightPtr, entryNdx – minEntries, upEntry) rightPtr->numEntries = rightPtr->numEntries + 1 node->numEntries = node->numEntries – 1 Build entry for parent end if upEntry.data = node->entries[minEntries].data upEntry.rightPtr = rightPtr rightPtr->firstPtr = node->entries[minEntries].rightPtr return end splitNode Algorithm 10-4 B-tree split node (Cont'd)
Figure 10-8 Split node B-tree order of 5 a) New entry <= median 2 2 2 2 2 2 ≤
Figure 10-8 Split node B-tree order of 5 b) New entry > median 3 3 2 3 3 2 3 3 2 3
algorithm insertEntry (val node <pointer>, val insertNdx <key>, val newEntry <entry>) shifter = node->numEntries loop (shifter > insertNdx) node->entries[shifter] = node->entries[shifter - 1] shifter = shifter -1 end loop node->entries[shifter] = newEntry return end insertEntry Algorithm 10-5 B-tree insert entry
algorithm BTreeDelete (ref tree <pointer>, val dltKey <key>) if (tree empty) return false end if delete (tree, dltKey, success) if (success) if (tree->numEntries is zero) Tree is shorter -- delete root dltPtr = tree tree = tree->firstPtr recycle (dltPtr) end if end if return success end BTreeDelete Algorithm 10-6 B-tree delete
algorithm delete (ref root <pointer>, val deleteKey <key>, ref success <Boolean>) if (root null) Leaf node found – deleteKey key does not exist return false end if entryNdx = searchNode (root, deleteKey) if (deleteKey equal root->entries[entryNdx].data.key) Found entry to be deleted success = true if (root->entries[entryNdx].rightPtr is null) Entry is a leaf node underflow = deleteEntry (root, entryNdx) else Entry is in internal node if (entryNdx > 0) leftPtr = root->entries[entryNdx – 1].rightPtr else leftPtr = root->firstPtr end if underflow = deleteMid (root, entryNdx, leftPtr) if (underflow) underflow = reFlow (root, entryNdx) end if end if Algorithm 10-7 B-tree node delete
else if (deleteKey < root->entries[0].data.key) deleteKey less than first entry subtree = root->firstPtr else deleteKey is in right subtree subtree = root->entries[entryNdx].rightPtr end if underflow = delete (subtree, deleteKey, success) if (underflow) underflow = reFlow (root, entryNdx) end if end if return underflow end delete Algorithm 10-7 B-tree node delete (cont'd)
algorithm deleteEntry (ref node <pointer>, val entryNdx <key>) shifter = entryNdx + 1 loop (shifter <= node->numEntries) node->entries[shifter - 1] = node->entries[shifter] shifter = shifter + 1 end loop node->numEntries = node->numEntries - 1 if (node->numEntries < minimum entries return true else return false end if end deleteEntry Algorithm 10-8 B-tree delete entry
algorithm deleteMid (ref root <pointer>, val entryNdx <index>, val subtree <pointer>) if (subtree->firstPtr null) Leaf located. Exchange data and delete leaf entry deleteNdx = subtree->numEntries – 1 root->entries[entryNdx].data = subtree->entries[deleteNdx].data deleteNdx = subtree->numEntries - 1 subtree->entries[deleteNdx].data subtree->numEntries = subtree->numEntries – 1 underflow = subtree->numEntries < minimum entries else Not located. Traverse right to locate predecessor right = subtree->numEntries – 1 underflow = deleteMid (root, entryNdx, subtree-> entries[right].rightPtr) if (underflow) underflow = reFlow (subtree, rightNdx) end if end if return underflow end deleteMid Algorithm 10-9 B-tree delete mid
Figure 10-11 B-tree deletions 3 4 • 1 dltPtr = tree • 2 tree = tree->firstPtr • 3 recycle(dltPtr) • 5 end if • 6 return success 0 1 1
algorithm reFlow (ref root <pointer>, val entryNdx <index>) Try to borrow first. Located subtree with available entry. if (entryNdx equal 0) leftTree = root->firstPtr else leftTree = root->entries[entryNdx – 1].rightPtr end if rightTree = root->entries[entryNdx].rightPtr if (rightTree->numEntries > minimum entries) borrowRight (root, entryNdx, leftTree, rightTree) underflow = false Algorithm 10-10 B-tree underflow reFlow
else Can't balance from right. Try left if (leftTree->numEntries > minimum entrees) borrowLeft (root, entryNdx, leftTree, rightTree) underflow = false else Can't borrow. Must combine entries combine (root, entryNdx, leftTree, rightTree) if (root->numEntries < minimum entries) underflow = true else underflow = false end if end if end if return underflow end reFlow Algorithm 10-10 B-tree underflow reFlow (cont'd)
algorithm borrowLeft (ref root <pointer>, val entryNdx <key>, val left <pointer>, val right <pointer>) Shift entries right to make room for new data shifter = right>numEntries loop (shifter > 0) right->entries[shifter] = right->entries[shifter - 1] shifter = shifter -1 end loop Move parent data down and reset right pointer right->entries[0].data = root->entries[entryNdx].data right->entries[0].rightPtr = right->firstPtr Moved entry's rightPtr becomes right tree first pointer fromNdx = left->numEntries – 1 right->firstPtr = left->entries[fromNdx].rightPtr right->numEntries = right->numEntries + 1 Move data from left to parent root->entries[entryNdx].data = left->entries[fromNdx].data left->numEntries = left->numEntries - 1 return end borrowLeft Algorithm 10-11 B-tree borrow left
algorithm borrowRight (ref root <pointer>, val entryNdx <key>, val left <pointer>, val right <pointer>) Move parent and subtree pointer to left tree toNdx = left->numEntries left->entries[toNdx].data = root->entries[entryNdx].data left->entries[toNdx].rightPtr = right->firstPtr left->numEntries = left->numEntries + 1 Move right data to parent root->entries[entryNdx].data = right->entries[0].data Set right tree first pointer and shift data right->firstPtr = right->entries[0].rightPtr shifter = 0 loop (shifter < right->numEntries – 1) right->entries[shifter] = right->entries[shifter + 1] shifter = shifter + 1 end loop right->numEntries = right->numEntries - 1 return end borrowRight Algorithm 10-12 B-tree borrow right
algorithm combine (ref root <pointer>, val entryNdx <key>, val left <pointer>, val right <pointer>) Move parent and set its rightPtr from right tree toNdx = left->numEntries left->entries[toNdx].data = root->entries[entryNdx].data left->entries[toNdx].rightPtr = right->firstPtr left->numEntries = left->numEntries + 1 root->numEntries = root->numEntries - 1 Move data from right tree to left tree frNdx = 0 toNdx = toNdx + 1 loop (frNdx < right->numEntries) left->entries[toNdx] = right->entries[frNdx] toNdx = toNdx + 1 frNdx = frNdx + 1 end loop left->numEntries = left->numEntries + right->numEntries recycle (right) Now shift data in root to the left shifter = entryNdx loop (shifter < root->numEntries) root->entries[shifter] = root->entries[shifter + 1] shifter = shifter + 1 end loop return end combine Algorithm B-tree combine
algorithm BTreeTraversal (val root <pointer>) scanCount = 0 ptr = root->firstPtr loop (scanCount <= root->numEntries) Test for subtree if (ptr not null) BTreeTraversal (ptr) end if Subtree processed –- get next entry if (scanCount < root->numEntries) process (root->entries[scanCount].data ptr = root->entires[scanCount].rightPtr end if scanCount = scanCount + 1 end loop return end insertEntry Algorithm 10-14 B-tree traversal
algorithm BTreeSearch (val root <pointer>, val srchKey <key>, ref node < pointer> ref foundLoc <index>) if (emtpy tree) return false end if if (srchKey < first entry) return BTreeSearch (root->firstPtr, srchKey, node, foundLoc) end if foundLoc = root->numEntries - 1 loop (srchKey < root->entries[foundLoc].data.key) foundLoc = foundLoc - 1 end loop if (srchKey equal root->entries[foundLoc].data.key) node = root return true end if return BTreeSearch (root->entries[foundLoc].rightPtr, srchKey, node, foundLoc) end BTreeSearch Algorithm 10-15 B-tree search
Specialized B-Trees have unique names: 2-3 tree (B-tree of order 3) Each non-root node has two or three sub-trees The root may have zero, two, or three sub-trees 2-3-4 tree (B-tree of order 4) Each node can have two, three, or four children Simplified B-Trees
B*Tree When node overflows, data are redistributed among the node's siblings. Splitting occurs only when all siblings are full When nodes are split, data from two full siblings are divided among the two full nodes and a new node: all three nodes are two-thirds full B-Tree Variations
B+Tree Enables random and sequential data processing Each data entry must be represented at the leaf level. Internal nodes (used for searching) don't contain data Each leaf node contains an extra pointer, used to move to the next leaf node in sequence B-Tree Variations (Cont'd)