bit数组构建一个非负整数Set集合 [Go]

bit数组构建一个非负整数Set集合

实现了下面这些方法:

  • func (s *IntSet) Has(x int) bool //不断集合中是否存在元素x
  • func (s *IntSet) Add(x int) // 添加元素
  • func (*IntSet) Len() int // return the number of elements
  • func (*IntSet) Remove(x int) // remove x from the set
  • func (*IntSet) Clear() // remove all elements from the set
  • func (*IntSet) Copy() *IntSet // return a copy of the set
  • func (s *IntSet) UnionWith(t *IntSet) // 并集
  • IntersectWith(交集:元素在A集合B集合均出现)
  • DifferenceWith(差集:元素出现在A集合,未出现在B集合)
  • SymmetricDifference(并差集:元素出现在A但没有出现在B,或者出现在B没有出现在A)

intset.go:

package intset

import (
	"bytes"
	"fmt"
	"log"
)

var pc [256]byte
func init() {
	for i:= range pc {
		pc[i] = pc[i>>1] + byte(i&1)
	}
}

type IntSet struct {
	words []uint64
}

func (s *IntSet) Has(x int) bool{
	word := x / 64
	bit := x % 64
	return word < len(s.words) && s.words[word]&(1<<bit) != 0
}

func (s *IntSet) Add(x int) {
	word, bit := x/64, x%64
	for word >= len(s.words) {
		s.words = append(s.words, 0)
	}
	s.words[word] |= 1 << bit
}

// 并集
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(交集:元素在A集合B集合均出现),
func (s *IntSet) IntersectWith(t *IntSet) {
	n1 := len(s.words)
    n2 := len(t.words)
    minLen := n1
    if n2 < n1 {
        minLen = n2
    }
    // 前 minLen 个 word 做按位与
    for i := 0; i < minLen; i++ {
        s.words[i] &= t.words[i]
    }
    // s.words 超出的部分清零
    for i := minLen; i < n1; i++ {
        s.words[i] = 0
    }
}

// DifferenceWith(差集:元素出现在A集合,未出现在B集合),
func (s *IntSet) DifferenceWith(t *IntSet) {
	for i, tword := range t.words {
		if i < len(s.words) {
			s.words[i] &^= tword
		}
	}
}

// SymmetricDifference(并差集:元素出现在A但没有出现在B,或者出现在B没有出现在A)
func (s *IntSet) SymmetricDifference(t *IntSet) {
	tCopy := t.Copy()
	tCopy.DifferenceWith(s) 
	s.DifferenceWith(t) 
	s.UnionWith(tCopy) 
}


// PopCount 计算一个64位无符号整数中设置位(值为1的位)的个数
// 参数:
//   x - 要计算设置位个数的64位无符号整数
// 返回值:
//   int - x中设置位的个数
func PopCount(x uint64) int {
	return int(pc[byte(x>>(0*8)) +
		pc[byte(x>>(1*8))] +
		pc[byte(x>>(2*8))] +
		pc[byte(x>>(3*8))] +
		pc[byte(x>>(4*8))] +
		pc[byte(x>>(5*8))] +
		pc[byte(x>>(6*8))] +
		pc[byte(x>>(7*8))]])
}

// return the number of elements
func (s *IntSet) Len() int {
	num := 0
	for _, word := range s.words {
		if word == 0 {
			continue
		}
		num += PopCount(word)
	}
	return num
}

// remove x from the set
func (s *IntSet) Remove(x int) {
	word, bit := x/64, uint(x%64)
	if word > len(s.words) {
		log.Printf("集合中不存在该元素:%d\n", x)
	}
	s.words[word] &^= 1 << bit
}

// remove all elements from the set
func (s *IntSet) Clear() {
	s.words = []uint64{}
}    


// Copy returns a copy of the set.
func (s *IntSet) Copy() *IntSet {
	n := &IntSet{}
	n.words = make([]uint64, len(s.words)) // 分配长度
	copy(n.words, s.words)
	return n
}

//!+string

func (s *IntSet) String() string {
	var buf bytes.Buffer
	buf.WriteByte('{')
	for i, word := range s.words {
		if word == 0 {
			continue
		}
		for j:=0; j<64; j++ {
			if word & (1 << j) != 0 {
				if buf.Len() > 1 {
					buf.WriteByte(' ')
				}
				fmt.Fprintf(&buf, "%d ", 64*i+j)
			}
		}
	}
	buf.WriteByte('}')
	return buf.String()
}
//!-string

intset_test.go:

package intset

import (
	"fmt"
	"testing"
)


func TestIntSet(t *testing.T) {
	var x, y IntSet
	x.Add(1)
	x.Add(144)
	x.Add(9)
	fmt.Println(&x) // "{1 9 144}"
	y.Add(9)
	y.Add(42)
	fmt.Println(y.String()) // "{9 42}"
	x.UnionWith(&y)
	fmt.Println(x.String()) // "{1 9 42 144}"
	fmt.Println(x.Has(9), x.Has(123)) // "true false"
}


var x IntSet
func TestIntSet2(t *testing.T) {
	x.Add(1)
	x.Add(144)
	x.Add(9)
	fmt.Println(x.Len())
	fmt.Println(x.String())
	x.Remove(10)
	fmt.Println(x.String())
	n := x.Copy()
	fmt.Println("x.Copy()", n.String())
	fmt.Println("x", x.String())
	x.Clear()
	fmt.Println("x.Clear()", x.String())
}
posted @ 2025-08-21 16:53  dwhere  阅读(9)  评论(0)    收藏  举报