From bb83664e87261f9449f5c4595cce56088de46d63 Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Wed, 31 Jul 2019 01:19:09 +0200 Subject: [PATCH] btree: store strings via "data" struct --- btree/btree.go | 113 +++++++++++++++++++++++++++----------------- btree/btree_test.go | 108 +++++++++++++++++++++++++++--------------- main.go | 31 ++++++------ 3 files changed, 156 insertions(+), 96 deletions(-) diff --git a/btree/btree.go b/btree/btree.go index 564bb6a..d1ae10f 100644 --- a/btree/btree.go +++ b/btree/btree.go @@ -2,21 +2,26 @@ package btree import ( "fmt" + "strings" ) +type data struct { + key string + value string +} + // Tree is the tree itself type Tree struct { - root *Node // Pointer to the Node root + root *node // Pointer to the node root t int // Minimum degree } -// Node is a Node of a Btree -type Node struct { +type node struct { numberOfKeys int // The number of keys really stored degree int // The value of degree dependes upon disk blok size isLeaf bool - keys []int - children []*Node + keys []*data + children []*node } // Constructors @@ -30,17 +35,31 @@ func NewBtree(t int) *Tree { } } -func newNode(degree int, isLeaf bool) *Node { +func newNode(degree int, isLeaf bool) *node { - return &Node{ + return &node{ numberOfKeys: 0, degree: degree, isLeaf: isLeaf, - keys: make([]int, 2*degree-1), - children: make([]*Node, 2*degree), + keys: make([]*data, 2*degree-1), + children: make([]*node, 2*degree), } } +// Data methods + +func (a *data) eq(b *data) bool { + return strings.Compare(a.key, b.key) == 0 +} + +func (a *data) lt(b *data) bool { + return strings.Compare(a.key, b.key) == -1 +} + +func (a *data) gt(b *data) bool { + return strings.Compare(a.key, b.key) == 1 +} + // Tree methods // Traverse the tree @@ -52,20 +71,22 @@ func (t *Tree) Traverse() { } // Search k in the tree -func (t *Tree) Search(k int) *Node { +func (t *Tree) Search(k string) (string, error) { if t.root == nil { - return nil + return "", fmt.Errorf("The key %s does not exist", k) } - return t.root.search(k) + return t.root.search(&data{key: k}) } // Remove k in the tree -func (t *Tree) Remove(k int) error { +func (t *Tree) Remove(key string) error { + if t.root == nil { return fmt.Errorf("The tree is empty") } + k := &data{key: key} err := t.root.remove(k) @@ -83,7 +104,13 @@ func (t *Tree) Remove(k int) error { } // Insert k in the tree -func (t *Tree) Insert(k int) { +func (t *Tree) Insert(key, value string) { + + k := &data{ + key: key, + value: value, + } + // If the tree is empty if t.root == nil { t.root = newNode(t.t, true) @@ -111,7 +138,7 @@ func (t *Tree) Insert(k int) { // The new root has two children now. // We decide which of the two children is going to have the new key i := 0 - if s.keys[0] < k { + if s.keys[0].lt(k) { i++ } s.children[i].insertNonFull(k) @@ -120,10 +147,10 @@ func (t *Tree) Insert(k int) { t.root = s } -// Node methods +// node methods // traverse all nodes in a subtree rooted with this node -func (n *Node) traverse() { +func (n *node) traverse() { // There are n entries and n+1 children, treverse trough n keys and n first children for i := 0; i < n.numberOfKeys; i++ { @@ -131,7 +158,7 @@ func (n *Node) traverse() { if !n.isLeaf { n.children[i].traverse() } - fmt.Printf(" %d", n.keys[i]) + fmt.Printf(" %s:%s", n.keys[i].key, n.keys[i].value) } // Print the subtree rooted with the last child @@ -141,33 +168,33 @@ func (n *Node) traverse() { } // search k in the subtree rooted with this node -func (n *Node) search(k int) *Node { +func (n *node) search(k *data) (string, error) { // Find the first entry greater than or equal to k i := 0 - for i < n.numberOfKeys && k > n.keys[i] { + for i < n.numberOfKeys && k.gt(n.keys[i]) { i++ } - // If theh found key is equal to k, return this node - if n.keys[i] == k { - return n + // If the found key is equal to k, return this node + if n.keys[i] != nil && k.eq(n.keys[i]) { + return n.keys[i].value, nil } // If the key is not found here and this is a leaf node if n.isLeaf { - return nil + return "", fmt.Errorf("The key %s does not exist", k.key) } // Go to the approipriate child return n.children[i].search(k) } -func (n *Node) isFull() bool { +func (n *node) isFull() bool { return n.numberOfKeys == 2*n.degree-1 } -func (n *Node) insertNonFull(k int) { +func (n *node) insertNonFull(k *data) { // Initialize the index as the index of the rightmost element i := n.numberOfKeys - 1 @@ -176,7 +203,7 @@ func (n *Node) insertNonFull(k int) { if n.isLeaf { // Finds the location of the new key to be inserted // Moves all greater keys to one place ahead - for i >= 0 && n.keys[i] > k { + for i >= 0 && n.keys[i].gt(k) { n.keys[i+1] = n.keys[i] i-- } @@ -189,7 +216,7 @@ func (n *Node) insertNonFull(k int) { // If this is not a leaf // Finds the child wich is going to have the new key - for i >= 0 && n.keys[i] > k { + for i >= 0 && n.keys[i].gt(k) { i-- } @@ -201,7 +228,7 @@ func (n *Node) insertNonFull(k int) { // After the split, the middle key of children[i] goes up and // children[i] is splitted into two // See which of those two is going to have the new key - if n.keys[i+1] < k { + if n.keys[i+1].lt(k) { i++ } } @@ -209,7 +236,7 @@ func (n *Node) insertNonFull(k int) { n.children[i+1].insertNonFull(k) } -func (n *Node) splitChild(i int, y *Node) { +func (n *node) splitChild(i int, y *node) { // Create a new node that will store (t-1) keys of y z := newNode(y.degree, y.isLeaf) @@ -253,22 +280,22 @@ func (n *Node) splitChild(i int, y *Node) { } // findKey returns the index of the first key that is greater than or equal to k -func (n *Node) findKey(k int) int { +func (n *node) findKey(k *data) int { index := 0 - for index < n.numberOfKeys && n.keys[index] < k { + for index < n.numberOfKeys && n.keys[index].lt(k) { index++ } return index } // remove the key k from the sub-tree rooted with this node -func (n *Node) remove(k int) error { +func (n *node) remove(k *data) error { index := n.findKey(k) // The key to be removed is in this node - if index < n.numberOfKeys && n.keys[index] == k { + if index < n.numberOfKeys && n.keys[index].eq(k) { if n.isLeaf { return n.removeFromLeaf(index) } @@ -277,7 +304,7 @@ func (n *Node) remove(k int) error { // If this is a leaf, the key is not in the tree if n.isLeaf { - return fmt.Errorf("The key %d does not exist in the tree", k) + return fmt.Errorf("The key %s does not exist in the tree", k) } isInLastChild := false @@ -301,7 +328,7 @@ func (n *Node) remove(k int) error { } // removeFromLeaf the index-th key from this node which is a leaf node -func (n *Node) removeFromLeaf(index int) error { +func (n *node) removeFromLeaf(index int) error { // Move all the keys after the index-th position one place backward for i := index + 1; i < n.numberOfKeys; i++ { @@ -313,7 +340,7 @@ func (n *Node) removeFromLeaf(index int) error { } // removeFromNonLeaf the index-th key from this node which is not a leaf node -func (n *Node) removeFromNonLeaf(index int) error { +func (n *node) removeFromNonLeaf(index int) error { k := n.keys[index] @@ -342,7 +369,7 @@ func (n *Node) removeFromNonLeaf(index int) error { } // getPred returns the predecessor of keys[index] -func (n *Node) getPred(index int) int { +func (n *node) getPred(index int) *data { // Keep moving to the rightmost node until we reach a leaf current := n.children[index] @@ -355,7 +382,7 @@ func (n *Node) getPred(index int) int { } // getSucc returns the successor of keys[index] -func (n *Node) getSucc(index int) int { +func (n *node) getSucc(index int) *data { // Keep moving to the leftmost node starting from children[index+1] until we reach a leaf current := n.children[index+1] @@ -368,7 +395,7 @@ func (n *Node) getSucc(index int) int { } // fill child children[index] which has less than t-1 keys -func (n *Node) fill(index int) { +func (n *node) fill(index int) { // If the previous child has more than t-1 keys, borrow a key from that child if index != 0 && n.children[index-1].numberOfKeys >= n.degree { @@ -393,7 +420,7 @@ func (n *Node) fill(index int) { } // borrowFromPrev takes a key from children[index+1] and insert it in children[index] -func (n *Node) borrowFromPrev(index int) { +func (n *node) borrowFromPrev(index int) { child := n.children[index] sibling := n.children[index-1] @@ -426,7 +453,7 @@ func (n *Node) borrowFromPrev(index int) { } // borrowFromNext takes a key from children[index+1] and insert it in children[index] -func (n *Node) borrowFromNext(index int) { +func (n *node) borrowFromNext(index int) { child := n.children[index] sibling := n.children[index+1] @@ -460,7 +487,7 @@ func (n *Node) borrowFromNext(index int) { } // merge children[index] with children[index+1] -func (n *Node) merge(index int) { +func (n *node) merge(index int) { child := n.children[index] sibling := n.children[index+1] diff --git a/btree/btree_test.go b/btree/btree_test.go index 6f33b82..3f87dd5 100644 --- a/btree/btree_test.go +++ b/btree/btree_test.go @@ -7,59 +7,75 @@ import ( func TestTree_Search(t *testing.T) { tree := NewBtree(3) - tree.Insert(6) + tree.Insert("A", "a") - k := 6 - if tree.Search(k) == nil { - t.Errorf("Not present %d", k) + k := "A" + if _, err := tree.Search(k); err != nil { + t.Errorf("Not present %s", k) } - k = 15 - if tree.Search(k) != nil { - t.Errorf("Present %d", k) + k = "bike" + if val, err := tree.Search(k); err == nil { + t.Errorf("Present %s with value %s", k, val) } } func TestTree_Remove(t *testing.T) { tree := NewBtree(3) - toInsert := []int{10, 20, 5, 6, 12, 30, 7, 17} - - for _, k := range toInsert { - tree.Insert(k) + toInsert := [][]string{ + []string{"Monday", "Lundi"}, + []string{"Tuesday", "Mardi"}, + []string{"Wednesday", "Mercredi"}, + []string{"Thursday", "Jeudi"}, + []string{"Friday", "Vendredi"}, + []string{"Saturday", "Samedi"}, + []string{"Sunday", "Dimanche"}, } - tree.Remove(toInsert[0]) + for _, k := range toInsert { + tree.Insert(k[0], k[1]) + } + + tree.Remove("Monday") for _, k := range toInsert[1:] { - if tree.Search(k) == nil { - t.Errorf("Not present %d", k) + if _, err := tree.Search(k[0]); err != nil { + t.Errorf("Not present %s", k) } } - if tree.Search(toInsert[0]) != nil { - t.Errorf("Present %d", toInsert[0]) + if val, err := tree.Search("Monday"); err == nil { + t.Errorf("Present %s with value %s", toInsert[0], val) } } func TestTree_Insert(t *testing.T) { tree := NewBtree(3) - toInsert := []int{10, 20, 5, 6, 12, 30, 7, 17, 20} + toInsert := [][]string{ + []string{"Monday", "Lundi"}, + []string{"Tuesday", "Mardi"}, + []string{"Wednesday", "Mercredi"}, + []string{"Thursday", "Jeudi"}, + []string{"Friday", "Vendredi"}, + []string{"Saturday", "Samedi"}, + []string{"Sunday", "Dimanche"}, + } // Test before insertion for _, k := range toInsert { - if tree.Search(k) != nil { - t.Errorf("Present %d", k) + if val, err := tree.Search(k[0]); err == nil { + t.Errorf("Present %s with value %s", k[0], val) } } for _, k := range toInsert { - tree.Insert(k) + tree.Insert(k[0], k[1]) } // Test after insertion for _, k := range toInsert { - if tree.Search(k) == nil { - t.Errorf("Not present %d", k) + if _, err := tree.Search(k[0]); err != nil { + t.Errorf("Not present %s", k) } } } @@ -67,43 +83,61 @@ func TestTree_Insert(t *testing.T) { func ExampleTree_Traverse() { tree := NewBtree(3) - toInsert := []int{1, 3, 7, 10, 11, 13, 14, 15, 18, 16, 19, 24, 25, 26, 21, 4, 5, 20, 22, 2, 17, 12, 6} + toInsert := [][]string{ + []string{"a", "A"}, + []string{"b", "B"}, + []string{"c", "C"}, + []string{"d", "D"}, + []string{"e", "E"}, + []string{"f", "F"}, + []string{"g", "G"}, + []string{"h", "H"}, + []string{"i", "I"}, + []string{"j", "J"}, + []string{"k", "K"}, + []string{"l", "L"}, + []string{"m", "M"}, + []string{"n", "N"}, + []string{"o", "O"}, + []string{"p", "P"}, + []string{"q", "Q"}, + } for _, k := range toInsert { - tree.Insert(k) + tree.Insert(k[0], k[1]) } tree.Traverse() fmt.Println("") - tree.Remove(6) + tree.Remove("e") tree.Traverse() fmt.Println("") - tree.Remove(13) + tree.Remove("j") tree.Traverse() fmt.Println("") - tree.Remove(7) + tree.Remove("a") tree.Traverse() fmt.Println("") - tree.Remove(4) + tree.Remove("b") tree.Traverse() fmt.Println("") - tree.Remove(2) + tree.Remove("d") tree.Traverse() fmt.Println("") - tree.Remove(16) + tree.Remove("f") tree.Traverse() // Output: - // 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 18 19 20 21 22 24 25 26 - // 1 2 3 4 5 7 10 11 12 13 14 15 16 17 18 19 20 21 22 24 25 26 - // 1 2 3 4 5 7 10 11 12 14 15 16 17 18 19 20 21 22 24 25 26 - // 1 2 3 4 5 10 11 12 14 15 16 17 18 19 20 21 22 24 25 26 - // 1 2 3 5 10 11 12 14 15 16 17 18 19 20 21 22 24 25 26 - // 1 3 5 10 11 12 14 15 16 17 18 19 20 21 22 24 25 26 - // 1 3 5 10 11 12 14 15 17 18 19 20 21 22 24 25 26 + // a:A b:B c:C d:D e:E f:F g:G h:H i:I j:J k:K l:L m:M n:N o:O p:P q:Q + // a:A b:B c:C d:D f:F g:G h:H i:I j:J k:K l:L m:M n:N o:O p:P q:Q + // a:A b:B c:C d:D f:F g:G h:H i:I k:K l:L m:M n:N o:O p:P q:Q + // b:B c:C d:D f:F g:G h:H i:I k:K l:L m:M n:N o:O p:P q:Q + // c:C d:D f:F g:G h:H i:I k:K l:L m:M n:N o:O p:P q:Q + // c:C f:F g:G h:H i:I k:K l:L m:M n:N o:O p:P q:Q + // c:C g:G h:H i:I k:K l:L m:M n:N o:O p:P q:Q } diff --git a/main.go b/main.go index 3596aff..1b7d811 100644 --- a/main.go +++ b/main.go @@ -7,30 +7,29 @@ import ( ) func main() { + + // Example program t := btree.NewBtree(3) - t.Insert(10) - t.Insert(20) - t.Insert(5) - t.Insert(6) - t.Insert(12) - t.Insert(30) - t.Insert(7) - t.Insert(17) + t.Insert("animal", "dog") + t.Insert("potato", "fries") + t.Insert("6", "number") + t.Insert("12", "number") + t.Insert("car", "ferrari") + t.Insert("7", "number") + t.Insert("plane", "airbus") fmt.Print("Traversal of the constructed tree is") t.Traverse() - k := 6 - if t.Search(k) != nil { - fmt.Print("\nPresent") - } else { + if val, err := t.Search("6"); err != nil { fmt.Print("\nNot Present") + } else { + fmt.Printf("\nPresent: value '%s'", val) } - k = 15 - if t.Search(k) != nil { - fmt.Print("\nPresent") - } else { + if val, err := t.Search("15"); err != nil { fmt.Print("\nNot Present") + } else { + fmt.Printf("\nPresent: value '%s'", val) } }