Go语言实现HashSet

set.go

// set project set.go
package set

type Set interface {
    Add(e interface{}) bool
    Remove(e interface{})
    Clear()
    Contains(e interface{}) bool
    Len() int
    Same(other Set) bool
    Elements() []interface{}
    String() string
}

// 将集合other添加到集合one中
func AddSet(one Set, other Set) {
    if one == nil || other == nil || other.Len() == 0 {
        return
    }
    for _, v := range other.Elements() {
        one.Add(v)
    }
}

// 判断集合 one 是否是集合 other 的超集
func IsSuperset(one Set, other Set) bool {
    if one == nil || other == nil {
        return false
    }
    oneLen := one.Len()
    otherLen := other.Len()
    if oneLen == 0 || oneLen <= otherLen {
        return false
    }
    if oneLen > 0 && otherLen == 0 {
        return true
    }
    for _, v := range other.Elements() {
        if !one.Contains(v) {
            return false
        }
    }
    return true
}

// 生成集合 one 和集合 other 的并集
func Union(one Set, other Set) Set {
    if one == nil && other == nil {
        return nil
    }
    unionedSet := NewSimpleSet()
    AddSet(unionedSet, one)
    AddSet(unionedSet, other)
    return unionedSet
}

// 生成集合 one 和集合 other 的交集
func Intersect(one Set, other Set) Set {
    if one == nil || other == nil {
        return nil
    }
    intersectedSet := NewSimpleSet()
    if one.Len() == 0 || other.Len() == 0 {
        return intersectedSet
    }
    if one.Len() < other.Len() {
        for _, v := range one.Elements() {
            if other.Contains(v) {
                intersectedSet.Add(v)
            }
        }
    } else {
        for _, v := range other.Elements() {
            if one.Contains(v) {
                intersectedSet.Add(v)
            }
        }
    }
    return intersectedSet
}

// 生成集合 one 对集合 other 的差集
func Difference(one Set, other Set) Set {
    if one == nil {
        return nil
    }
    differencedSet := NewSimpleSet()
    if other == nil || other.Len() == 0 {
        AddSet(differencedSet, one)
        return differencedSet
    }
    for _, v := range one.Elements() {
        if !other.Contains(v) {
            differencedSet.Add(v)
        }
    }
    return differencedSet
}

// 生成集合 one 和集合 other 的对称差集
func SymmetricDifference(one Set, other Set) Set {
    diffA := Difference(one, other)
    if other == nil || other.Len() == 0 {
        return diffA
    }
    diffB := Difference(other, one)
    return Union(diffA, diffB)
}

// 返回一个HashSet
func NewSimpleSet() Set {
    return NewHashSet()
}

// 判断给定value是否为集合
func IsSet(value interface{}) bool {
    if _, ok := value.(Set); ok {
        return true
    }
    return false
}

hash_set.go

// hash_set
package set

import (
    "bytes"
    "fmt"
)

type HashSet struct {
    m map[interface{}]bool
}

// 创建和初始化HashSet的方法
func NewHashSet() *HashSet {
    return &HashSet{m: make(map[interface{}]bool)}
}

// 向HashSet中添加元素的方法
func (set *HashSet) Add(e interface{}) bool {
    if !set.m[e] {
        set.m[e] = true
        return true
    }
    return false
}

// 删除HashSet中指定的元素
func (set *HashSet) Remove(e interface{}) {
    delete(set.m, e)
}

// 清除HashSet中的所有元素
func (set *HashSet) Clear() {
    set.m = make(map[interface{}]bool)
}

// 判断HashSet是否包含指定元素
func (set *HashSet) Contains(e interface{}) bool {
    return set.m[e]
}

// 获取HashSet中元素值数量
func (set *HashSet) Len() int {
    return len(set.m)
}

// 判断两个Set类型值是否相同
func (set *HashSet) Same(other Set) bool {
    if other == nil {
        return false
    }
    if set.Len() != other.Len() {
        return false
    }
    for key := range set.m {
        if !other.Contains(key) {
            return false
        }
    }
    return true
}

// 生成HashSet的一个快照
func (set *HashSet) Elements() []interface{} {
    initialLen := len(set.m)
    snapshot := make([]interface{}, initialLen)
    actualLen := 0
    for key := range set.m {
        if actualLen < initialLen {
            snapshot[actualLen] = key
        } else {
            snapshot = append(snapshot, key)
        }
        actualLen++
    }
    if actualLen < initialLen {
        snapshot = snapshot[:actualLen]
    }
    return snapshot
}

// 获取HashSet自身字符串表示形式
func (set *HashSet) String() string {
    var buf bytes.Buffer
    buf.WriteString("Set{")
    first := true
    for key := range set.m {
        if first {
            first = false
        } else {
            buf.WriteString(" ")
        }
        buf.WriteString(fmt.Sprintf("%v", key))
    }
    buf.WriteString("}")
    return buf.String()
}

功能测试:

set_test.go

// set_test
package set

import (
    "bytes"
    "fmt"
    "math/rand"
    "runtime/debug"
    "strings"
    "testing"
    "time"
)

func testSetLenAndContains(t *testing.T, newSet func() Set, typeName string) {
    t.Logf("Starting Test%sLenAndContains...", typeName)
    set, expectedElemMap := genRandSet(newSet)
    t.Logf("Got a %s value: %v.", typeName, set)
    expectedLen := len(expectedElemMap)
    if set.Len() != expectedLen {
        t.Errorf("ERROR: The length of %s value %d is not %d!\n",
            set.Len(), typeName, expectedLen)
        t.FailNow()
    }
    t.Logf("The length of %s value is %d.\n", typeName, set.Len())
    for k := range expectedElemMap {
        if !set.Contains(k) {
            t.Errorf("ERROR: The %s value %v do not contains %v!",
                set, typeName, k)
            t.FailNow()
        }
    }
}

func testSetAdd(t *testing.T, newSet func() Set, typeName string) {
    t.Logf("Starting Test%sAdd...", typeName)
    set := newSet()
    var randElem interface{}
    var result bool
    expectedElemMap := make(map[interface{}]bool)
    for i := 0; i < 5; i++ {
        randElem = genRandElement()
        t.Logf("Add %v to the %s value %v.\n", randElem, typeName, set)
        result = set.Add(randElem)
        if expectedElemMap[randElem] && result {
            t.Errorf("ERROR: The element adding (%v => %v) is successful but should be failing!\n",
                randElem, set)
            t.FailNow()
        }
        if !expectedElemMap[randElem] && !result {
            t.Errorf("ERROR: The element adding (%v => %v) is failing!\n",
                randElem, set)
            t.FailNow()
        }
        expectedElemMap[randElem] = true
    }
    t.Logf("The %s value: %v.", typeName, set)
    expectedLen := len(expectedElemMap)
    if set.Len() != expectedLen {
        t.Errorf("ERROR: The length of %s value %d is not %d!\n",
            set.Len(), typeName, expectedLen)
        t.FailNow()
    }
    t.Logf("The length of %s value is %d.\n", typeName, set.Len())
    for k := range expectedElemMap {
        if !set.Contains(k) {
            t.Errorf("ERROR: The %s value %v do not contains %v!",
                set, typeName, k)
            t.FailNow()
        }
    }
}

