《swift-algorithm-club》——数据结构/集合

·  阅读 974

集合(Sets)

布隆过滤器

布隆过滤器是一种节省空间的数据结构 (哈希表空间换时间),可以告诉我们元素是否存在于集合中。

这是一个概率数据结构:对布隆过滤器的查询返回 false,意味着该元素肯定不在集合中。如果返回 true,这意味着元素可能在集合中。

所以布隆过滤器告诉你,“绝对不是”或“可能是的”。

将对象插入集合中

布隆过滤器本质上是一个固定长度的位向量,一个位数组。当我们插入对象时,我们将其中一些位设置为1,当我们查询对象时,我们检查某些位是0还是1。两个操作都使用哈希函数。

要在过滤器中插入元素,可以使用多个不同的哈希函数对元素进行哈希。每个哈希函数返回一个我们映射到数组中索引的值。然后,我们将这个索引处的位设置为1true

查询集合

类似于插入,查询是通过首先对期望值进行哈希来实现的,该期望值给出几个数组索引,然后检查这些索引处的所有为是否为1。如果其中一个位不是1,则该元素没有被插入过,并且查询返回 false。如果所有为都是1,则查询返回 true

使用布隆过滤器无法删除,因为任何一个位都有可能属于多个元素。一旦你添加了一个元素,它就在那里。

布隆过滤器的性能是O(k),其中k是哈希函数的数量。

初始化

public init(size: Int = 1024, hashFunctions: [(T) -> Int]) {
  self.array = [Bool](repeating: false, count: size)
  self.hashFunctions = hashFunctions
}
复制代码

插入

public func insert(_ element: T) {
  for hashValue in computeHashes(element) {
    array[hashValue] = true
  }
}

private func computeHashes(_ value: T) -> [Int] {
  return hashFunctions.map() { hashFunc in abs(hashFunc(value) % array.count) }
}
复制代码

查询

public func query(_ value: T) -> Bool {
  let hashValues = computeHashes(value)
  let results = hashValues.map() { hashValue in array[hashValue] }
  let exists = results.reduce(true, { $0 && $1})
  return exist
}
复制代码

哈希集合

基础

public struct HashSet<T: Hashable> {
  fileprivate var dictionary = Dictionary<T, Bool>()
  
  public init() {
    
  }
  
  public mutating func insert(_ element: T) {
    dictionary[element] = true
  }
  
  public mutating func remove(_ element: T) {
    dictionary[element] = nil
  }
  
 	public func contains(_ element: T) -> Bool {
  	return dictionary[element] != nil
 	} 
 	
  public func allElements() -> [T] {
    return Array(dictionary.keys)
  }
  
  public var count: Int {
    return dictionary.count
  }
  
  public var isEmpty: Bool {
    return dictionary.isEmpty
  } 
} 
复制代码

合并

extension HashSet {
  public func union(_ otherSet: HashSet<T>) -> HashSet<T> {
    var combined = HashSet<T>()
    for obj in self.dictionary.keys {
      combined.insert(obj)
    }
    for obj in otherSet.dictionary.keys {
      combined.insert(obj)
    }
    return combined
  }
}
复制代码

并集

extension HashSet {
  public func intersect(_ otherSet: HashSet<T>) -> HashSet<T> {
    var common = HashSet<T>()
    for obj in dictionary.keys {
      if otherSet.contains(obj) {
        common.insert(obj)
      }
    }
    return common
  }
}
复制代码

A - B

extension HashSet {
  public func difference(_ otherSet: HashSet<T>) -> HashSet<T> {
    var diff = HashSet<T>()
    for obj in dictionary.keys {
      if !otherSet.contains(obj) {
        diff.insert(obj)
      }
    }
    return diff
  }
}
复制代码

多重集

var set = Multiset<Int>()
set.add(1) // set is now [1]
set.add(2) // set is now [1, 2]
set.add(2) // set is now [1, 2, 2]
复制代码

这看起来像是一个数组。差异是:

  • 顺序:数组维护添加到它的项的顺序,多重集合没有
  • 测试成员资格:测试元素是否是其成员,数组是O(n),多重集合是O(1)
  • 测试子集:测试集合X是否是集合Y的子集,对于多重集而言是一个简单的操作,但对于数组来说是复杂的。

使用字典实现

public struct Multiset<Element: Hashable> {
  private var storage: [Element: UInt] = [:]
  
  public init() {}
}
复制代码

添加元素

public mutating func add (_ elem: Element) {
  storage[elem, default: 0] += 1
}
复制代码

删除元素

public mutating func remove(_ elem: Element) {
  if let currentCount = storage[elem] {
    if currentCount > 1 {
      storage[elem] = currentCount - 1
    } else {
      storage.removeValue(forKey: elem)
    }
  }
}
复制代码

有序集

首先看看APPLE实现的有序集是怎样表现的:

let s = AppleOrderedSet<Int>()

s.add(1)
s.add(2)
s.add(-1)
s.add(0)
s.insert(4, at:3)

print(s.all()) // [1, 2, -1, 4, 0]

s.set(-1, at: 0) // 已经有-1在index: 2,因此这个操作不做任何事情

print(s.all()) // [1, 2, -1, 4, 0]

s.remove(-1)

print(s.all()) // [1, 2, 4, 0]

print(s.object(at: 1)) // 2

print(s.object(at: 2)) // 4
复制代码

很容易考虑哈希表实现

var indexOfKey: [T: Int]
var objects: [T]
复制代码

添加

// O(1)
public func add(_ object: T) {
  guard indexOfKey[object] == nil else {
    return
  }
  objects.append(object)
  indexOfKey[object] = objects.count - 1
}
复制代码

插入

// O(n)
public func insert(_ object: T, at index: Int) {
  assert(index < objects.count, "Index should be smaller than object count")
  assert(index >= 0, "Index should be bigger than 0")
  
  guard indexOfKey[object] == nil else {
    return
  }
  
  objects.insert(object, at: index)
  indexOfKey[object] = index
  for i in index+1..<objects.count {
    indexOfKey[objects[i]] = i
  }
}
复制代码

设置(如果object已存在于OrderedSet中,则什么也不做。否则,我们需要更新indexOfKeyobjects。)

// O(1)
public func set(_ object: T, at index: Int) {
  assert(index < object.count, "Index should be smaller than object count")
  assert(index >= 0, "Index should be bigger than 0")
  
  guard indexOfKey[object] == nil else {
    return
  }
  
  indexOfKey.removeValue(forKey: objects[index])
  indexOfKey[object] = index
  objects[index] = object
}
复制代码

删除

// O(n)
public func remove(_ object: T) {
  guard let index = indexOfKey[object] else {
    return
  }
  indexOfKey.removeValue(forKey: object)
  objects.remove(at: index)
	for i in index..<objects.count {
    indexOfKey[objects[i]] = i
  }
}
复制代码
分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改