Coder Social home page Coder Social logo

liyue201 / gostl Goto Github PK

View Code? Open in Web Editor NEW
985.0 18.0 111.0 361 KB

Data structure and algorithm library for go, designed to provide functions similar to C++ STL

License: MIT License

Go 100.00%
list vector deque queue stack set rbtree multiset bitmap sort

gostl's Introduction

GoSTL

GoDoc Goreportcard Build Status Coverall License View examples

English | 简体中文

Introduction

GoSTL is a data structure and algorithm library for go, designed to provide functions similar to C++ STL, but more powerful. Combined with the characteristics of go language, most of the data structures have realized goroutine-safe. When creating objects, you can specify whether to turn it on or not through configuration parameters.

Function list

Examples

The slice in this library is a wrapper of go native slice.

package main

import (
 "fmt"
 "github.com/liyue201/gostl/algorithm/sort"
 "github.com/liyue201/gostl/ds/slice"
 "github.com/liyue201/gostl/utils/comparator"
)

func main() {
 a := make([]int, 0)
 a = append(a, 2)
 a = append(a, 1)
 a = append(a, 3)
 fmt.Printf("%v\n", a)

 wa := slice.NewSliceWrapper(a)

 // sort in ascending
 sort.Sort[int](wa.Begin(), wa.End(), comparator.IntComparator)
 fmt.Printf("%v\n", a)

 // sort in descending
 sort.Sort[int](wa.Begin(), wa.End(), comparator.Reverse(comparator.IntComparator))
 fmt.Printf("%v\n", a)
}

Array is a data structure with fixed length once it is created, which supports random access and iterator access.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/array"
)

func main() {
  a := array.New[int](5)
  for i := 0; i < a.Size(); i++ {
    a.Set(i, i+1)
  }
  for i := 0; i < a.Size(); i++ {
    fmt.Printf("%v ", a.At(i))
  }

  fmt.Printf("\n")
  for iter := a.Begin(); iter.IsValid(); iter.Next() {
    fmt.Printf("%v ", iter.Value())
  }
}

Vector is a kind of data structure whose size can be automatically expanded, which is realized by slice internally. Supports random access and iterator access.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/algorithm/sort"
  "github.com/liyue201/gostl/ds/vector"
  "github.com/liyue201/gostl/utils/comparator"
)

func main() {
  v := vector.New[int]()
  v.PushBack(1)
  v.PushBack(2)
  v.PushBack(3)
  for i := 0; i < v.Size(); i++ {
    fmt.Printf("%v ", v.At(i))
  }
  fmt.Printf("\n")

  // sort in descending
  sort.Sort[int](v.Begin(), v.End(), comparator.Reverse(comparator.IntComparator))
  for iter := v.Begin(); iter.IsValid(); iter.Next() {
    fmt.Printf("%v ", iter.Value())
  }
}
  • simple list
    Simple list is a one directional list, which supports inserting data from the head and tail, and only traversing data from the head.
package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/list/simplelist"
)

func main() {
  l := simplelist.New[int]()
  l.PushBack(1)
  l.PushFront(2)
  l.PushFront(3)
  l.PushBack(4)
  for n := l.FrontNode(); n != nil; n = n.Next() {
    fmt.Printf("%v ", n.Value)
  }
  fmt.Printf("\n===============\n")
}
  • bidirectional list
    Bidirectional list supports inserting data from the head and tail, and traversing data from the head and tail.
package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/list/bidlist"
)

func main() {
  l := bidlist.New[int]()
  l.PushBack(1)
  l.PushFront(2)
  l.PushFront(3)
  l.PushBack(4)
  for n := l.FrontNode(); n != nil; n = n.Next() {
    fmt.Printf("%v ", n.Value)
  }
  fmt.Printf("\n")

  for n := l.BackNode(); n != nil; n = n.Prev() {
    fmt.Printf("%v ", n.Value)
  }
}

Deque supports efficient data insertion from the head and tail, random access and iterator access.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/algorithm/sort"
  "github.com/liyue201/gostl/ds/deque"
  "github.com/liyue201/gostl/utils/comparator"
  "math/rand"
)

