Go語言實現位集程式


位集是一種資料結構,它表示一組固定大小的二進位制值,每個值可以是 0 或 1。它通常用於高效地儲存和操作大量的布林值。在本文中,我們將使用兩種不同的方法在 Go 語言中實現位集,第一種方法涉及使用布林值的切片,第二種方法涉及使用無符號整數進行位操作。這裡的實現意味著我們將執行各種操作,例如設定、清除和測試位集資料結構中單個位。

解釋

位集是一種用於高效儲存和操作一組二進位制值的資料結構,其中每個值可以是 0 或 1。它特別適用於需要跟蹤大量布林值的情況,例如表示集合中元素的成員資格或存在。

Bitset: [0, 1, 0, 1, 0, 0, 1, 0]
Index:   0  1  2  3  4  5  6  7

語法

type BitSet struct{ data []uint64; size int }

語法:BitSet 結構使用 uint64 的切片實現位集。data 欄位是 uint64 的切片,用於儲存位集的實際位。size 欄位表示位集中的位總數。這種方法對於處理大量位非常節省記憶體,並且對 uint64 元素執行按位運算可以有效地操作單個位。

演算法

  • 建立一個具有空的 uint64 資料切片的 BitSet 結構,並將大小設定為位集中的所需位數。

  • 要設定特定位置 pos 的位,請使用 pos / 64 計算資料切片中 uint64 元素的索引,並使用 pos % 64 計算該 uint64 元素中位的位位置。使用按位或 (|) 將位設定為計算出的 uint64 元素中的位置。

  • 要清除特定位置 pos 的位,請類似於設定操作,計算 uint64 元素的索引和該元素中位的位位置。使用位與 (&) 和位掩碼的反運算來清除計算出的位置的位。

  • 要切換特定位置 pos 的位,請類似於設定操作,計算 uint64 元素的索引和該元素中位的位位置。使用按位異或 (^) 和位掩碼來切換計算出的位置的位。

  • 並集、交集和差集:要對兩個位集執行並集、交集和差集等集合運算,請在兩個位集的資料切片的元素之間應用相應的按位運算(或、與和異或)。

  • 要對位集執行移位和旋轉操作,請對資料切片元素使用按位移位和旋轉操作來向左或向右移動位。

示例 1

在這個例子中,我們將使用 uint64 的切片在 Go 中實現一個位集。切片中的每個 uint64 元素可以表示 64 位,允許我們有效地處理大量位。NewBitSet 函式使用指定的大小初始化位集。Set 函式設定給定索引處的特定位,Clear 函式清除給定索引處的位,Test 函式檢查給定索引處的位是否已設定。

package main

import "fmt"

type BitSet struct {
	bitArray []uint64
	size     int
}

func NewBitSet(size int) *BitSet {
	sliceSize := (size + 63) / 64
	return &BitSet{
		bitArray: make([]uint64, sliceSize),
		size:     size,
	}
}

func (bs *BitSet) Set(bit int) {
	if bit < 0 || bit >= bs.size {
		return
	}

	index := bit / 64
	offset := bit % 64
	bs.bitArray[index] |= 1 << offset
}

func (bs *BitSet) Clear(bit int) {
	if bit < 0 || bit >= bs.size {
		return
	}

	index := bit / 64
	offset := bit % 64
	bs.bitArray[index] &= ^(1 << offset)
}

func (bs *BitSet) Test(bit int) bool {
	if bit < 0 || bit >= bs.size {
		return false
	}

	index := bit / 64
	offset := bit % 64
	return (bs.bitArray[index] & (1 << offset)) != 0
}

func main() {
	bitSet := NewBitSet(128)

	bitSet.Set(1)
	bitSet.Set(3)
	bitSet.Set(5)
	bitSet.Set(120)

	fmt.Println("Bit at position 1 is set:", bitSet.Test(1))   
	fmt.Println("Bit at position 10 is set:", bitSet.Test(10)) 
	fmt.Println("Bit at position 3 is set:", bitSet.Test(3))   

}

輸出

Bit at position 1 is set: true
Bit at position 10 is set: false
Bit at position 3 is set: true

示例 2

在這個例子中,我們將使用固定大小的整數陣列在 Go 中實現一個位集。這裡每個整數表示固定數量的位。例如,使用 32 位整數,我們可以表示 32 位。我們將演示如何在位集中設定、清除和測試單個位。我們將使用 32 位整數陣列來表示位集,其中每個元素可以容納 32 位。

package main

import (
	"fmt"
)

type BitSet struct {
	bitArray []uint32
	size     int
}

func NewBitSet(size int) *BitSet {
	numElements := (size + 31) / 32
	return &BitSet{
		bitArray: make([]uint32, numElements),
		size:     size,
	}
}

func (bs *BitSet) Set(bit int) {
	if bit < 0 || bit >= bs.size {
		return
	}

	element := bit / 32
	bitWithinElement := bit % 32
	bs.bitArray[element] |= (1 << uint32(bitWithinElement))
}

func (bs *BitSet) Clear(bit int) {
	if bit < 0 || bit >= bs.size {
		return
	}

	element := bit / 32
	bitWithinElement := bit % 32
	bs.bitArray[element] &= ^(1 << uint32(bitWithinElement))
}

func (bs *BitSet) Test(bit int) bool {
	if bit < 0 || bit >= bs.size {
		return false
	}

	element := bit / 32
	bitWithinElement := bit % 32
	return bs.bitArray[element]&(1<<uint32(bitWithinElement)) != 0
}

func main() {
	bitSet := NewBitSet(128)

	bitSet.Set(1)
	bitSet.Set(3)
	bitSet.Set(5)
	bitSet.Set(120)

	fmt.Println("Bit at position 1 is set:", bitSet.Test(1))   
	fmt.Println("Bit at position 10 is set:", bitSet.Test(10)) 
	fmt.Println("Bit at position 3 is set:", bitSet.Test(3))   

}

輸出

Bit at position 1 is set: true
Bit at position 10 is set: false
Bit at position 3 is set: true

現實生活中的應用

網路資料包過濾

位集用於網路資料包過濾,其中路由器和防火牆將傳入資料包與規則匹配。每個規則都表示為一個位集,其中位表示源 IP 範圍、協議或資料標誌等條件。高效的按位運算有助於快速確定是否允許資料包。

稀疏資料索引

在資料庫和搜尋引擎中,位集索引用於稀疏資料。它將屬性壓縮為位,從而節省記憶體。例如,在搜尋引擎中,位集標識包含特定術語的文件。設定的位表示術語的存在,從而使索引和查詢速度更快。

結論

位集是一種用於高效儲存和操作一組二進位制值的資料結構,其中每個值可以是 0 或 1。在本文中,我們研究瞭如何在 Go 中實現位集:一種使用 uint64 的切片,另一種使用固定大小的整數陣列。對於處理大量位,第一個示例在記憶體效率方面更高,而對於較少數量的位,第二個示例的記憶體效率更高。

更新於:2023年9月5日

瀏覽量:265

開啟您的職業生涯

透過完成課程獲得認證

開始學習
廣告
© . All rights reserved.