編程珠璣:如何使用位邏輯運算來實現位向量 - Swift

題目描述:使用二進制位來表示整數,好比將二進制位的第 9 位置爲 1 來表示整數 9 。數組

二進制:10 0000 0000 表明 十進制:9bash

由於 Int 類型佔用四個字節,共 32 位,若是每一位存儲一個整數的話,則數組的第一個元素能夠表示: 1~32,第二個元素能夠表示:33~64 ...以此類推。函數

首先定義一下要使用的變量,假設咱們須要存儲 1億 之內的整數 :測試

let bits = 32 // Int 佔用 4 個字節,一共 32 位
let shift = 5 // 32 爲 2 的 5 次方,即偏移量爲 5
let mask = 31 
let n = 10_000_000
var nums = Array(repeating: 0, count: 1 + n / bits)
複製代碼

添加函數

接下來咱們看一下添加函數。該函數須要如下的三步:ui

  • 1)計算出當前整數在數組中的索引
  • 2)計算出 2 的當前整數的次方
  • 3)將第 2 步中得出的值再或上數組中當前索引存儲的值,將結果存入數組便可

下面來詳細說一下上面的三步:spa

計算出當前整數在數組中的索引

以十進制整數 45 舉例。下面是計算 45 的索引代碼:code

let index = 45 >> shift // 等價於 45 / 32 
複製代碼

上述代碼計算得出 45 的索引爲 1 ,即 index = 1。計算出索引以後要計算在該索引存儲的具體值。索引

計算出 2 的當前整數的次方

以 45 來舉例:element

let power = 1 << (45 & mask) // 至關與求 2 的 45 次方
複製代碼

將第 2 步中得出的值再或上數組中當前索引存儲的值,將結果存入數組

let oldValue = nums[index]
let newValue = oldValue | power
nums[index] = newValue
複製代碼

採用或的方式是由於這樣不會影響上次存儲的值,由於上次存儲的值已將相應位置爲 1 。rem

完整的添加函數:

func set(_ newElement: Int) {
    let index = newElement >> shift
    let power = 1 << (newElement & mask)
    let oldValue = nums[index]
    let newValue = oldValue | power
    nums[index] = newValue
}
複製代碼

移除函數

移除函數共須要三步:

  • 1)計算索引(同上)
  • 2)計算出 2 的當前整數的次方,而後取反
  • 3)將第 2 步中得出的值再與上數組中當前索引存儲的值,將結果存入數組

計算出 2 的當前整數的次方,取反

let power = 1 << (element & mask)
let negation = ~power
let oldValue = nums[index]
let newValue = oldValue & negation
nums[index] = newValue
複製代碼

完整的移除函數:

func remove(_ element: Int) {
    let index = element >> shift
    let power = 1 << (element & mask)
    let negation = ~power
    let oldValue = nums[index]
    let newValue = oldValue & negation
    nums[index] = newValue
}
複製代碼

獲取函數

獲取函數共須要三步:

  • 1)計算索引(同上)
  • 2)計算出 2 的當前整數的次方(同上)
  • 3)將第 2 步中得出的值再與上數組中當前索引存儲的值,返回結果

完整代碼:

func get(_ element: Int) -> Int {
    let index = element >> shift
    let value = 1 << (element & mask)
    return nums[index] & value
}
複製代碼

測試代碼

set(30)
print(nums[0]) // 2 的 30 次方 1073741824
print(get(30)) // 1073741824
remove(30)
print(get(30)) // 0
複製代碼

易讀版完整代碼:

func set(_ newElement: Int) {
    let index = newElement >> shift
    let power = 1 << (newElement & mask)
    let oldValue = nums[index]
    let newValue = oldValue | power
    nums[index] = newValue
}

func remove(_ element: Int) {
    let index = element >> shift
    let power = 1 << (element & mask)
    let negation = ~power
    let oldValue = nums[index]
    let newValue = oldValue & negation
    nums[index] = newValue
}

func get(_ element: Int) -> Int {
    let index = element >> shift
    let value = 1 << (element & mask)
    return nums[index] & value
}
複製代碼

下面的代碼版本爲簡易版本(我的感受不太易讀):

func set(_ newElement: Int) {
    let index = newElement >> shift
    let curNum = nums[index]
    nums[index] = curNum | (1 << (newElement & mask))
}

func remove(_ element: Int) {
    let index = element >> shift
    nums[index] &= ~(1 << (element & mask))
}

func get(_ element: Int) -> Int {
    let index = element >> shift
    return nums[index] & (1 << (element & mask))
}
複製代碼
相關文章
相關標籤/搜索