func main() {
  q := deque.New[int]()
  for i := 0; i < 100; i++ {
    r := rand.Int() % 100
    q.PushBack(r)
    q.PushFront(r)
  }
  fmt.Printf("%v\n", q)

  sort.Sort[int](q.Begin(), q.End(), comparator.IntComparator)
  fmt.Printf("%v\n", q)

  for !q.Empty() {
    r := rand.Int() % q.Size()
    q.EraseAt(r)
  }
  fmt.Printf("%v\n", q)
}

Queue is a first-in-first-out data structure. The bottom layer uses the deque or list as the container. By default, the deque is used. If you want to use the list, you can use the queue.WithListContainer() parameter when creating an object. Goroutine safety is supported.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/queue"
)

func main() {
  q := queue.New[int]()
  for i := 0; i < 5; i++ {
    q.Push(i)
  }
  for !q.Empty() {
    fmt.Printf("%v\n", q.Pop())
  }
}

Priority Queue is an abstract data type that is similar to a queue, and every element has some priority value associated with it. The priority of the elements in a priority queue determines the order in which elements are served (i.e., the order in which they are removed). If in any case the elements have same priority, they are served as per their ordering in the queue.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/priorityqueue"
  "github.com/liyue201/gostl/utils/comparator"
)

func main() {
  q := priorityqueue.New[int](comparator.Reverse(comparator.IntComparator),
    priorityqueue.WithGoroutineSafe())
  q.Push(4)
  q.Push(13)
  q.Push(7)
  q.Push(9)
  q.Push(0)
  q.Push(88)

  for !q.Empty() {
    fmt.Printf("%v\n", q.Pop())
  }
}

Stack is a kind of last-in-first-out data structure. The bottom layer uses the deque or list as the container. By default, the deque is used. If you want to use the list, you can use the queue.WithListContainer() parameter when creating an object. Goroutine safety is supported.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/stack"
)

func main() {
  s := stack.New[int]()
  s.Push(1)
  s.Push(2)
  s.Push(3)
  for !s.Empty() {
    fmt.Printf("%v\n", s.Pop())
  }
}

Red black tree is a balanced binary sort tree, which is used to insert and find data efficiently.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/rbtree"
  "github.com/liyue201/gostl/utils/comparator"
)

func main() {
  tree := rbtree.New[int, string](comparator.IntComparator)
  tree.Insert(1, "aaa")
  tree.Insert(5, "bbb")
  tree.Insert(3, "ccc")
  v, _ := tree.Find(5)
  fmt.Printf("find %v returns %v\n", 5, v)

  tree.Traversal(func(key int, value string) bool {
    fmt.Printf("%v : %v\n", key, value)
    return true
  })
  tree.Delete(tree.FindNode(3))
}

The Map bottom layer is implemented by using red black tree, and supports iterative access in key order, which is different from the go native map type (the go native map bottom layer is hash, and does not support iterative access in key order). Goroutine safety is supported.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/map"
  "github.com/liyue201/gostl/utils/comparator"
)

func main() {
  m := treemap.New[string, string](comparator.StringComparator, treemap.WithGoroutineSafe())

  m.Insert("a", "aaa")
  m.Insert("b", "bbb")

  a, _ := m.Get("a")
  b, _ := m.Get("b")
  fmt.Printf("a = %v\n", a)
  fmt.Printf("b = %v\n", b)

  m.Erase("b")
}

The Set bottom layer is implemented by red black tree, which supports goroutine safety. Support basic operations of set, such as union, intersection and difference. Goroutine safety is supported.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/set"
  "github.com/liyue201/gostl/utils/comparator"
)

func main() {
  s := set.New[int](comparator.IntComparator, set.WithGoroutineSafe())
  s.Insert(1)
  s.Insert(5)
  s.Insert(3)
  s.Insert(4)
  s.Insert(2)

  s.Erase(4)

  for iter := s.Begin(); iter.IsValid(); iter.Next() {
    fmt.Printf("%v\n", iter.Value())
  }

  fmt.Printf("%v\n", s.Contains(3))
  fmt.Printf("%v\n", s.Contains(10))
}

Bitmap is used to quickly mark and find whether a non negative integer is in a set. It takes up less memory than map or array.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/bitmap"
)

func main() {
  bm := bitmap.New(1000)
  bm.Set(6)
  bm.Set(10)

  fmt.Printf("%v\n", bm.IsSet(5))
  fmt.Printf("%v\n", bm.IsSet(6))
  bm.Unset(6)
  fmt.Printf("%v\n", bm.IsSet(6))
}

Boomfilter is used to quickly determine whether the data is in the collection. The bottom layer is implemented with bitmap, which uses less memory than map. The disadvantage is that it does not support deletion and has a certain error rate. Goroutine safety is supported , supports data export and reconstruction through exported data.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/bloomfilter"
)

func main() {
  filter := bloom.New(100, 4, bloom.WithGoroutineSafe())
  filter.Add("hhhh")
  filter.Add("gggg")

  fmt.Printf("%v\n", filter.Contains("aaaa"))
  fmt.Printf("%v\n", filter.Contains("gggg"))
}

Compared with the traditional hash (open address method or linked list method hash), hamt has lower probability of hash conflict and higher space utilization. The time complexity of capacity expansion is low. Goroutine safety is supported.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/hamt"
)

func main() {
  h := hamt.New[string](hamt.WithGoroutineSafe())
  key := []byte("aaaaa")
  val := "bbbbbbbbbbbbb"

  h.Insert(key, val)
  v, _ := h.Get(key)
  fmt.Printf("%v = %v\n", string(key), v)

  h.Erase(key)
  v, _ = h.Get(key)
  fmt.Printf("%v = %v\n", string(key), v)
}

Consistent hash Ketama algorithm, using 64 bit hash function and map storage, has less conflict probability. Goroutine safety is supported.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/ketama"
)

func main() {
  k := ketama.New()
  k.Add("1.2.3.3")
  k.Add("2.4.5.6")
  k.Add("5.5.5.1")

  for i := 0; i < 10; i++ {
    node, _ := k.Get(fmt.Sprintf("%d", i))
    fmt.Printf("%v\n", node)
  }
  k.Remove("2.4.5.6")
}

Skiplist is a kind of data structure which can search quickly by exchanging space for time. Goroutine safety is supported.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/ds/skiplist"
  "github.com/liyue201/gostl/utils/comparator"
)

func main() {
  list := skiplist.New[string, string](comparator.StringComparator, skiplist.WithMaxLevel(15))
  list.Insert("aaa", "1111")
  list.Insert("bbb", "2222")
  v1, _ := list.Get("aaa")
  v2, _ := list.Get("bbb")
  fmt.Printf("aaa = %v\n", v1)
  fmt.Printf("bbb = %v\n", v2)

  list.Traversal(func(key, value string) bool {
    fmt.Printf("key:%v value:%v\n", key, value)
    return true
  })

  list.Remove("aaa")
}

Sort: quick sort algorithm is used internally.
Stable: stable sorting. Merge sorting is used internally.
Binarysearch: determine whether an element is in the scope of iterator by binary search.
Lowerbound: find the first data equal to the element and return the iterator by binary search.
Upperbound: find the first data larger than the element and return the iterator by binary search.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/algorithm/sort"
  "github.com/liyue201/gostl/ds/slice"
  "github.com/liyue201/gostl/utils/comparator"
)

func main() {
  a := make([]string, 0)
  a = append(a, "bbbb")
  a = append(a, "ccc")
  a = append(a, "aaaa")
  a = append(a, "bbbb")
  a = append(a, "bb")

  sliceA := slice.NewSliceWrapper(a)

  ////Sort in ascending order
  sort.Sort[string](sliceA.Begin(), sliceA.End(), comparator.OrderedTypeCmp[string])

  sort.Stable[string](sliceA.Begin(), sliceA.End(), comparator.StringComparator)
  fmt.Printf("%v\n", a)

  if sort.BinarySearch[string](sliceA.Begin(), sliceA.End(), "bbbb", comparator.StringComparator) {
    fmt.Printf("BinarySearch: found bbbb\n")
  }

  iter := sort.LowerBound[string](sliceA.Begin(), sliceA.End(), "bbbb", comparator.StringComparator)
  if iter.IsValid() {
    fmt.Printf("LowerBound bbbb: %v\n", iter.Value())
  }
  iter = sort.UpperBound[string](sliceA.Begin(), sliceA.End(), "bbbb", comparator.StringComparator)
  if iter.IsValid() {
    fmt.Printf("UpperBound bbbb: %v\n", iter.Value())
  }
  //Sort in descending order
  sort.Sort[string](sliceA.Begin(), sliceA.End(), comparator.Reverse(comparator.StringComparator))
  //sort.Stable[string](sliceA.Begin(), sliceA.End(), comparator.Reverse(comparator.StringComparator))
  fmt.Printf("%v\n", a)
}

This function modifies the data in the iterator range to the next sort combination.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/algorithm/sort"
  "github.com/liyue201/gostl/ds/slice"
  "github.com/liyue201/gostl/utils/comparator"
)

func main() {
  a := make([]int, 0)
  for i := 1; i <= 3; i++ {
    a = append(a, i)
  }
  wa := slice.NewSliceWrapper(a)
  fmt.Println("NextPermutation")
  for {
    fmt.Printf("%v\n", a)
    if !sort.NextPermutation[int](wa.Begin(), wa.End(), comparator.IntComparator) {
      break
    }
  }
  fmt.Println("PrePermutation")
  for {
    fmt.Printf("%v\n", a)
    if !sort.NextPermutation[int](wa.Begin(), wa.End(), comparator.Reverse(comparator.IntComparator)) {
      break
    }
  }
}

Place the nth element in the scope of the iterator in the position of N, and put the element less than or equal to it on the left, and the element greater than or equal to it on the right.

package main

import (
  "fmt"
  "github.com/liyue201/gostl/algorithm/sort"
  "github.com/liyue201/gostl/ds/deque"
  "github.com/liyue201/gostl/utils/comparator"
)

func main() {
  a := deque.New[int]()
  a.PushBack(9)
  a.PushBack(8)
  a.PushBack(7)
  a.PushBack(6)
  a.PushBack(5)
  a.PushBack(4)
  a.PushBack(3)
  a.PushBack(2)
  a.PushBack(1)
  fmt.Printf("%v\n", a)
  sort.NthElement[int](a.Begin(), a.End(), 3, comparator.IntComparator)
  fmt.Printf("%v\n", a.At(3))
  fmt.Printf("%v\n", a)
}
  • swap: swap the values of two iterators
  • reverse: Reverse values in the range of two iterators
package main

import (
  "fmt"
  "github.com/liyue201/gostl/algorithm"
  "github.com/liyue201/gostl/ds/deque"
)

func main() {
  a := deque.New[int]()
  for i := 0; i < 9; i++ {
    a.PushBack(i)
  }
  fmt.Printf("%v\n", a)

  algorithm.Swap[int](a.First(), a.Last())
  fmt.Printf("%v\n", a)

  algorithm.Reverse[int](a.Begin(), a.End())
  fmt.Printf("%v\n", a)
}
  • Count : Count the number of elements equal to the specified value in the iterator interval
  • CountIf: Count the number of elements that satisfy the function f in the iterator interval
  • Find: Find the first element equal to the specified value in the iterator interval and returns its iterator
  • FindIf:Find the first element satisfying function f in the iterator interval and return its iterator
  • MaxElement : Find the largest element and return its iterator
  • MinElement : Find the smallest element and return its iterator
package main

import (
  "fmt"
  "github.com/liyue201/gostl/algorithm"
  "github.com/liyue201/gostl/ds/deque"
  "github.com/liyue201/gostl/utils/comparator"
  "github.com/liyue201/gostl/utils/iterator"
)

func isEven(iter iterator.ConstIterator[int]) bool {
  return iter.Value()%2 == 0
}

func greaterThan5(iter iterator.ConstIterator[int]) bool {
  return iter.Value() > 5
}

func main() {
  a := deque.New[int]()
  for i := 0; i < 10; i++ {
    a.PushBack(i)
  }
  for i := 0; i < 5; i++ {
    a.PushBack(i)
  }
  fmt.Printf("%v\n", a)

  fmt.Printf("Count 2: %v\n", algorithm.Count[int](a.Begin(), a.End(), 2, comparator.IntComparator))

  fmt.Printf("Count 2: %v\n", algorithm.CountIf[int](a.Begin(), a.End(), isEven))

  iter := algorithm.Find[int](a.Begin(), a.End(), 2, comparator.IntComparator)
  if !iter.Equal(a.End()) {
    fmt.Printf("Fund %v\n", iter.Value())
  }
  iter = algorithm.FindIf[int](a.Begin(), a.End(), greaterThan5)
  if !iter.Equal(a.End()) {
    fmt.Printf("FindIf greaterThan5 : %v\n", iter.Value())
  }
  iter = algorithm.MaxElement[int](a.Begin(), a.End(), comparator.IntComparator)
  if !iter.Equal(a.End()) {
    fmt.Printf("largest value : %v\n", iter.Value())
  }
  iter = algorithm.MinElement[int](a.Begin(), a.End(), comparator.IntComparator)
  if !iter.Equal(a.End()) {
    fmt.Printf("largest value : %v\n", iter.Value())
  }
}

Stargazers over time

Stargazers over time

gostl's People

Contributors

aaroniscoollab avatar allexsen avatar cupen avatar gudzpoz avatar kdh6429 avatar l-time avatar liyue201 avatar rfyiamcool avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gostl's Issues

单元测试应该断言

没有断言的单元测试不是单元测试,没有任何意义.建议用testify库或者直接reflect.DeepEqual比较下期望值和实际值.

RbTree.delete invalidate successor pointer when `y != z`

Hi, there is a problem in the implementation of the delete function of Red Black Tree.
rbtree.go:219:

if y != z {
	z.key = y.key
	z.value = y.value
}

It reuse the node-to-delete z in the tree and delete the successor node y
This is not correct because all pointers stored by the user on the y node will be invalidated.
I found a solution in the C++ STL of clang 13 (I believe), they swap the nodes y and z such that only z is invalidated, as expected.
Here is the code that I found:
__tree:382:

if (__y != __z)
{
    // __z->__left_ != nulptr but __z->__right_ might == __x == nullptr
    __y->__parent_ = __z->__parent_; // 1
    if (_VSTD::__tree_is_left_child(__z))
      __y->__parent_->__left_ = __y;
    else
      __y->__parent_unsafe()->__right_ = __y;
    __y->__left_ = __z->__left_;
    __y->__left_->__set_parent(__y);
    __y->__right_ = __z->__right_;
    if (__y->__right_ != nullptr)
      __y->__right_->__set_parent(__y);
    __y->__is_black_ = __z->__is_black_;
    if (__root == __z)
      __root = __y;
}

Which I try'd to adapt to our implementation, it give me something like:
rbtree.go:219:

if y != z {
    //z.key = y.key
    //z.value = y.value

    y.parent = z.parent

    if t.root == z {
      t.root = y
    } else if z.parent.left == z {
      y.parent.left = y
    } else {
      y.parent.right = y
    }

    y.left = z.left
    y.left.parent = y

    y.right = z.right
    if y.right != nil {
      y.right.parent = y
    }

    y.color = z.color
}

But unfortunately this solution seems to break the tree for some reason that I don't know, it fail the tests.
Could a brilliant brain figure it out? I'm stuck

线程安全还是协程安全?

看到介绍里面,大部分算法标记的都是线程安全。但在具体使用过程中,协程使用场景远远大于线程使用场景,所以向大佬确认一下到底是线程安全还是协程安全?

