繁体   English   中英

不使用任何库也不使用 hash 表编写稀疏数组的最佳方式

[英]Most optimal way of writing sparse array not using any libraries nor hash table

给定一个大数组,其中绝大多数元素为零。 创建一个 class 可以更有效地存储这些元素的空间。 你的class必须有以下方法:

  • constructor(originalArr) - 你传入原始数组来存储
  • set(i, val) - 在索引 i 处设置值 val
  • get(i) - 获取索引 i 处的值

想出一个不使用字典/hash 表的数据结构。

 EXAMPLE(S) sparseArr = new SparseArray([0, 0, 1, 0, 0, 0, 0, 2]) sparseArr.get(0) // returns 0 sparseArr.set(0, 3) sparseArr.get(0) // returns 3 sparseArr.get(2) // returns 1 FUNCTION SIGNATURE class SparseArray: constructor(original) set(i, val) get(i)

我正在考虑拥有三个 arrays、non_zero_arr、non_zero_indices_arr 和 zero_indices_arr 但是当我想到将零值设置为非零的情况时,我会在 zero_indices_arr 中使用二进制搜索来查找给定索引是否存在于 zero_indices_arr 中,删除数组中的索引(使用数组切片?)再次通过二进制搜索在non_zero_indices_arr中找到position,然后使用数组切片添加放置新的更新索引并使用其在non_zero_indices_arr中的索引通过使用数组更新其在non_zero_arr中的non_zero_value再次切片。

我想每个操作的时间复杂度是

构造函数的 O(n) [用于在适当命名的数组中记录索引、零和非零]

O(log n) for get [用于非零或零索引数组中的二进制搜索索引]

O(log n + n) [搜索然后切片数组并可能添加更新值]

但对我来说,这感觉有点混乱或坚韧不拔。 有没有更优化更清洁的方法来做到这一点? 鉴于这是一个面试问题? 请随时纠正我的思路或提出您的最佳解决方案和时间复杂度。

先感谢您

有很多数据结构可以处理这些需求,包括:

另一个是按位 trie

这是一个准系统按位 trie 实现,其中每个节点只处理给定索引的一位,因此它是一棵二叉树 树的高度将等于数据结构必须为其存储值的最大索引的二进制表示中的位数。

class SparseArray:
    def __init__(self, original=None):
        self.height = self.tree = 0
        if original:
            for i, val in enumerate(original):
                if val:
                    self.set(i, val)
    
    def remove(self, i):
        def recur(node, shift, i):
            j = (i >> shift) & 1
            node[j] = shift and recur(node[j], shift - 1, i & ((1 << shift) - 1))
            return node if any(node) else 0
        
        if i.bit_length() <= self.height:
            self.tree = recur(self.tree, self.height - 1, i)
            # Reduce height if possible
            if self.tree != 0:
                while self.height > 1 and self.tree[1] == 0:
                    self.height -= 1
                    self.tree = self.tree[0]
            else:
                self.height = 0
                
    def set(self, i, val):
        if val == 0:  # We don't store zeroes...
            return self.remove(i)
        # Increase tree height if this index needs more bits
        width = i.bit_length()
        if self.height < width and self.tree != 0:
            for _ in range(self.height, width):
                self.tree = [self.tree, 0]
        self.height = max(width, self.height)
        # Drill down
        if not self.tree:
            self.tree = [0]*2
        node = self.tree
        for bit in range(self.height - 1, 0, -1):
            side = (i >> bit) & 1
            if node[side] == 0:
                node[side] = [0]*2
            node = node[side]
        node[i & 1] = val  # Set leaf's value
                
    def get(self, i):
        node = self.tree
        if i.bit_length() > self.height:  # Out of current range
            return 0
        node = self.tree
        for bit in range(self.height - 1, 0, -1):
            side = (i >> bit) & 1
            node = node[side]
            if node == 0:  # No subtree here
                return 0
        return node[i & 1]  # Get leaf's value

    def items(self):
        def recur(node, i):
            if isinstance(node, list):
                yield from recur(node[0], i*2)
                yield from recur(node[1], i*2+1)
            elif node != 0:
                yield i, node
            
        yield from recur(self.tree, 0)

最坏情况下的空间复杂度为 O(),其中 是存储在稀疏数组中的非零值的个数, 是用于非零值的最大索引的二进制表示中的位数。 最坏情况的一个例子是所有索引都是 2 的连续幂。

最好的情况空间复杂度是 O()。 这是二叉树完美的时候,这意味着数组中没有间隙(它不是稀疏的)。

getset的时间复杂度是O()。

改进

当节点获得更大的分支因子(而不是 2)并因此处理更大的位块而不是 1 时,性能将会提高。比如 4 位。

存在几种改进 memory 和速度的变体。 请参阅 bitmap 的按位树,包括 CTPOP 位破解实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM