如何在Go中实现BitSet?

huangapple go评论118阅读模式
英文:

How to implement BitSet with Go?

问题

我在Go语言中没有找到BitSet包,所以我尝试自己实现它。
我想使用一个uint64数组来存储位。

我需要知道位数以分配uint64数组的大小。
在Java中,我可以定义一个构造函数来接受一个整数。
而Go语言没有提供构造函数,当用户调用new()时,我该如何正确初始化BitSet '对象'呢?

英文:

I didn't find a BitSet package in Go, so I tried to implement it.
I'd like to use a array of uint64 to store the bits.

I need the number of bits to allocate the uint64 array.
With Java, I can define a constructor that takes an integer.
While Go doesn't provide constructor, how can I properly initialize
the BitSet 'object' when user call new()?

答案1

得分: 16

Go的标准库big.Int可以用作位集合:

package main

import (
	"fmt"
	"math/big"
)

func main() {
	var bits big.Int
	for i := 1000; i < 2000; i++ {
		bits.SetBit(&bits, i, 1)
	}
	for i := 0; i < 10000; i++ {
		if bits.Bit(i) != 0 {
			fmt.Println(i)
		}
	}
}

https://play.golang.org/p/xbIK-boouqC

英文:

Go's standard big.Int can be used as a bit set:

package main

import (
	&quot;fmt&quot;
	&quot;math/big&quot;
)

func main() {
	var bits big.Int
	for i := 1000; i &lt; 2000; i++ {
		bits.SetBit(&amp;bits, i, 1)
	}
	for i := 0; i &lt; 10000; i++ {
		if bits.Bit(i) != 0 {
			fmt.Println(i)
		}
	}
}

https://play.golang.org/p/xbIK-boouqC

答案2

得分: 5

声明bitSet为一个私有结构体:

type bitSet struct {
  len int
  array []uint64
}

暴露BitSet接口:

type BitSet interface {
  Has(pos int) bool
  Add(pos int) bool
  Len() int
}

同时暴露一个NewBitSet函数:

func NewBitSet(len int) BitSet {
  return &bitSet{len, make([]uint64, (len+7) / 8) }
}

这是Go语言中封装的一种方式:共享接口,而不是实现。

英文:

Declare bitSet as a private struct:

type bitSet struct {
  len int
  array []uint64
}

Expose the interface BitSet:

type BitSet interface {
  Has(pos int) bool
  Add(pos int) bool
  Len() int
}

Also expose a function NewBitSet:

func NewBitSet(len int) BitSet {
  return &amp;bitSet{len, make(uint64, (len+7) / 8) }
}

This is a Go way for encapsulation: share an interface, not the implementation.

答案3

得分: 3

如果您使用一个 []uint64 切片来存储数据,那么零切片可以作为空的 BitSet。实际上,向一个空切片追加元素会为您分配一个新的数组,尽管语言规范似乎并没有保证这一点。有了这样的设置,new(BitSet) 就可以立即使用。示例:

bitset.go:

package bitset

const size = 64

type bits uint64

// BitSet 是一个可以设置、清除和查询的位集合。
type BitSet []bits

// Set 确保 BitSet 中的给定位被设置。
func (s *BitSet) Set(i uint) {
	if len(*s) < int(i/size+1) {
		r := make([]bits, i/size+1)
		copy(r, *s)
		*s = r
	}
	(*s)[i/size] |= 1 << (i % size)
}

// Clear 确保 BitSet 中的给定位被清除(未设置)。
func (s *BitSet) Clear(i uint) {
	if len(*s) >= int(i/size+1) {
		(*s)[i/size] &^= 1 << (i % size)
	}
}

// IsSet 如果给定位被设置,则返回 true,如果被清除,则返回 false。
func (s *BitSet) IsSet(i uint) bool {
	return (*s)[i/size]&(1<<(i%size)) != 0
}

bitset_test.go:

package bitset

import "fmt"

func ExampleBitSet() {
	s := new(BitSet)
	s.Set(13)
	s.Set(45)
	s.Clear(13)
	fmt.Printf("s.IsSet(13) = %t; s.IsSet(45) = %t; s.IsSet(30) = %t\n",
               s.IsSet(13), s.IsSet(45), s.IsSet(30))
	// Output: s.IsSet(13) = false; s.IsSet(45) = true; s.IsSet(30) = false
}
英文:

If you use a []uint64 slice to store your data, then the zero slice could function as the empty BitSet. In fact appending to a nil slice allocates a new array for you, although the Language Specification doesn't appear to guarantee that. With that kind of setup, new(BitSet) would be immediately usable. Example:

bitset.go:

package bitset

const size = 64

type bits uint64

// BitSet is a set of bits that can be set, cleared and queried.
type BitSet []bits

// Set ensures that the given bit is set in the BitSet.
func (s *BitSet) Set(i uint) {
	if len(*s) &lt; int(i/size+1) {
		r := make([]bits, i/size+1)
		copy(r, *s)
		*s = r
	}
	(*s)[i/size] |= 1 &lt;&lt; (i % size)
}

// Clear ensures that the given bit is cleared (not set) in the BitSet.
func (s *BitSet) Clear(i uint) {
	if len(*s) &gt;= int(i/size+1) {
		(*s)[i/size] &amp;^= 1 &lt;&lt; (i % size)
	}
}

// IsSet returns true if the given bit is set, false if it is cleared.
func (s *BitSet) IsSet(i uint) bool {
	return (*s)[i/size]&amp;(1&lt;&lt;(i%size)) != 0
}

bitset_test.go:

package bitset

import &quot;fmt&quot;

func ExampleBitSet() {
	s := new(BitSet)
	s.Set(13)
	s.Set(45)
	s.Clear(13)
	fmt.Printf(&quot;s.IsSet(13) = %t; s.IsSet(45) = %t; s.IsSet(30) = %t\n&quot;,
               s.IsSet(13), s.IsSet(45), s.IsSet(30))
	// Output: s.IsSet(13) = false; s.IsSet(45) = true; s.IsSet(30) = false
}

答案4

得分: 1

简短的回答是,当客户端调用new()时,无法正确初始化BitSet对象。

你能做的最好的事情是确保你的BitSet的零值是有效的。这就是像list.Listsync.Mutexbig.Int这样的类型所做的。这样你就知道客户端不可能得到一个无效的值。

你能做的下一件最好的事情是创建一个类似构造函数的函数(在这种情况下命名为NewBitSet),并期望客户端调用它。

英文:

The short answer is, you can't properly initialize the BitSet object when a client calls new().

The best thing you can do is make it so that your BitSet's zero value is valid. This is what types like list.List, sync.Mutex, and big.Int do. This way you know that it's impossible for a client to get an invalid value.

The next best thing you can do is create a constuctor-like function (named NewBitSet in this case) and expect clients to call it.

答案5

得分: 0

我也实现了自己的,它是这样工作的:

bm := bitmask.New(4)        // [4]{0000}
bm.Set(3)                   // [4]{0001}
bm.Slice(2, 4).ToggleAll()  // [4]{0010}
bm.Slice(1, 3).ToggleAll()  // [4]{0100}
bm.Slice(0, 2).ToggleAll()  // [4]{1000}
bm.Clear()                  // [4]{0000}

正如其他人所回答的,有一个惯例使用New函数来模拟构造函数。

英文:

I've implemented my own too, and that's how It works:

bm := bitmask.New(4)        // [4]{0000}
bm.Set(3)                   // [4]{0001}
bm.Slice(2, 4).ToggleAll()  // [4]{0010}
bm.Slice(1, 3).ToggleAll()  // [4]{0100}
bm.Slice(0, 2).ToggleAll()  // [4]{1000}
bm.Clear()                  // [4]{0000}

As others have answered, there's a convention to use New function to mimic the constructor.

huangapple
  • 本文由 发表于 2010年2月22日 22:17:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/2311373.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定