MutilMap的删除有BUG

`
func TestMulitMap(t *testing.T) {
m := NewMultiMap()

x := []int{20, 40, 50, 50, 35, 60, 70, 80, 120, 140, 50, 2, 5, 60, 50,50,50}
N := len(x)
for i := 1; i <= N; i++ {
	m.Insert(x[i-1], i)
}
m.Erase(50)

}
`

试一下上面这个Test

`
--- FAIL: TestMulitMap (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x52274f]

goroutine 19 [running]:
testing.tRunner.func1(0xc0000ea300)
C:/Go/src/testing/testing.go:792 +0x38e
panic(0x695580, 0x8e9fd0)
C:/Go/src/runtime/panic.go:513 +0x1c7
github.com/liyue201/gostl/ds/rbtree.(*RbTree).rbFixupLeft(0xc0000468e0, 0x0, 0xc000048d40, 0x0, 0xe, 0xc0000f9e98)
E:/third/gostl/ds/rbtree/rbtree.go:249 +0x2f
github.com/liyue201/gostl/ds/rbtree.(*RbTree).rbDeleteFixup(0xc0000468e0, 0x0, 0xc000048d40)
E:/third/gostl/ds/rbtree/rbtree.go:237 +0x95
github.com/liyue201/gostl/ds/rbtree.(*RbTree).Delete(0xc0000468e0, 0xc000048c40)
E:/third/gostl/ds/rbtree/rbtree.go:225 +0x106
github.com/liyue201/gostl/ds/map.(*MultiMap).Erase(0xc000046900, 0x67e300, 0x72ba68)
E:/third/gostl/ds/map/multimap.go:62 +0x146
github.com/liyue201/gostl/ds/map.TestMulitMap(0xc0000ea300)
E:/third/gostl/ds/map/multimap_test.go:18 +0x155
testing.tRunner(0xc0000ea300, 0x6fbc60)
C:/Go/src/testing/testing.go:827 +0xc6
created by testing.(*T).Run
C:/Go/src/testing/testing.go:878 +0x363
`

我不确定是红黑树的问题还是Erase时后继迭代问题,可能删除时有两个子节点的情况的处理为删除最先后继使得 mutilateMap Erase时不能简单用后继迭代

a question for Equal() Function in ds/array.go

First of all, I will say It's great repository. @liyue201 Thanks for implementing it!
I want to ask a question that what's the meaning of the first line in ds/array.go Equal() ?

// Equal returns true if the iterator is equal to the passed iterator, otherwise returns false
func (iter *ArrayIterator) Equal(other iterator.ConstIterator) bool {
	otherIter, ok := other.(*ArrayIterator)  // what's the grammar in here?Thanks a lot!
	if !ok {
		return false
	}
	if otherIter.array == iter.array && otherIter.position == iter.position {
		return true
	}
	return false
}

ds: add EraseIter to Set, MultiSet and MultiMap

Motivation

I wanted to delete a element one by one from MultiSet and MultiMap. However, Erase(K) delete all elements having key K.

Solution

Using EraseIter(iter), we can delete the element one by one.

Example

package main

import (
	"fmt"

	"github.com/liyue201/gostl/ds/set"
	"github.com/liyue201/gostl/utils/comparator"
)

func main() {
	ms := set.NewMultiSet(comparator.IntComparator)

	// Insert
	for i := 0; i < 3; i++ {
		ms.Insert(5000)
	}
	fmt.Println(ms) // [5000 5000 5000]

	// EraseIter (one element)
	it := ms.Find(5000)
	ms.EraseIter(it)
	fmt.Println(ms) // [5000 5000]

	// Erase (all elements)
	ms.Erase(5000)
	fmt.Println(ms) // []
}

Other little things

Map already have had EraseIter, so I did nothing to that.

I am ready to send a pull request related this issue. If you approve of this feature addition, I will send that to this repository.

improve the ketama

we can move the replicas field to the ketama.add() function as a parameter.
so we can adjust the replicas of the machine based at the ability of these machines.
this is better

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.