Maison  >  Article  >  développement back-end  >  Comment implémenter un tableau de bits dans Golang (exemple de code)

Comment implémenter un tableau de bits dans Golang (exemple de code)

藏色散人
藏色散人avant
2020-08-11 13:21:553273parcourir

La colonne suivante du Tutoriel Golang vous présentera la méthode d'implémentation du tableau Bit dans Golang. J'espère qu'elle sera utile aux amis dans le besoin !

Comment implémenter un tableau de bits dans Golang (exemple de code)

Langage Go Méthodes courantes d'implémentation des tableaux de bits

Les collections en langage Go utilisent généralement map[T]bool In sous cette forme, T représente le type d'élément. Les collections sont représentées sous forme de types de cartes, bien qu'elles soient très flexibles, mais nous pouvons les exprimer d'une meilleure manière. Par exemple, dans le domaine de l'analyse des flux de données, l'élément de l'ensemble est généralement un entier non négatif, l'ensemble contiendra de nombreux éléments et l'ensemble effectuera souvent des opérations d'union et d'intersection. Dans ce cas, le tableau de bits en effectuera davantage. idéalement que la carte.

Un tableau de bits est généralement représenté par un nombre non signé ou une tranche appelée "mot". Chaque bit de chaque élément représente une valeur dans l'ensemble. Lorsque le i-ième bit d’un ensemble est défini, nous disons que l’ensemble contient l’élément i. Le programme suivant montre un type de tableau de bits simple et implémente trois fonctions pour opérer sur ce tableau de bits :

package main
import (
	"bytes"
	"fmt"
)
// An IntSet is a set of small non-negative integers.
// Its zero value represents the empty set.
type IntSet struct {
	words []uint
}
const (
	bitNum = (32 << (^uint(0) >> 63)) //根据平台自动判断决定是32还是64
)
// Has reports whether the set contains the non-negative value x.
func (s *IntSet) Has(x int) bool {
	word, bit := x/bitNum, uint(x%bitNum)
	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/bitNum, uint(x%bitNum)
	for word >= len(s.words) {
		s.words = append(s.words, 0)
	}
	s.words[word] |= 1 << bit
}
//A与B的交集,合并A与B
// 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)
		}
	}
}

Parce que chaque mot a 64 bits binaires, afin de localiser x Pour la position du bit, nous utilisons le quotient de x/64 comme indice du mot et utilisez la valeur obtenue par x%64 comme emplacement du bit dans le mot.

Par exemple, pour le chiffre 1, ajoutez-le au tableau de bits :

func (s *IntSet) Add(x int) {
	word, bit := x/bitNum, uint(x%bitNum) //0, 1 := 1/64, uint(1%64)
	for word >= len(s.words) { // 条件不满足
		s.words = append(s.words, 0)
	}
	s.words[word] |= 1 << bit // s.words[0] |= 1 << 1
}
// 把1存入后,words数组变为了[]uint64{2}

De même, si on ajoute 66 au tableau de bits :

func (s *IntSet) Add(x int) {
	word, bit := x/bitNum, uint(x%bitNum) //1, 2 := 66/64, uint(66%64)
	for word >= len(s.words) { // 条件满足
		s.words = append(s.words, 0) // 此时s.words = []uint64{2, 0}
	}
	s.words[word] |= 1 << bit // s.words[1] |= 1 << 2
}
// 继续把66存入后,words数组变为了[]uint64{2, 4}

Donc, pour les mots , chaque Il y a 64 valeurs qui peuvent être stockées dans chaque élément. Chaque fois que la valeur dépasse 64, un report est effectué, c'est-à-dire qu'un élément est ajouté. (Notez que 0 occupe également un bit, donc 64 doit être transporté et le premier élément peut stocker 0-63).

Donc, pour un élément en mots, lorsque vous souhaitez le convertir en une valeur spécifique : obtenez d'abord sa position i, utilisez 64 * i comme nombre de portages (similaire à un portage tous les 10 chiffres), et alors Cet élément est converti en nombre binaire En comptant de droite à gauche, le nombre de chiffres est 1, ce qui signifie que la valeur correspondante est présente Le nombre de chiffres x+64 *i est la valeur que nous stockons.

En conséquence, il peut y avoir la fonction String() suivante

// String returns the set as a string of the form "{1 2 3}".
func (s *IntSet) String() string {
	var buf bytes.Buffer
	buf.WriteByte(&#39;{&#39;)
	for i, word := range s.words {
		if word == 0 {
			continue
		}
		for j := 0; j < bitNum; j++ {
			if word&(1<<uint(j)) != 0 {
				if buf.Len() > len("{") {
					buf.WriteByte(&#39; &#39;)
				}
				fmt.Fprintf(&buf, "%d", bitNum*i+j)
			}
		}
	}
	buf.WriteByte(&#39;}&#39;)
	return buf.String()
}

Par exemple, après avoir stocké 1 et 66 précédemment, le processus de conversion est :

// []uint64{2 4}
// 对于2: 1 << 1 = 2; 所以 x = 0 * 64 + 1 
// 对于4: 1 << 2 = 4; 所以 x = 1 * 64 + 2
// 所以转换为String为{1 66}

Implémenter d'autres tableaux de bits Fonction de méthode

func (s *IntSet) Len() int {
	var len int
	for _, word := range s.words {
		for j := 0; j < bitNum; j++ {
			if word&(1<<uint(j)) != 0 {
				len++
			}
		}
	}
	return len
}
func (s *IntSet) Remove(x int) {
	word, bit := x/bitNum, uint(x%bitNum)
	if s.Has(x) {
		s.words[word] ^= 1 << bit
	}
}
func (s *IntSet) Clear() {
	s.words = append([]uint{})
}
func (s *IntSet) Copy() *IntSet {
	intSet := &IntSet{
		words: []uint{},
	}
	for _, value := range s.words {
		intSet.words = append(intSet.words, value)
	}
	return intSet
}
func (s *IntSet) AddAll(args ...int) {
	for _, x := range args {
		s.Add(x)
	}
}
//A与B的并集,A与B中均出现
func (s *IntSet) IntersectWith(t *IntSet) {
	for i, tword := range t.words {
		if i >= len(s.words) {
			continue
		}
		s.words[i] &= tword
	}
}
//A与B的差集,元素出现在A未出现在B
func (s *IntSet) DifferenceWith(t *IntSet) {
	t1 := t.Copy() //为了不改变传参t,拷贝一份
	t1.IntersectWith(s)
	for i, tword := range t1.words {
		if i < len(s.words) {
			s.words[i] ^= tword
		}
	}
}
//A与B的并差集,元素出现在A没有出现在B,或出现在B没有出现在A
func (s *IntSet) SymmetricDifference(t *IntSet) {
	for i, tword := range t.words {
		if i < len(s.words) {
			s.words[i] ^= tword
		} else {
			s.words = append(s.words, tword)
		}
	}
}
//获取比特数组中的所有元素的slice集合
func (s *IntSet) Elems() []int {
	var elems []int
	for i, word := range s.words {
		for j := 0; j < bitNum; j++ {
			if word&(1<<uint(j)) != 0 {
				elems = append(elems, bitNum*i+j)
			}
		}
	}
	return elems
}

À ce stade, les fonctions de méthode courantes des tableaux de bits ont été implémentées et vous pouvez maintenant les utiliser.

func main() {
	var x, y IntSet
	x.Add(1)
	x.Add(144)
	x.Add(9)
	fmt.Println("x:", x.String()) // "{1 9 144}"
	y.Add(9)
	y.Add(42)
	fmt.Println("y:", y.String()) // "{9 42}"
	x.UnionWith(&y)
	fmt.Println("x unionWith y:", x.String())         // "{1 9 42 144}"
	fmt.Println("x has 9,123:", x.Has(9), x.Has(123)) // "true false"
	fmt.Println("x len:", x.Len())                    //4
	fmt.Println("y len:", y.Len())                    //2
	x.Remove(42)
	fmt.Println("x after Remove 42:", x.String()) //{1 9 144}
	z := x.Copy()
	fmt.Println("z copy from x:", z.String()) //{1 9 144}
	x.Clear()
	fmt.Println("clear x:", x.String()) //{}
	x.AddAll(1, 2, 9)
	fmt.Println("x addAll 1,2,9:", x.String()) //{1 2 9}
	x.IntersectWith(&y)
	fmt.Println("x intersectWith y:", x.String()) //{9}
	x.AddAll(1, 2)
	fmt.Println("x addAll 1,2:", x.String()) //{1 2 9}
	x.DifferenceWith(&y)
	fmt.Println("x differenceWith y:", x.String()) //{1 2}
	x.AddAll(9, 144)
	fmt.Println("x addAll 9,144:", x.String()) //{1 2 9 144}
	x.SymmetricDifference(&y)
	fmt.Println("x symmetricDifference y:", x.String()) //{1 2 42 144}
	for _, value := range x.Elems() {
		fmt.Print(value, " ") //1 2 42 144
	}
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer