Data structures 对象类索引的数据结构

Data structures 对象类索引的数据结构,data-structures,language-agnostic,Data Structures,Language Agnostic,我希望能够保持对象的集合,并根据对象的类型对其进行查找,其中类型可以是层次结构的,就像多重继承OO系统中的类一样 现在,我只需保留一个对象列表,然后循环遍历,查询每个对象,看看它是否属于请求的类型,类似于这样,在类似Python的伪代码中: def hastype(对象,类型): 对于对象中的obj: 如果存在(对象,类型): 返回obj 一无所获 通常这对我来说并不是一个特别的问题,但是在有些情况下,能够更有效地进行这些查找会很好 如前所述,我的类型与多重继承系统中的类非常相似;每个类型声明

我希望能够保持对象的集合,并根据对象的类型对其进行查找,其中类型可以是层次结构的,就像多重继承OO系统中的类一样

现在,我只需保留一个对象列表,然后循环遍历,查询每个对象,看看它是否属于请求的类型,类似于这样,在类似Python的伪代码中:

def hastype(对象,类型):
对于对象中的obj:
如果存在(对象,类型):
返回obj
一无所获
通常这对我来说并不是一个特别的问题,但是在有些情况下,能够更有效地进行这些查找会很好

如前所述,我的类型与多重继承系统中的类非常相似;每个类型声明任意数量的直接超类型,并提供这些类型中直接和间接超类型的完整列表。有一个类型root。我可以轻松地查询类型的超类型的完整列表。我还拥有系统中所有已知类型的全局知识,每个类型都有一个整数ID,如果有帮助的话,这些ID是连续分配的

我关心的主要特性是无论集合中有多少个对象都可以快速查找(不需要是O(1),但最好是比O(n)更好的),但我也非常关心有效的插入和删除(最好不管集合中有多少个对象,也不管对象类型中有多少个超类型,但我愿意相信这些标准可能是相互排斥的),以及使用的内存量

我已经搜索了一些已经发明的此类数据结构,但没有找到任何;我也没有想到任何适合我上述需求的数据结构(例如,给定连续的类型ID,使用O(1)可以轻松地创建从类型到对象的直接查找表)查找,但这会占用太多内存)


有人知道或能想到这种数据结构吗?

好的,我来试试。如果你担心内存限制,那么它可能不是你想要的

下面是一些ruby-ish代码:

# hash of all objects by type
#
# heirarchy:
#
#   animal
#     amphibian
#     mammal
#       hominid
#
objects_by_type = {
  animal: [:snake, :fish]
  amphibian: [:frog, :newt]
  mammal: [:whale, :rabbit]
  hominid: [:gorilla, :chimpanzee]
}

# print all objects that are of type `search_type`, or a subtype of `search_type`
def print_objects_of_type(search_type)
  #get a list of all valid types
  all_types = [search_type] + search_type.subtypes

  #print all objects belonging to a type in all_types
  all_types.each do |t|
    objects_by_type[t].each do |obj|
      print obj.to_s + ' '
    end
  end

  print "\n"
end

print_objects_of_type(:animal)
# snake fish frog newt whale rabbit gorilla chimpanzee human

print_objects_of_type(:mammal)
# whale rabbit gorilla chimpanzee human

print_objects_of_type(:amphibian)
# frog newt
这一切都取决于一个散列,其中键是一个类型,值是一个对象列表

搜索给定类型的对象要比O(n)好,因为您直接转到正确的对象,而不测试不正确的对象。哈希查找将是O(1),其余取决于您获取给定类型的子类型列表的速度

对于插入和删除,只要对象列表是链表,就应该能够实现O(1)。插入和删除将需要一次哈希表查找(O(1))和一次链表插入/删除(也是O(1))

现在,唯一的问题是这种方法需要的内存量。类型的数目影响哈希表内存使用,并且对象的数量影响链表内存使用。您可以用相邻的内存替换链表(例如C++ STD::vector)。,这可以消除每个对象的开销,但插入/删除将不再是O(1)。您只需计算每个类型和每个对象的开销,将其乘以预期的类型和对象数,然后从中做出决定


我能想到的所有解决方案都需要一个哈希表,因此如果哈希表有太多的内存开销,那么我就没有主意了。

汤姆·达林的方法在内存开销方面非常接近最优。然而,正如前面提到的,有一些算法可以用这些开销换取更快的超类型,并计算一个类型的直接/间接超类型的数量has.下面是一些这样做的算法,由您来决定是否值得权衡。最后,两种算法的性能在很大程度上取决于类型图(子类型和超类型之间的连接)的外观。如果类型图是相当空闲的或其他有利的(与性能相关的变量更接近性能界限的下限),那么以下算法的平均(摊销)性能可以使它们值得使用

绩效相关变量:

  • N是类型数
  • D是平均深度(子类型向下延伸的距离)。边界O(1)到O(N)
  • M是编号最高的ID的值,该ID是给定类型的子类型。边界为O(1)到O(N)
  • k是一个类型具有的直接超类型的数目。界为O(1)到O(N)
  • K是一个类型具有的唯一超类型总数的平均数。界为O(1)到O(N)
  • L是一个类型具有的唯一子类型总数的平均数。边界为O(1)到O(N)
  • E是子类型超类型连接的数量。边界为O(N)到O(N^2)
算法:

  • O(1)超类型查找,具有O(N*D)额外空间开销。其思想是让每个类型保持一个(动态)它的所有超类型的布尔数组。超类型数组的大小将等于最大超类型ID号。该数组将通过复制每个内置超类型的超类型数组,然后为继承的超类型本身添加每个ID来构建。Pythonic检查类型是否有超类型将是他这样说:

    return len(supertype_array) > supertype_id and supertype_array[supertype_id] is True
    
    添加子类型等于在每个直接超类型的“超类型”列表上执行集合并集,即O(k*N)

  • 另一种方法是,如果E相对接近N,而其他地方的成本稍高,则可提供优于#1的空间性能在这里添加子类型相当于在每个直接超类型的超类型列表上进行集合并集,但最终在每个超类型列表的元素总和中是线性的。其思想是在占用空间小于布尔数组时使用一组ID。如果ID号为