集合的另一种实现方式

撰写于 2018-04-03 修改于 2018-04-04 分类 go语言 标签 go杂记

集合是什么

集合是一种数据结构,类似于数组,但是其中的元素有以下三个特征:
1.确定性
2.互异性
3.无序性

如何实现集合

此处,不讨论集合的用法,重点讨论,如何实现集合这种数据结构。可能第一个想到的就是使用map这种数据结构实现,当然map是很灵活,但是会增大内存空间的使用。我们可以使用一种更好的形式来表示它。我们使用字节数组来表示集合,数组的每一个元素的每一位都表示集合里面的一个值。这样就可以保证集合的三个特性。具体如何实现呢?

go语言的集合实现

定义包含字节数组的结构体及相关方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
type IntSet struct {
words []int64
}

/*集合是否包含某个元素*/
func (s *IntSet) Has(x int) bool {
word, bit := x/64, uint(x%64)
return word < len(s.words) && s.words[word]&(1<<bit) != 0
}

/*向集合中添加元素*/
func (s *IntSet) Add(x int) {
word, bit := x/64, uint(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 {
append(s.words, tword)
}
}
}

/*集合的交集操作*/
func (s *IntSet) Intersection(t *IntSet) *IntSet {
dest := new(IntSet)
for i, tword := range t.words {
if i < len(s.words) {
for j := 0; j < 64; j++ {
bitvalue := int64(1 << uint(j))
if (tword&bitvalue != 0) && (s.words[i]&bitvalue != 0) {
for k := len(dest.words) - 1; k <= i; k++ {
dest.words = append(dest.words, 0)
}
dest.words[i] |= bitvalue
}
}
}
}
return dest
}
/*集合的字符串转换*/
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<<uint(j)) != 0 {
if buf.Len() > len("{") {
buf.WriteByte(' ')
}
fmt.Fprintf(&buf, "%d", 64*i + j)
}
}
}
buf.WriteByte('}')
return buf.String()
}

使用该集合定义

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
var x, y IntSet
x.Add(1)
x.Add(144)
x.Add(9)
fmt.Println(x.String())

y.Add(9)
y.Add(32)
fmt.Println(x.String())

fmt.Println((x.Intersection(y)).String()) /*{9}*/
}

这种方式实现集合更加高效

Site by ZHJ using Hexo & Random

Hide