欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析Go語言bitset的實現(xiàn)原理

 更新時間:2023年08月08日 11:32:55   作者:Go學(xué)堂  
bitset包是一個將非負整數(shù)映射到布爾值的位的集合,這篇文章主要通過開源包bitset來為大家分析一下位集合的設(shè)計和實現(xiàn),感興趣的可以學(xué)習(xí)一下

一、bitset簡介

1.1、主要功能

bitset包是一個將非負整數(shù)映射到布爾值的位的集合。比如我們有一個64位的二進制序列,要將第N位設(shè)置成true,對應(yīng)的就是將第N位置成1。如下:

該包因為使用的是位操作,所以比使用map[uint]bool來實現(xiàn)非負整數(shù)到布爾值的映射會更高效。

該包不僅提供了setting、clearing、flipping和testing的方法。還提供了集合的交集、并集、差集等方法。

1.2、github上的基礎(chǔ)屬性

項目地址: https://github.com/bits-and-blooms/bitset 

1.3、誰在用

二、設(shè)計與實現(xiàn)

在了解了bitset的基本功能之后,我們來分析bitset的設(shè)計和實現(xiàn)。

2.1 數(shù)據(jù)結(jié)構(gòu)

在bitset包中,核心的數(shù)據(jù)結(jié)構(gòu)是BitSet。其定義如下:

// A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0.
type BitSet struct {
	length uint
	set    []uint64
}

set字段為什么是一個切片?

首先來看為什么使用uint64的數(shù)據(jù)類型。bitset不是按位存儲的集合嗎,怎么set的數(shù)據(jù)類型是uint64呢?

這里就涉及到計算機的一個基礎(chǔ)知識點:

計算機存儲和處理的信息都是以二值信號表示的。所謂的二值信號就是0和1,也就是我們常說的二進制。

所以,整數(shù)的底層也是二進制位。uint64在go語言中就代表的是用64個二進制位表示的整數(shù)值。

在bitset中,我們先假設(shè)set字段只有一個uint64的整數(shù)。那么,如果我們想將第7位設(shè)置成1,那么就如下:

但是,一個uint64的整數(shù)最多也就只有64個二進制位。那如果我們想設(shè)置第100位為true,那又該怎么表示呢? 這也就是set字段的類型為什么是一個切片的原因了。既然一個uint64最多只能表示64個二進制位,那么我就用多個uint64不就能表示更多的二進制位了嗎。

所以,set中第一個uint64表示前64個二進制位,第二個uint64表示65到128的二進制位,以此類推。這樣就理論上就可以表示任意位數(shù)的二進制位了。

2.2 length字段代表的是什么的長度

length字段表示在初始化一個BitSet對象時,該BitSet對象總共能容納多少位,根據(jù)這個總位數(shù)來分配set字段的切片長度。如下:

// New creates a new BitSet with a hint that length bits will be required
func New(length uint) (bset *BitSet) {
	defer func() {
		if r := recover(); r != nil {
			bset = &BitSet{
				0,
				make([]uint64, 0),
			}
		}
	}()
	bset = &BitSet{
		length,
		make([]uint64, wordsNeeded(length)),
	}
	return bset
}

看代碼的第12到15行。在第14行中,需要計算的是要表示length個二進制位需要幾個uint64的非負整數(shù)來表示。這里通過wordsNeeded函數(shù)來計算的,如下:

// wordsNeeded calculates the number of words needed for i bits
func wordsNeeded(i uint) int {
	if i > (Cap() - wordSize + 1) {
		return int(Cap() >> log2WordSize)
	}
	return int((i + (wordSize - 1)) >> log2WordSize)
}

這里主要看第6行的int((i + (wordSize - 1)) >> log2WordSize)。這里有幾個常量,如下:

  • **log2WordSize常量:**在bitset中的定義是uint(6)。為什么是6呢?因為2的6次方是64,而我們在set字段中又是用uint64來表示一組二進制位的。 同時 看這個計算右移6位,右移6位代表什么?就是代表用左邊的數(shù)除以64(2的6次方)的商。這里我們要計算length個位數(shù)一共能用幾個uint64來表示,就是用length除以64即可了。
  • **wordSize常量:在bitset中的定義是uint(64)。**正好表示的是64位,一個uint64類型的位數(shù)。這里要看一下為什么還要用i(也就是length)加上一個(wordSize-1)呢?。舉個例子,假設(shè)i=65,即要表示65個二進制位,那需要用兩個uint64的整數(shù)來表示才行。但65右移6位是1,所以需要加上wordSize-1再右移6位,結(jié)果就是2,即用2個uint64的整數(shù)才能存儲65位的二進制位。

所以,wordsNeeded函數(shù)表示的就是要存儲i個二進制位需要用幾個uint64的整數(shù)。

2.3 如何在整數(shù)中實現(xiàn)位操作

為了簡便,我們用uint8來說明。uint8代表的是一個8位的非負整數(shù)。例如,要把uint8的第2位設(shè)置成1。用二進制表示就是:00000100。這個怎么得到呢?我們知道1的二進制表示是00000001,那么讓這個1左移2位就能得到結(jié)果00000100。即 1<<2

如果再把該uint8的第3位也設(shè)置成1,怎么辦呢?首先讓1左移3位得到00001000。因為原有uint8的第二位也是1,這里就要用uint8原有的值和00001000進行做或操作,就能保持住uint8原有的位的值不變了。如下:

原有的uint8(第二位是1):00000100
          第三位設(shè)置成1:00001000
     -----------------------------
或的結(jié)果:              00001100

以上就是在整數(shù)中進行的位操作。

2.4 如何計算第N位落在哪個分組上

在上面的BitSet的數(shù)據(jù)結(jié)構(gòu)中,我們知道set字段是一個uint64的切片類型,相當于把每64位分成一組。那么,當設(shè)置第N位為1的時候,首先要做的是計算第N位應(yīng)該落在哪個分組上。這個是怎么計算呢?就是第N位是63(因為位數(shù)是從0開始的)的多少倍,比如要設(shè)置第66位為1,那么66位是63的1倍(余數(shù)省略),所以在切片的第1個分組上(索引是從0開始,實際是切片的第二個分組)。

還是以uint8(8位)一組為例來說。如果要設(shè)置第10位,則落在第二個uint8的分組上。如下:

按位操作來計算除法就是右移操作。這里讓N右移3位,因為移動3位,代表的2的3次方,即8。也是用10除以8的商是1,即在set切片的第1個索引上,也就是第二個uint8上。

2.5 如何計算第N位落在分組的第幾位上

其次,要計算第N位是在第2個分組的第幾位上。簡單點就是取余操作。用10%8,就是第2位上(因為從0開始,所以是第3位)。 同樣,這里還有一種按位移操作的方法:10&7。我們解釋下這個與操作。 我們看下8的二進制表示:1000。要想讓10除以8,就是將第3位的1抹掉,并保持其他位不變。要想保持原有位保持不變,就和1進行與操作。所以,讓二進制的1000變成0111,再和10的二進制進行與操作,就相當于除以8取余數(shù)了。如下:

你看,這樣就把最高位的1給消除了,結(jié)果余數(shù)是2的1次方,即2。 最后,因為一個uint8的整數(shù)的最高位是第7位(從0位開始),所以第10位應(yīng)該是第二個uint8的第3位上。最后讓1再左移上述結(jié)果的2位即可。

如下是bitset的實現(xiàn):

// log2WordSize is lg(wordSize)
const log2WordSize = uint(6)
func (b *BitSet) Set(i uint) *BitSet {
	if i >= b.length { // if we need more bits, make 'em
		b.extendSet(i)
	}
	// 說明第0位從右邊往左邊數(shù)的
	b.set[i>>log2WordSize] |= 1 << wordsIndex(i)
	return b
}
// the wordSize of a bit set
const wordSize = uint(64)
// wordsIndex calculates the index of words in a `uint64`
func wordsIndex(i uint) uint {
	return i & (wordSize - 1)
}

以上就是針對BitSet最基本的數(shù)據(jù)結(jié)構(gòu)以及如何設(shè)置一個位為1的實現(xiàn),其他的方法基本都是類似的思想來實現(xiàn)的,有興趣大家可以繼續(xù)研讀該包的源代碼。

總結(jié)

bitset基于uint64的整數(shù)實現(xiàn)了位的操作。該包的代碼實現(xiàn)中涉及到大量的位操作。閱讀本包的源代碼,可以幫助大家理解位操作的概念以及應(yīng)用場景。

以上就是淺析Go語言bitset的實現(xiàn)原理的詳細內(nèi)容,更多關(guān)于Go bitset的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang三個編譯基本命令的使用小結(jié)

    Golang三個編譯基本命令的使用小結(jié)

    本文主要介紹了Golang三個編譯基本命令的使用小結(jié),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Go語言中的流程控制結(jié)構(gòu)和函數(shù)詳解

    Go語言中的流程控制結(jié)構(gòu)和函數(shù)詳解

    這篇文章主要介紹了Go語言中的流程控制結(jié)構(gòu)和函數(shù)詳解,本文詳細講解了if、goto、for、switch等控制語句,同時對函數(shù)相關(guān)知識做了講解,需要的朋友可以參考下
    2014-10-10
  • Go語言讀取,設(shè)置Cookie及設(shè)置cookie過期方法詳解

    Go語言讀取,設(shè)置Cookie及設(shè)置cookie過期方法詳解

    這篇文章主要介紹了Go語言讀取,設(shè)置Cookie及設(shè)置cookie過期方法詳解,需要的朋友可以參考下
    2022-04-04
  • goland 搭建 gin 框架的步驟詳解

    goland 搭建 gin 框架的步驟詳解

    這篇文章主要介紹了goland 搭建 gin 框架的相關(guān)知識,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • golang 如何獲取map所有key的方式

    golang 如何獲取map所有key的方式

    這篇文章主要介紹了golang 獲取map所有key的方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go并發(fā)同步Mutex典型易錯使用場景

    Go并發(fā)同步Mutex典型易錯使用場景

    這篇文章主要為大家介紹了Go并發(fā)同步Mutex典型易錯使用場景示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • golang實現(xiàn)枚舉的幾種方式

    golang實現(xiàn)枚舉的幾種方式

    在Go語言中,雖沒有內(nèi)置枚舉類型,但可通過常量、結(jié)構(gòu)體或自定義類型和方法實現(xiàn)枚舉功能,這些方法提高了代碼的可讀性和維護性,避免了魔法數(shù)字的使用,感興趣的可以了解一下
    2024-09-09
  • golang實現(xiàn)讀取excel數(shù)據(jù)并導(dǎo)入數(shù)據(jù)庫

    golang實現(xiàn)讀取excel數(shù)據(jù)并導(dǎo)入數(shù)據(jù)庫

    Go 語言是一門適合用于編寫高效且并發(fā)的 Web 應(yīng)用程序的編程語言,同時也可以使用它進行數(shù)據(jù)處理和分析,本文主要介紹了如何通過go語言實現(xiàn)讀取excel數(shù)據(jù)并導(dǎo)入數(shù)據(jù)庫,感興趣的小伙伴可以了解下
    2025-04-04
  • go函數(shù)的參數(shù)設(shè)置默認值的方法

    go函數(shù)的參數(shù)設(shè)置默認值的方法

    Go語言不直接支持函數(shù)參數(shù)默認值,但可以通過指針、結(jié)構(gòu)體、變長參數(shù)和選項模式等方法模擬,下面給大家分享幾種方式模擬函數(shù)參數(shù)的默認值功能,感興趣的朋友一起看看吧
    2025-01-01
  • GoLang中Strconv庫有哪些常用方法

    GoLang中Strconv庫有哪些常用方法

    這篇文章主要介紹了GoLang中Strconv庫有哪些常用方法,strconv庫實現(xiàn)了基本數(shù)據(jù)類型與其字符串表示的轉(zhuǎn)換,主要有以下常用函數(shù):?Atoi()、Itia()、parse系列、format系列、append系列
    2023-01-01

最新評論