From ab73314ad47c851ec0929b66a1e5410b9cb4064f Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 9 Jul 2016 04:13:51 +0200 Subject: [PATCH] - btree expose its root, nodes and entries (for extension purposes) --- trees/btree/btree.go | 107 ++++++++++++++++---------------- trees/btree/btree_test.go | 124 +++++++++++++++++++------------------- trees/btree/main/main.go | 14 ----- 3 files changed, 116 insertions(+), 129 deletions(-) delete mode 100644 trees/btree/main/main.go diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 806e590..d365825 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -21,22 +21,23 @@ func assertTreeImplementation() { // Tree holds elements of the B-tree type Tree struct { - root *Node // Root node - comparator utils.Comparator // Key comparator + Root *Node // Root node + Comparator utils.Comparator // Key comparator size int // Total number of keys in the tree m int // Knuth order (maximum number of children) } // Node is a single element within the tree type Node struct { - parent *Node - entries []*Entry // Contained keys in node - children []*Node // Children nodes + Parent *Node + Entries []*Entry // Contained keys in node + Children []*Node // Children nodes } +// Entry represents the key-value pair contained within nodes type Entry struct { - key interface{} - value interface{} + Key interface{} + Value interface{} } // NewWith instantiates a B-tree with the Knuth order (maximum number of children) and a custom key comparator. @@ -44,7 +45,7 @@ func NewWith(order int, comparator utils.Comparator) *Tree { if order < 2 { panic("Invalid order, should be at least 2") } - return &Tree{m: order, comparator: comparator} + return &Tree{m: order, Comparator: comparator} } // NewWithIntComparator instantiates a B-tree with the Knuth order (maximum number of children) and the IntComparator, i.e. keys are of type int. @@ -61,15 +62,15 @@ func NewWithStringComparator(order int) *Tree { // If key already exists, then its value is updated with the new value. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Put(key interface{}, value interface{}) { - entry := &Entry{key: key, value: value} + entry := &Entry{Key: key, Value: value} - if tree.root == nil { - tree.root = &Node{entries: []*Entry{entry}, children: []*Node{}} + if tree.Root == nil { + tree.Root = &Node{Entries: []*Entry{entry}, Children: []*Node{}} tree.size++ return } - if tree.insert(tree.root, entry) { + if tree.insert(tree.Root, entry) { tree.size++ } } @@ -109,7 +110,7 @@ func (tree *Tree) Values() []interface{} { // Clear removes all nodes from the tree. func (tree *Tree) Clear() { - tree.root = nil + tree.Root = nil tree.size = 0 } @@ -117,29 +118,29 @@ func (tree *Tree) Clear() { func (tree *Tree) String() string { str := "BTree\n" if !tree.Empty() { - str += tree.root.String() + str += tree.Root.String() } return str } func (node *Node) String() string { - return fmt.Sprintf("%v", node.entries) + return fmt.Sprintf("%v", node.Entries) } func (entry *Entry) String() string { - return fmt.Sprintf("%v", entry.key) + return fmt.Sprintf("%v", entry.Key) } func (tree *Tree) isLeaf(node *Node) bool { - return len(node.children) == 0 + return len(node.Children) == 0 } func (tree *Tree) isFull(node *Node) bool { - return len(node.entries) == tree.maxEntries() + return len(node.Entries) == tree.maxEntries() } func (tree *Tree) shouldSplit(node *Node) bool { - return len(node.entries) > tree.maxEntries() + return len(node.Entries) > tree.maxEntries() } func (tree *Tree) maxChildren() int { @@ -155,11 +156,11 @@ func (tree *Tree) middle() int { } func (tree *Tree) search(node *Node, entry *Entry) (index int, found bool) { - low, high := 0, len(node.entries) - 1 + low, high := 0, len(node.Entries)-1 var mid int for low <= high { mid = (high + low) / 2 - compare := tree.comparator(entry.key, node.entries[mid].key) + compare := tree.Comparator(entry.Key, node.Entries[mid].Key) switch { case compare > 0: low = mid + 1 @@ -182,13 +183,13 @@ func (tree *Tree) insert(node *Node, entry *Entry) (inserted bool) { func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { insertPosition, found := tree.search(node, entry) if found { - node.entries[insertPosition] = nil // GC - node.entries[insertPosition] = entry + node.Entries[insertPosition] = nil // GC + node.Entries[insertPosition] = entry return false } - node.entries = append(node.entries, nil) - copy(node.entries[insertPosition + 1:], node.entries[insertPosition:]) - node.entries[insertPosition] = entry + node.Entries = append(node.Entries, nil) + copy(node.Entries[insertPosition+1:], node.Entries[insertPosition:]) + node.Entries[insertPosition] = entry tree.split(node) return true } @@ -196,11 +197,11 @@ func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { func (tree *Tree) insertIntoInternal(node *Node, entry *Entry) (inserted bool) { insertPosition, found := tree.search(node, entry) if found { - node.entries[insertPosition] = nil // GC - node.entries[insertPosition] = entry + node.Entries[insertPosition] = nil // GC + node.Entries[insertPosition] = entry return false } - return tree.insert(node.children[insertPosition], entry) + return tree.insert(node.Children[insertPosition], entry) } func (tree *Tree) split(node *Node) { @@ -208,7 +209,7 @@ func (tree *Tree) split(node *Node) { return } - if node == tree.root { + if node == tree.Root { tree.splitRoot() return } @@ -218,26 +219,26 @@ func (tree *Tree) split(node *Node) { func (tree *Tree) splitNonRoot(node *Node) { middle := tree.middle() - parent := node.parent + parent := node.Parent - left := &Node{entries: node.entries[:middle], parent: parent} - right := &Node{entries: node.entries[middle + 1:], parent: parent} + left := &Node{Entries: node.Entries[:middle], Parent: parent} + right := &Node{Entries: node.Entries[middle+1:], Parent: parent} if !tree.isLeaf(node) { - left.children = node.children[:middle + 1] - right.children = node.children[middle + 1:] + left.Children = node.Children[:middle+1] + right.Children = node.Children[middle+1:] } - insertPosition, _ := tree.search(parent, node.entries[middle]) - parent.entries = append(parent.entries, nil) - copy(parent.entries[insertPosition + 1:], parent.entries[insertPosition:]) - parent.entries[insertPosition] = node.entries[middle] + insertPosition, _ := tree.search(parent, node.Entries[middle]) + parent.Entries = append(parent.Entries, nil) + copy(parent.Entries[insertPosition+1:], parent.Entries[insertPosition:]) + parent.Entries[insertPosition] = node.Entries[middle] - parent.children[insertPosition] = left + parent.Children[insertPosition] = left - parent.children = append(parent.children, nil) - copy(parent.children[insertPosition + 2:], parent.children[insertPosition + 1:]) - parent.children[insertPosition + 1] = right + parent.Children = append(parent.Children, nil) + copy(parent.Children[insertPosition+2:], parent.Children[insertPosition+1:]) + parent.Children[insertPosition+1] = right node = nil // GC @@ -247,20 +248,20 @@ func (tree *Tree) splitNonRoot(node *Node) { func (tree *Tree) splitRoot() { middle := tree.middle() - left := &Node{entries: tree.root.entries[:middle]} - right := &Node{entries: tree.root.entries[middle + 1:]} + left := &Node{Entries: tree.Root.Entries[:middle]} + right := &Node{Entries: tree.Root.Entries[middle+1:]} - if !tree.isLeaf(tree.root) { - left.children = tree.root.children[:middle + 1] - right.children = tree.root.children[middle + 1:] + if !tree.isLeaf(tree.Root) { + left.Children = tree.Root.Children[:middle+1] + right.Children = tree.Root.Children[middle+1:] } newRoot := &Node{ - entries: []*Entry{tree.root.entries[middle]}, - children: []*Node{left, right}, + Entries: []*Entry{tree.Root.Entries[middle]}, + Children: []*Node{left, right}, } - left.parent = newRoot - right.parent = newRoot - tree.root = newRoot + left.Parent = newRoot + right.Parent = newRoot + tree.Root = newRoot } diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index c8a7b78..3a87344 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -12,12 +12,12 @@ import ( func TestBTree_search(t *testing.T) { { tree := NewWithIntComparator(3) - tree.root = &Node{entries: []*Entry{}, children: make([]*Node, 0)} + tree.Root = &Node{Entries: []*Entry{}, Children: make([]*Node, 0)} tests := [][]interface{}{ {0, 0, false}, } for _, test := range tests { - index, found := tree.search(tree.root, &Entry{test[0], nil}) + index, found := tree.search(tree.Root, &Entry{test[0], nil}) if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -28,7 +28,7 @@ func TestBTree_search(t *testing.T) { } { tree := NewWithIntComparator(3) - tree.root = &Node{entries: []*Entry{&Entry{2, 0}, &Entry{4, 1}, &Entry{6, 2}}, children: []*Node{}} + tree.Root = &Node{Entries: []*Entry{{2, 0}, {4, 1}, {6, 2}}, Children: []*Node{}} tests := [][]interface{}{ {0, 0, false}, {1, 0, false}, @@ -40,7 +40,7 @@ func TestBTree_search(t *testing.T) { {7, 3, false}, } for _, test := range tests { - index, found := tree.search(tree.root, &Entry{test[0], nil}) + index, found := tree.search(tree.Root, &Entry{test[0], nil}) if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -58,47 +58,47 @@ func TestBTree_insert1(t *testing.T) { tree.Put(1, 0) assertValidTree(t, tree, 1) - assertValidTreeNode(t, tree.root, 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root, 1, 0, []int{1}) tree.Put(2, 1) assertValidTree(t, tree, 2) - assertValidTreeNode(t, tree.root, 2, 0, []int{1, 2}) + assertValidTreeNode(t, tree.Root, 2, 0, []int{1, 2}) tree.Put(3, 2) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.root, 1, 2, []int{2}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{2}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}) tree.Put(4, 2) assertValidTree(t, tree, 4) - assertValidTreeNode(t, tree.root, 1, 2, []int{2}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.root.children[1], 2, 0, []int{3, 4}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{2}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{3, 4}) tree.Put(5, 2) assertValidTree(t, tree, 5) - assertValidTreeNode(t, tree.root, 2, 3, []int{2, 4}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{3}) - assertValidTreeNode(t, tree.root.children[2], 1, 0, []int{5}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{5}) tree.Put(6, 2) assertValidTree(t, tree, 6) - assertValidTreeNode(t, tree.root, 2, 3, []int{2, 4}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{3}) - assertValidTreeNode(t, tree.root.children[2], 2, 0, []int{5, 6}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{5, 6}) tree.Put(7, 2) assertValidTree(t, tree, 7) - assertValidTreeNode(t, tree.root, 1, 2, []int{4}) - assertValidTreeNode(t, tree.root.children[0], 1, 2, []int{2}) - assertValidTreeNode(t, tree.root.children[1], 1, 2, []int{6}) - assertValidTreeNode(t, tree.root.children[0].children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.root.children[0].children[1], 1, 0, []int{3}) - assertValidTreeNode(t, tree.root.children[1].children[0], 1, 0, []int{5}) - assertValidTreeNode(t, tree.root.children[1].children[1], 1, 0, []int{7}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{4}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{6}) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}) } func TestBTree_insert2(t *testing.T) { @@ -107,38 +107,38 @@ func TestBTree_insert2(t *testing.T) { tree.Put(0, 0) assertValidTree(t, tree, 1) - assertValidTreeNode(t, tree.root, 1, 0, []int{0}) + assertValidTreeNode(t, tree.Root, 1, 0, []int{0}) tree.Put(2, 2) assertValidTree(t, tree, 2) - assertValidTreeNode(t, tree.root, 2, 0, []int{0, 2}) + assertValidTreeNode(t, tree.Root, 2, 0, []int{0, 2}) tree.Put(1, 1) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.root, 3, 0, []int{0, 1, 2}) + assertValidTreeNode(t, tree.Root, 3, 0, []int{0, 1, 2}) tree.Put(1, 1) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.root, 3, 0, []int{0, 1, 2}) + assertValidTreeNode(t, tree.Root, 3, 0, []int{0, 1, 2}) tree.Put(3, 3) assertValidTree(t, tree, 4) - assertValidTreeNode(t, tree.root, 1, 2, []int{1}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{0}) - assertValidTreeNode(t, tree.root.children[1], 2, 0, []int{2, 3}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{1}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}) + assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{2, 3}) tree.Put(4, 4) assertValidTree(t, tree, 5) - assertValidTreeNode(t, tree.root, 1, 2, []int{1}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{0}) - assertValidTreeNode(t, tree.root.children[1], 3, 0, []int{2, 3, 4}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{1}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}) + assertValidTreeNode(t, tree.Root.Children[1], 3, 0, []int{2, 3, 4}) tree.Put(5, 5) assertValidTree(t, tree, 6) - assertValidTreeNode(t, tree.root, 2, 3, []int{1, 3}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{0}) - assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{2}) - assertValidTreeNode(t, tree.root.children[2], 2, 0, []int{4, 5}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{1, 3}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{2}) + assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{4, 5}) } func TestBTree_insert3(t *testing.T) { @@ -148,48 +148,48 @@ func TestBTree_insert3(t *testing.T) { tree.Put(10, 0) assertValidTree(t, tree, 1) - assertValidTreeNode(t, tree.root, 1, 0, []int{10}) + assertValidTreeNode(t, tree.Root, 1, 0, []int{10}) tree.Put(20, 1) assertValidTree(t, tree, 2) - assertValidTreeNode(t, tree.root, 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root, 2, 0, []int{10, 20}) tree.Put(30, 2) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.root, 3, 0, []int{10, 20, 30}) + assertValidTreeNode(t, tree.Root, 3, 0, []int{10, 20, 30}) tree.Put(40, 3) assertValidTree(t, tree, 4) - assertValidTreeNode(t, tree.root, 4, 0, []int{10, 20, 30, 40}) + assertValidTreeNode(t, tree.Root, 4, 0, []int{10, 20, 30, 40}) tree.Put(50, 4) assertValidTree(t, tree, 5) - assertValidTreeNode(t, tree.root, 5, 0, []int{10, 20, 30, 40, 50}) + assertValidTreeNode(t, tree.Root, 5, 0, []int{10, 20, 30, 40, 50}) tree.Put(60, 5) assertValidTree(t, tree, 6) - assertValidTreeNode(t, tree.root, 1, 2, []int{30}) - assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.root.children[1], 3, 0, []int{40, 50, 60}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{30}) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root.Children[1], 3, 0, []int{40, 50, 60}) tree.Put(70, 6) assertValidTree(t, tree, 7) - assertValidTreeNode(t, tree.root, 1, 2, []int{30}) - assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.root.children[1], 4, 0, []int{40, 50, 60, 70}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{30}) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root.Children[1], 4, 0, []int{40, 50, 60, 70}) tree.Put(80, 7) assertValidTree(t, tree, 8) - assertValidTreeNode(t, tree.root, 1, 2, []int{30}) - assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.root.children[1], 5, 0, []int{40, 50, 60, 70, 80}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{30}) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root.Children[1], 5, 0, []int{40, 50, 60, 70, 80}) tree.Put(90, 8) assertValidTree(t, tree, 9) - assertValidTreeNode(t, tree.root, 2, 3, []int{30, 60}) - assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.root.children[1], 2, 0, []int{40, 50}) - assertValidTreeNode(t, tree.root.children[2], 3, 0, []int{70, 80, 90}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{30, 60}) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{40, 50}) + assertValidTreeNode(t, tree.Root.Children[2], 3, 0, []int{70, 80, 90}) } func assertValidTree(t *testing.T, tree *Tree, expectedSize int) { @@ -199,14 +199,14 @@ func assertValidTree(t *testing.T, tree *Tree, expectedSize int) { } func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expectedChildren int, keys []int) { - if actualValue, expectedValue := len(node.entries), expectedEntries; actualValue != expectedValue { + if actualValue, expectedValue := len(node.Entries), expectedEntries; actualValue != expectedValue { t.Errorf("Got %v expected %v for entries size", actualValue, expectedValue) } - if actualValue, expectedValue := len(node.children), expectedChildren; actualValue != expectedValue { + if actualValue, expectedValue := len(node.Children), expectedChildren; actualValue != expectedValue { t.Errorf("Got %v expected %v for children size", actualValue, expectedValue) } for i, key := range keys { - if actualValue, expectedValue := node.entries[i].key, key; actualValue != expectedValue { + if actualValue, expectedValue := node.Entries[i].Key, key; actualValue != expectedValue { t.Errorf("Got %v expected %v for key", actualValue, expectedValue) } } diff --git a/trees/btree/main/main.go b/trees/btree/main/main.go deleted file mode 100644 index 145f36d..0000000 --- a/trees/btree/main/main.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "github.com/emirpasic/gods/trees/btree" - "fmt" -) - -func main() { - tree := btree.NewWithIntComparator(3) - tree.Put(1, 0) - tree.Put(2, 1) - tree.Put(3, 2) - fmt.Println() -}