前言
位運算操作比較多,練練手。
代碼分兩塊 一個是代碼部分,另一個是測試代碼部分。使用 go test xxx 返回ok即正確。
題目:
練習6.1: 爲bit數組實現Len, Remove, Copy, Clear
練習6.2: 定義一個變參方法(*IntSet).AddAll(…int),這個方法可以爲一組IntSet值求和,比如 s.AddAll(1,2,3)。
練習6.3:並集、差集、對稱差
練習6.4: 返回可迭代的列表
練習6.5:將 64改成按平臺自動確定取32或64.
代碼
運行代碼
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 165.
// Package intset provides a set of integers based on a bit vector.
package intset
import (
"bytes"
"fmt"
)
//!+intset
// An IntSet is a set of small non-negative integers.
// Its zero value represents the empty set.
const bit = 32 << (^uint(0) >> 63)
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/bit, uint(x%bit)
return word < len(s.words) && s.words[word]&(1<<bit) != 0
}
// Add adds the non-negative value x to the set.
func (s *IntSet) Add(x int) {
word, bit := x/bit, uint(x%bit)
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 sets s to the intersect of s and t.
func (s *IntSet) IntersectWith(t *IntSet) *IntSet {
var z IntSet
for i, tword := range t.words {
if i < len(s.words) {
z.words = append(z.words, s.words[i] & tword)
}
}
return &z
}
// DifferenceWith sets s to the difference of s and t.
func (s *IntSet) DifferenceWith(t *IntSet) *IntSet{
var z IntSet
for i, tword := range t.words {
if i < len(s.words) {
tmp := s.words[i] & tword
z.words = append(z.words, s.words[i] - tmp)
}
}
return &z
}
// SymmetricDifference sets s to the difference of s and t.
func (s *IntSet) SymmetricDifference(t *IntSet) *IntSet{
var z IntSet
if len(t.words) == 0 {
return s
}
len1, len2 := len(s.words), len(t.words)
n := len1
if len1 < len2 {
n = len2
}
for i:=0; i<n; i++ {
if i < len1 && i < len2 {
tmp := s.words[i] & t.words[i]
z.words = append(z.words, (s.words[i] - tmp) | (t.words[i] - tmp))
} else if i < len1 {
z.words = append(z.words, s.words[i])
} else {
z.words = append(z.words, t.words[i])
}
}
return &z
}
//!-intset
//!+string
// String returns the set as a string of the form "{1 2 3}".
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 < bit; j++ {
if word&(1<<uint(j)) != 0 {
if buf.Len() > len("{") {
buf.WriteByte(' ')
}
fmt.Fprintf(&buf, "%d", bit*i+j)
}
}
}
buf.WriteByte('}')
return buf.String()
}
//!-string
// return the number of elements
func (s *IntSet) Len() int {
count := 0
for _, word := range s.words {
if word == 0 {
continue
}
for j := 0; j < bit; j++ {
if word&(1<<uint(j)) != 0 {
count++
}
}
}
return count
}
// remove x from the set
func (s *IntSet) Remove(x int) {
word, bit := x/bit, uint(x%bit)
for word >= len(s.words) {
return
}
s.words[word] &= ^(1 << bit)
}
func (s *IntSet) Clear() {
s.words = s.words[:0]
}
func (s *IntSet) Copy() *IntSet {
var b IntSet
for _, word := range s.words {
b.words = append(b.words, word)
}
return &b
}
func (s *IntSet) AddAll(vals...int) {
for _, val := range vals {
s.Add(val)
}
}
// String returns the set as a string of the form "{1 2 3}".
func (s *IntSet) Elems() ([]uint) {
var ans []uint
for i, word := range s.words {
if word == 0 {
continue
}
for j := 0; j < bit; j++ {
if word&(1<<uint(j)) != 0 {
ans = append(ans, uint(bit*i+j))
}
}
}
return ans
}
測試代碼
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
package intset
import "fmt"
func Example_one() {
//!+main
var x, y IntSet
x.Add(1)
x.Add(144)
x.Add(9)
fmt.Println(x.String()) // "{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"
x.Remove(9)
fmt.Println(x.Has(9)) // "false"
fmt.Println(x.Len()) // 3
x.Clear()
fmt.Println(x.Len()) // 0
var z *IntSet
z = y.Copy()
fmt.Println(z.String()) // "{9 42}"
z.AddAll(1,2,3)
fmt.Println(z.String()) // {"1 2 3 9 42"}
//!-main
// Output:
// {1 9 144}
// {9 42}
// {1 9 42 144}
// true false
// false
// 3
// 0
// {9 42}
// {1 2 3 9 42}
}
func Example_two() {
var x IntSet
x.Add(1)
x.Add(144)
x.Add(9)
x.Add(42)
//!+note
fmt.Println(&x) // "{1 9 42 144}"
fmt.Println(x.String()) // "{1 9 42 144}"
fmt.Println(x) // "{[4398046511618 0 65536]}"
//!-note
// Output:
// {1 9 42 144}
// {1 9 42 144}
// {[4398046511618 0 65536]}
}
func Example_three() {
var x, y IntSet
x.AddAll(1, 2, 3)
y.AddAll(2, 5, 6)
var z *IntSet
z = x.IntersectWith(&y)
fmt.Println(z.String()) // {"2"}
z = x.DifferenceWith(&y)
fmt.Println(z.String()) // {"1 3"}
z = x.SymmetricDifference(&y)
fmt.Println(z.String()) // {"1 3 5 6"}
fmt.Println(z.Elems())
// Output:
// {2}
// {1 3}
// {1 3 5 6}
// [1 3 5 6]
}
注: Output後面爲預期值。函數名以Example開頭,詳見Go語言聖經測試章節。