Skip to content

Instantly share code, notes, and snippets.

@betandr
Created February 5, 2019 17:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save betandr/c40bb9ac9134901748d796f4cd2a1590 to your computer and use it in GitHub Desktop.
Save betandr/c40bb9ac9134901748d796f4cd2a1590 to your computer and use it in GitHub Desktop.
Go Bit Vector
// bitvec is a bit vector (also known as bit array, bit map, bit set, or bit string) compactly stores bits.
// It can be used to implement a simple set data structure. A bit array is effective at exploiting bit-level
// parallelism in hardware to perform operations quickly. A typical bit array stores kw bits, where w is the
// number of bits in the unit of storage, such as a byte or word, and k is some nonnegative integer. If w
// does not divide the number of bits to be stored, some space is wasted due to internal fragmentation.
package bitvec
import (
"fmt"
"strings"
)
const size = 32 << (^uint(0) >> 63)
// An IntSet is a set of small non-negative integers.
// Its zero value represents the empty set.
type IntSet struct {
words []uint
}
// Has reports whether the set contains the non-negative value x.
func (s *IntSet) Has(x int) bool {
word, bit := x/size, uint(x%size)
return word < len(s.words) && s.words[word]&(1<<bit) != 0
}
// AddAll adds the non-negative values x to the set.
func (s *IntSet) AddAll(vals ...int) {
for _, val := range vals {
s.Add(val)
}
}
// Add adds the non-negative value x to the set.
func (s *IntSet) Add(x int) {
word, bit := x/size, uint(x%size)
for word >= len(s.words) {
s.words = append(s.words, 0)
}
s.words[word] |= 1 << bit
}
// UnionWith sets s to the union of s and t.
func (s *IntSet) UnionWith(t *IntSet) {
for i, tword := range t.words {
if i < len(s.words) {
s.words[i] |= tword
} else {
s.words = append(s.words, tword)
}
}
}
// IntersectWith computes the intersection between two sets
func (s *IntSet) IntersectWith(t *IntSet) {
for i, tword := range t.words {
if i < len(s.words) {
s.words[i] &= tword
} else {
s.words = append(s.words, tword)
}
}
}
// DifferenceWith computes the difference between two sets
func (s *IntSet) DifferenceWith(t *IntSet) {
for i, tword := range t.words {
if i < len(s.words) {
s.words[i] &^= tword
} else {
s.words = append(s.words, tword)
}
}
}
// SymmetricDifferenceWith computes the symmetric difference between two sets
func (s *IntSet) SymmetricDifferenceWith(t *IntSet) {
for i, tword := range t.words {
if i < len(s.words) {
s.words[i] ^= tword
} else {
s.words = append(s.words, tword)
}
}
}
// Len returns the number of elements by running a population count (by clearing)
// on each word.
func (s *IntSet) Len() int {
count := 0
for _, w := range s.words {
for w != 0 {
w = w & (w - 1) // clear rightmost non-zero bit
count++
}
}
return count
}
// Remove removes `x` from the set
func (s *IntSet) Remove(x int) {
word, bit := x/size, uint(x%size)
s.words[word] ^= 1 << bit
}
// Clear removes all elements from the set
func (s *IntSet) Clear() {
s.words = nil // is this a cheat? :thinking_face:
}
// Copy returns a copy of the set
func (s *IntSet) Copy() *IntSet {
ns := new(IntSet)
for _, word := range s.words {
ns.words = append(ns.words, word)
}
return ns
}
// Elems returns a slice containing the elements of the set, suitable for
// iterating over with a range loop.
func (s *IntSet) Elems() []int {
e := []int{}
for i, word := range s.words {
if word == 0 {
continue
}
for j := 0; j < size; j++ {
if word&(1<<uint(j)) != 0 {
e = append(e, size*i+j)
}
}
}
return e
}
// String returns the set as a string of the form "{1 2 3}".
func (s *IntSet) String() string {
var sb strings.Builder
sb.WriteString("{")
for i, word := range s.words {
if word == 0 {
continue
}
for j := 0; j < size; j++ {
if word&(1<<uint(j)) != 0 {
if sb.Len() > len("{") {
sb.WriteString(" ")
}
sb.WriteString(fmt.Sprintf("%d", size*i+j))
}
}
}
sb.WriteString("}")
return sb.String()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment