最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

一、bitset簡(jiǎn)介

1.1、主要功能

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

該包因?yàn)槭褂玫氖俏徊僮鳎员仁褂胢ap[uint]bool來(lái)實(shí)現(xiàn)非負(fù)整數(shù)到布爾值的映射會(huì)更高效。

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

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

項(xiàng)目地址: https://github.com/bits-and-blooms/bitset 

1.3、誰(shuí)在用

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

在了解了bitset的基本功能之后,我們來(lái)分析bitset的設(shè)計(jì)和實(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字段為什么是一個(gè)切片?

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

這里就涉及到計(jì)算機(jī)的一個(gè)基礎(chǔ)知識(shí)點(diǎn):

計(jì)算機(jī)存儲(chǔ)和處理的信息都是以二值信號(hào)表示的。所謂的二值信號(hào)就是0和1,也就是我們常說(shuō)的二進(jìn)制。

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

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

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

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

2.2 length字段代表的是什么的長(zhǎng)度

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

// 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行中,需要計(jì)算的是要表示length個(gè)二進(jìn)制位需要幾個(gè)uint64的非負(fù)整數(shù)來(lái)表示。這里通過(guò)wordsNeeded函數(shù)來(lái)計(jì)算的,如下:

// 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)。這里有幾個(gè)常量,如下:

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

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

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

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

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

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

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

2.4 如何計(jì)算第N位落在哪個(gè)分組上

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

還是以u(píng)int8(8位)一組為例來(lái)說(shuō)。如果要設(shè)置第10位,則落在第二個(gè)uint8的分組上。如下:

按位操作來(lái)計(jì)算除法就是右移操作。這里讓N右移3位,因?yàn)橐苿?dòng)3位,代表的2的3次方,即8。也是用10除以8的商是1,即在set切片的第1個(gè)索引上,也就是第二個(gè)uint8上。

2.5 如何計(jì)算第N位落在分組的第幾位上

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

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

如下是bitset的實(shí)現(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)
	}
	// 說(shuō)明第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)
}

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

總結(jié)

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

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

相關(guān)文章

  • golang 輸出重定向:fmt Log,子進(jìn)程Log,第三方庫(kù)logrus的詳解

    golang 輸出重定向:fmt Log,子進(jìn)程Log,第三方庫(kù)logrus的詳解

    這篇文章主要介紹了golang 輸出重定向:fmt Log,子進(jìn)程Log,第三方庫(kù)logrus的詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • go?doudou應(yīng)用中使用枚舉類(lèi)型教程示例

    go?doudou應(yīng)用中使用枚舉類(lèi)型教程示例

    這篇文章主要為大家介紹了go?doudou應(yīng)用中使用枚舉類(lèi)型教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 詳解Golang中Context的原理和使用技巧

    詳解Golang中Context的原理和使用技巧

    Golang?的?Context?包,中文可以稱(chēng)之為“上下文”,是用來(lái)在?goroutine?協(xié)程之間進(jìn)行上下文信息傳遞的,這些上下文信息包括?kv?數(shù)據(jù)、取消信號(hào)、超時(shí)時(shí)間、截止時(shí)間等。本文主要介紹了Context的原理和使用技巧,希望對(duì)大家有所幫助
    2022-11-11
  • 淺談一下前端http與https有什么區(qū)別

    淺談一下前端http與https有什么區(qū)別

    這篇文章主要介紹了淺談一下前端http與https有什么區(qū)別,現(xiàn)今大部分的網(wǎng)站都已經(jīng)使用了 https 協(xié)議,那么https對(duì)比http協(xié)議有哪些不同呢,需要的朋友可以參考下
    2023-04-04
  • 淺析Golang中rune類(lèi)型的使用

    淺析Golang中rune類(lèi)型的使用

    從golang源碼中看出,rune關(guān)鍵字是int32的別名(-231~231-1),對(duì)比byte(-128~127),可表示的字符更多,本文就來(lái)簡(jiǎn)單聊聊它的使用方法吧,希望對(duì)大家有所幫助
    2023-05-05
  • Go GORM版本2.0新特性介紹

    Go GORM版本2.0新特性介紹

    這篇文章主要為大家介紹了Go GORM版本2.0新特性的使用示例介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Golang中使用Date進(jìn)行日期格式化(沿用Java風(fēng)格)

    Golang中使用Date進(jìn)行日期格式化(沿用Java風(fēng)格)

    這篇文章主要介紹了Golang中使用Date進(jìn)行日期格式化,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • golang框架中跨服務(wù)的最佳通信協(xié)議和工具

    golang框架中跨服務(wù)的最佳通信協(xié)議和工具

    在 go 框架中實(shí)現(xiàn)跨服務(wù)通信的最佳實(shí)踐包括使用 grpc(適用于低延遲高吞吐量)、http 客戶端(適用于 restful api)和消息隊(duì)列(適用于異步解耦通信),在選擇通信方式時(shí),應(yīng)考慮服務(wù)交互模式、性能要求和部署環(huán)境等因素
    2024-06-06
  • Golang?基于flag庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單命令行工具

    Golang?基于flag庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單命令行工具

    這篇文章主要介紹了Golang基于flag庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單命令行工具,Golang標(biāo)準(zhǔn)庫(kù)中的flag庫(kù)提供了解析命令行選項(xiàng)的能力,我們可以基于此來(lái)開(kāi)發(fā)命令行工具,下文詳細(xì)介紹。需要的小伙伴可以參考一下
    2022-08-08
  • golang中new與make的區(qū)別講解

    golang中new與make的區(qū)別講解

    new只能開(kāi)辟單個(gè)空間,不能為引用類(lèi)型開(kāi)辟多個(gè)空間,并且new是對(duì)類(lèi)型進(jìn)行內(nèi)存的開(kāi)辟,返回一個(gè)指向該內(nèi)存空間的指針類(lèi)型,如果使用new去初始化引用數(shù)據(jù)類(lèi)型,不是很合適(當(dāng)然,new一個(gè)對(duì)象還是可以的),因此就需要用到另一個(gè)內(nèi)置函數(shù)make,需要的朋友可以參考下
    2023-01-01

最新評(píng)論

五家渠市| 乌审旗| 梁河县| 西贡区| 朔州市| 旌德县| 东明县| 黄山市| 什邡市| 常德市| 松溪县| 五台县| 望江县| 育儿| 嘉兴市| 台东市| 犍为县| 澄迈县| 宽甸| 阿拉善右旗| 宜丰县| 无为县| 班戈县| 弥勒县| 武鸣县| 嘉峪关市| 成安县| 泽普县| 剑阁县| 顺昌县| 鄂伦春自治旗| 衡阳县| 武汉市| 晋州市| 墨玉县| 浦城县| 中宁县| 乌拉特前旗| 定南县| 萨嘎县| 汉沽区|