func testSetRemove(t *testing.T, newSet func() Set, typeName string) {
    t.Logf("Starting Test%sRemove...", typeName)
    set, expectedElemMap := genRandSet(newSet)
    t.Logf("Got a %s value: %v.", typeName, set)
    t.Logf("The length of %s value is %d.\n", typeName, set.Len())
    var number int
    for k, _ := range expectedElemMap {
        if number%2 == 0 {
            t.Logf("Remove %v from the HashSet value %v.\n", k, set)
            set.Remove(k)
            if set.Contains(k) {
                t.Errorf("ERROR: The element removing (%v => %v) is failing!\n",
                    k, set)
                t.FailNow()
            }
            delete(expectedElemMap, k)
        }
        number++
    }
    expectedLen := len(expectedElemMap)
    if set.Len() != expectedLen {
        t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", set.Len(), expectedLen)
        t.FailNow()
    }
    t.Logf("The length of %s value is %d.\n", typeName, set.Len())
    for _, v := range set.Elements() {
        if !expectedElemMap[v] {
            t.Errorf("ERROR: The HashSet value %v contains %v but should not contains!", set, v)
            t.FailNow()
        }
    }
}

func testSetClear(t *testing.T, newSet func() Set, typeName string) {
    t.Logf("Starting Test%sClear...", typeName)
    set, _ := genRandSet(newSet)
    t.Logf("Got a %s value: %v.", typeName, set)
    t.Logf("The length of %s value is %d.\n", typeName, set.Len())
    t.Logf("Clear the HashSet value %v.\n", set)
    set.Clear()
    expectedLen := 0
    if set.Len() != expectedLen {
        t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", set.Len(), expectedLen)
        t.FailNow()
    }
    t.Logf("The length of %s value is %d.\n", typeName, set.Len())
}

func testSetElements(t *testing.T, newSet func() Set, typeName string) {
    t.Logf("Starting Test%sElements...", typeName)
    set, expectedElemMap := genRandSet(newSet)
    t.Logf("Got a %s value: %v.", typeName, set)
    t.Logf("The length of %s value is %d.\n", typeName, set.Len())
    elems := set.Elements()
    t.Logf("The elements of %s value is %v.\n", typeName, elems)
    expectedLen := len(expectedElemMap)
    if len(elems) != expectedLen {
        t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", len(elems), expectedLen)
        t.FailNow()
    }
    t.Logf("The length of elements is %d.\n", len(elems))
    for _, v := range elems {
        if !expectedElemMap[v] {
            t.Errorf("ERROR: The elements %v contains %v but should not contains!", set, v)
            t.FailNow()
        }
    }
}

func testSetSame(t *testing.T, newSet func() Set, typeName string) {
    t.Logf("Starting Test%sSame...", typeName)
    set, _ := genRandSet(newSet)
    t.Logf("Got a %s value: %v.", typeName, set)
    t.Logf("The length of %s value is %d.\n", typeName, set.Len())
    set2 := newSet()
    t.Logf("Clone the HashSet value %v...\n", set)
    for _, v := range set.Elements() {
        set2.Add(v)
    }
    result := set2.Same(set)
    if !result {
        t.Errorf("ERROR: Two sets are not same!")
    }
    t.Logf("Two sets are same.")
}

func testSetString(t *testing.T, newSet func() Set, typeName string) {
    t.Logf("Starting Test%sString...", typeName)
    set, _ := genRandSet(newSet)
    t.Logf("Got a %s value: %v.", typeName, set)
    setStr := set.String()
    t.Logf("The string of %s value is %s.\n", typeName, setStr)
    var elemStr string
    for _, v := range set.Elements() {
        elemStr = fmt.Sprintf("%v", v)
        if !strings.Contains(setStr, elemStr) {
            t.Errorf("ERROR: The string of %s value %s do not contains %s!",
                typeName, setStr, elemStr)
            t.FailNow()
        }
    }
}

// ----- Set 公用函数测试 -----

func TestIsSuperset(t *testing.T) {
    defer func() {
        if err := recover(); err != nil {
            debug.PrintStack()
            t.Errorf("Fatal Error: %s\n", err)
        }
    }()
    t.Log("Starting TestIsSuperset...")
    set, _ := genRandSet(func() Set { return NewSimpleSet() })
    set2 := NewSimpleSet()
    for _, v := range set.Elements() {
        set2.Add(v)
    }
    for extraElem := genRandElement(); ; {
        if set2.Add(extraElem) {
            break
        } else {
            time.Sleep(10 * time.Millisecond)
        }
    }
    if !IsSuperset(set2, set) {
        t.Errorf("ERROR: The HashSet value %v is not a superset of %v!\n", set2, set)
        t.FailNow()
    } else {
        t.Logf("The HashSet value %v is a superset of %v.\n", set2, set)
    }
    for extraElem := genRandElement(); ; {
        if set.Add(extraElem) {
            break
        } else {
            time.Sleep(10 * time.Millisecond)
        }
    }
    if IsSuperset(set2, set) {
        t.Errorf("ERROR: The HashSet value %v should not be a superset of %v!\n", set2, set)
        t.FailNow()
    } else {
        t.Logf("The HashSet value %v is not a superset of %v.\n", set2, set)
    }
}

func TestUnion(t *testing.T) {
    defer func() {
        if err := recover(); err != nil {
            debug.PrintStack()
            t.Errorf("Fatal Error: %s\n", err)
        }
    }()
    t.Log("Starting TestUnion...")
    set, _ := genRandSet(func() Set { return NewSimpleSet() })
    t.Logf("The set value: %v", set)
    set2, _ := genRandSet(func() Set { return NewSimpleSet() })
    uSet := Union(set, set2)
    t.Logf("The set value (2): %v", set2)
    for _, v := range set.Elements() {
        if !uSet.Contains(v) {
            t.Errorf("ERROR: The union set value %v do not contains %v!",
                uSet, v)
            t.FailNow()
        }
    }
    for _, v := range set2.Elements() {
        if !uSet.Contains(v) {
            t.Errorf("ERROR: The union set value %v do not contains %v!",
                uSet, v)
            t.FailNow()
        }
    }
    t.Logf("The set value %v is a unioned set of %v and %v", uSet, set, set2)
}

func TestIntersect(t *testing.T) {
    defer func() {
        if err := recover(); err != nil {
            debug.PrintStack()
            t.Errorf("Fatal Error: %s\n", err)
        }
    }()
    t.Log("Starting TestIntersect...")
    commonElem := genRandElement()
    set, _ := genRandSet(func() Set { return NewSimpleSet() })
    set.Add(commonElem)
    t.Logf("The set value: %v", set)
    set2, _ := genRandSet(func() Set { return NewSimpleSet() })
    set2.Add(commonElem)
    t.Logf("The set value (2): %v", set2)
    iSet := Intersect(set, set2)
    for _, v := range iSet.Elements() {
        if !set.Contains(v) {
            t.Errorf("ERROR: The set value %v do not contains %v!",
                set, v)
            t.FailNow()
        }
        if !set2.Contains(v) {
            t.Errorf("ERROR: The set value %v do not contains %v!",
                set2, v)
            t.FailNow()
        }
    }
    t.Logf("The set value %v is a intersected set of %v and %v", iSet, set, set2)
}

func TestDifference(t *testing.T) {
    defer func() {
        if err := recover(); err != nil {
            debug.PrintStack()
            t.Errorf("Fatal Error: %s\n", err)
        }
    }()
    t.Log("Starting TestDifference...")
    commonElem := genRandElement()
    set, _ := genRandSet(func() Set { return NewSimpleSet() })
    set.Add(commonElem)
    t.Logf("The set value: %v", set)
    set2, _ := genRandSet(func() Set { return NewSimpleSet() })
    set2.Add(commonElem)
    t.Logf("The set value (2): %v", set2)
    dSet := Difference(set, set2)
    for _, v := range dSet.Elements() {
        if !set.Contains(v) {
            t.Errorf("ERROR: The set value %v do not contains %v!",
                set, v)
            t.FailNow()
        }
        if set2.Contains(v) {
            t.Errorf("ERROR: The set value %v contains %v!",
                set2, v)
            t.FailNow()
        }
    }
    t.Logf("The set value %v is a differenced set of %v to %v", dSet, set, set2)
}

func TestSymmetricDifference(t *testing.T) {
    defer func() {
        if err := recover(); err != nil {
            debug.PrintStack()
            t.Errorf("Fatal Error: %s\n", err)
        }
    }()
    t.Log("Starting TestSymmetricDifference...")
    commonElem := genRandElement()
    set, _ := genRandSet(func() Set { return NewSimpleSet() })
    set.Add(commonElem)
    t.Logf("The set value: %v", set)
    set2, _ := genRandSet(func() Set { return NewSimpleSet() })
    set2.Add(commonElem)
    t.Logf("The set value (2): %v", set2)
    sdSet := SymmetricDifference(set, set2)
    for _, v := range sdSet.Elements() {
        if set.Contains(v) && set2.Contains(v) {
            t.Errorf("ERROR: The element %v can not be a common element of %v to %v!",
                v, set, set2)
            t.FailNow()
        }
    }
    t.Logf("The set value %v is a symmetric differenced set of %v to %v", sdSet, set, set2)
}

// ----- 随机测试对象生成函数 -----

func genRandSet(newSet func() Set) (set Set, elemMap map[interface{}]bool) {
    set = newSet()
    elemMap = make(map[interface{}]bool)
    var enough bool
    for !enough {
        e := genRandElement()
        set.Add(e)
        elemMap[e] = true
        if len(elemMap) >= 3 {
            enough = true
        }
    }
    return
}

func genRandElement() interface{} {
    seed := rand.Int63n(10000)
    switch seed {
    case 0:
        return genRandInt()
    case 1:
        return genRandString()
    case 2:
        return struct {
            num int64
            str string
        }{genRandInt(), genRandString()}
    default:
        const length = 2
        arr := new([length]interface{})
        for i := 0; i < length; i++ {
            if i%2 == 0 {
                arr[i] = genRandInt()
            } else {
                arr[i] = genRandString()
            }
        }
        return *arr
    }
}

func genRandString() string {
    var buff bytes.Buffer
    var prev string
    var curr string
    for i := 0; buff.Len() < 3; i++ {
        curr = string(genRandAZAscii())
        if curr == prev {
            continue
        } else {
            prev = curr
        }
        buff.WriteString(curr)
    }
    return buff.String()
}

func genRandAZAscii() int {
    min := 65 // A
    max := 90 // Z
    rand.Seed(time.Now().UnixNano())
    return min + rand.Intn(max-min)
}

func genRandInt() int64 {
    return rand.Int63n(10000)
}

hash_set_test.go

// hash_set_test
package set

import (
    "fmt"
    "runtime/debug"
    "strings"
    "testing"
)

func TestHashSetCreation(t *testing.T) {
    defer func() {
        if err := recover(); err != nil {
            debug.PrintStack()
            t.Errorf("Fatal Error: %s\n", err)
        }
    }()
    t.Log("Starting TestHashSetCreation...")
    hs := NewHashSet()
    t.Logf("Create a HashSet value: %v\n", hs)
    if hs == nil {
        t.Errorf("The result of func NewHashSet is nil!\n")
    }
    isSet := IsSet(hs)
    if !isSet {
        t.Errorf("The value of HashSet is not Set!\n")
    } else {
        t.Logf("The HashSet value is a Set.\n")
    }
}

func TestHashSetLenAndContains(t *testing.T) {
    testSetLenAndContains(t, func() Set { return NewHashSet() }, "HashSet")
}

func TestHashSetAdd(t *testing.T) {
    testSetAdd(t, func() Set { return NewHashSet() }, "HashSet")
}

func TestHashSetRemove(t *testing.T) {
    testSetRemove(t, func() Set { return NewHashSet() }, "HashSet")
}

func TestHashSetClear(t *testing.T) {
    testSetClear(t, func() Set { return NewHashSet() }, "HashSet")
}

func TestHashSetElements(t *testing.T) {
    testSetElements(t, func() Set { return NewHashSet() }, "HashSet")
}

func TestHashSetSame(t *testing.T) {
    testSetSame(t, func() Set { return NewHashSet() }, "HashSet")
}

func TestSetString(t *testing.T) {
    testSetString(t, func() Set { return NewHashSet() }, "HashSet")
}

func testSetOp(t *testing.T) {
    defer func() {
        if err := recover(); err != nil {
            debug.PrintStack()
            t.Errorf("Fatal Error: %s\n", err)
        }
    }()
    fmt.Println(222)
    t.Logf("Starting TestHashSetOp...")
    hs := NewHashSet()
    if hs.Len() != 0 {
        t.Errorf("ERROR: The length of original HashSet value is not 0!\n")
        t.FailNow()
    }
    randElem := genRandElement()
    expectedElemMap := make(map[interface{}]bool)
    t.Logf("Add %v to the HashSet value %v.\n", randElem, hs)
    hs.Add(randElem)
    expectedElemMap[randElem] = true
    expectedLen := len(expectedElemMap)
    if hs.Len() != expectedLen {
        t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", hs.Len(), expectedLen)
        t.FailNow()
    }
    var result bool
    for i := 0; i < 8; i++ {
        randElem = genRandElement()
        t.Logf("Add %v to the HashSet value %v.\n", randElem, hs)
        result = hs.Add(randElem)
        if expectedElemMap[randElem] && result {
            t.Errorf("ERROR: The element adding (%v => %v) is successful but should be failing!\n",
                randElem, hs)
            t.FailNow()
        }
        if !expectedElemMap[randElem] && !result {
            t.Errorf("ERROR: The element adding (%v => %v) is failing!\n",
                randElem, hs)
            t.FailNow()
        }
        expectedElemMap[randElem] = true
    }
    expectedLen = len(expectedElemMap)
    if hs.Len() != expectedLen {
        t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", hs.Len(), expectedLen)
        t.FailNow()
    }
    for k, _ := range expectedElemMap {
        if !hs.Contains(k) {
            t.Errorf("ERROR: The HashSet value %v do not contains %v!", hs, k)
            t.FailNow()
        }
    }
    number := 2
    for k, _ := range expectedElemMap {
        if number%2 == 0 {
            t.Logf("Remove %v from the HashSet value %v.\n", k, hs)
            hs.Remove(k)
            if hs.Contains(k) {
                t.Errorf("ERROR: The element adding (%v => %v) is failing!\n",
                    randElem, hs)
                t.FailNow()
            }
            delete(expectedElemMap, k)
        }
        number++
    }
    expectedLen = len(expectedElemMap)
    if hs.Len() != expectedLen {
        t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", hs.Len(), expectedLen)
        t.FailNow()
    }
    for _, v := range hs.Elements() {
        if !expectedElemMap[v] {
            t.Errorf("ERROR: The HashSet value %v contains %v!", hs, v)
            t.FailNow()
        }
    }
    hs2 := NewHashSet()
    for k, _ := range expectedElemMap {
        hs2.Add(k)
    }
    if !hs.Same(hs2) {
        t.Errorf("ERROR: HashSet value %v do not same %v!\n", hs, hs2)
        t.FailNow()
    }
    str := hs.String()
    t.Logf("The string of HashSet value %v is '%s'.\n", hs, str)
    for _, v := range hs.Elements() {
        if !strings.Contains(str, fmt.Sprintf("%v", v)) {
            t.Errorf("ERROR: '%s' do not contains '%v'!", str, v)
            t.FailNow()
        }
    }
}

 

posted @ 2016-12-10 10:12  ~风轻云淡~  阅读(1508)  评论(0编辑  收藏  举报