Go語言聖經練習6.1~6.5

前言

位運算操作比較多,練練手。
代碼分兩塊 一個是代碼部分,另一個是測試代碼部分。使用 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語言聖經測試章節。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章