Go語言實現bitmap算法


有關bitmap算法的介紹資料網上很多,這里不贅述,各種語言的實現也不少,但是Go語言版的bitmap不多,本文就來寫一個Go版的bitmap實現。

首先創建一個 bitmap.go 文件,定義一個bitmap結構體,再提供一些操作方法。詳細代碼如下:

package bitmap

import (
    "fmt"
    "strings"
)

const (
    bitSize = 8
)

var bitmask = []byte{1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7}
// 首字母小寫 只能調用 工廠函數 創建
type bitmap struct {
    bits     []byte
    bitCount uint64 // 已填入數字的數量
    capacity uint64 // 容量
}
// 創建工廠函數
func NewBitmap(maxnum uint64) *bitmap {
    return &bitmap{bits: make([]byte, (maxnum+7)/bitSize), bitCount: 0, capacity: maxnum}
}

// 填入數字
func (this *bitmap) Set(num uint64) {
    byteIndex, bitPos := this.offset(num)
    // 1 左移 bitPos 位 進行 按位或 (置為 1)
    this.bits[byteIndex] |= bitmask[bitPos]
    this.bitCount++
}

// 清除填入的數字
func (this *bitmap) Reset(num uint64) {
    byteIndex, bitPos := this.offset(num)
    // 重置為空位 (重置為 0)
    this.bits[byteIndex] &= ^bitmask[bitPos]
    this.bitCount--
}

// 數字是否在位圖中
func (this *bitmap) Test(num uint64) bool {
    byteIndex := num / bitSize
    if byteIndex >= uint64(len(this.bits)) {
        return false
    }
    bitPos := num % bitSize
    // 右移 bitPos 位 和 1 進行 按位與
    return !(this.bits[byteIndex]&bitmask[bitPos] == 0)
}

func (this *bitmap) offset(num uint64) (byteIndex uint64, bitPos byte) {
    byteIndex = num / bitSize // 字節索引
    if byteIndex >= uint64(len(this.bits)) {
        panic(fmt.Sprintf(" runtime error: index value %d out of range", byteIndex))
        return
    }
    bitPos = byte(num % bitSize) // bit位置
    return byteIndex, bitPos
}

// 位圖的容量
func (this *bitmap) Size() uint64 {
    return uint64(len(this.bits) * bitSize)
}

// 是否空位圖
func (this *bitmap) IsEmpty() bool {
    return this.bitCount == 0
}

// 是否已填滿
func (this *bitmap) IsFully() bool {
    return this.bitCount == this.capacity
}

// 已填入的數字個數
func (this *bitmap) Count() uint64 {
    return this.bitCount
}

// 獲取填入的數字切片
func (this *bitmap) GetData() []uint64 {
    var data []uint64
    count := this.Size()
    for index := uint64(0); index < count; index++ {
        if this.Test(index) {
            data = append(data, index)
        }
    }
    return data
}

func (this *bitmap) String() string {
    var sb strings.Builder
    for index := len(this.bits) - 1; index >= 0; index-- {
        sb.WriteString(byteToBinaryString(this.bits[index]))
        sb.WriteString(" ")
    }
    return sb.String()
}

func byteToBinaryString(data byte) string {
    var sb strings.Builder
    for index := 0; index < bitSize; index++ {
        if (bitmask[7-index] & data) == 0 {
            sb.WriteString("0")
        } else {
            sb.WriteString("1")
        }
    }
    return sb.String()
}

 代碼中有注釋,很容易看懂。下面寫測試代碼,測試這個bitmap。

package main

import (
    "bitmap"
    "fmt"
)

func main() {
    array := [...]uint64{0, 6, 3, 7, 2, 8, 1, 4}

    var maxNum uint64 = 9
    bm := bitmap.NewBitmap(maxNum)

    for _, v := range array {
        bm.Set(v)
    }
    bm.Set(5)
    fmt.Println(bm.IsFully())
    fmt.Println(bm.IsEmpty())
    fmt.Println("bitmap 中存在的數字:")
    fmt.Println(bm.GetData())
    fmt.Println("bitmap 中的二進制串")
    fmt.Println(bm.String())
    fmt.Println("bitmap 中的數字個數:", bm.Count())
    fmt.Println("bitmap size:", bm.Size())
    fmt.Println("Test(0):", bm.Test(0))
    bm.Reset(5)
    fmt.Println(bm.String())
    fmt.Println("Test(5):", bm.Test(5))
    fmt.Println(bm.GetData())
}

 測試代碼的輸出如下:

true
false
bitmap 中存在的數字:
[0 1 2 3 4 5 6 7 8]
bitmap 中的二進制串
00000001 11111111
bitmap 中的數字個數: 9
bitmap size: 16
Test(0): true
00000001 11011111
Test(5): false
[0 1 2 3 4 6 7 8]

最后小結,bitmap的實現代碼可以根據需要添加其它方法,本文的實現僅供參考。另外文中的代碼不是線程安全的,多線程中使用需要改寫bitmap的代碼加上鎖。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM