从内存位置的哈希查找中删除列表中的项目?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从内存位置的哈希查找中删除列表中的项目?相关的知识,希望对你有一定的参考价值。
我有对象,每个对象都有一个唯一的ID,这些对象被插入到各种列表中。这些对象需要经常从其相应列表的中间删除,这通常是O(n)
,因此我想将它们的位置保持在dict
中,并在每次我想要删除它时在O(1)
中检索对象的位置。
class Node(object):
def __init__(self, lst_id, unique_id):
self.lst_id = lst_id
self.unique_id = unique_id
n1 = Node('a', 1)
n2 = Node('a', 2)
n3 = Node('b', 3)
node_lsts = {}
for node in [n1,n2,n3]:
if node.lst_id in node_lsts:
node_lsts[node.lst_id].append(node)
else:
node_lsts[node.lst_id] = [node]
nodes_hash = {n1.unique_id: n1, n2.unique_id: n2, n3.unique_id: n3}
ID_TO_REMOVE = 1
在上面的例子中,如果我简单地调用del nodes_hash[ID_TO_REMOVE]
,node_lsts
中的相应对象仍然保留,即使它已从字典中删除 - 我应该如何从O(1)
中的相应列表中删除它?
在C ++中,我可以保留指向列出邻居的指针作为节点成员变量(链表)并通过其内存地址查找节点,获取指向其邻居的指针,取消该节点与其邻居的链接(从而将其从“列表”中删除)最后释放节点。我试图复制这种行为。
您可以在Python中轻松创建双向链表:
class DoublyLinkedListNode(object):
def __init__(self, unique_id, lst_id, left=None, right=None):
self.unique_id, self.lst_id = unique_id, lst_id
self.left = left
self.right = right
def remove(self):
if self.left is not None:
self.left.right = self.right
if self.right is not None:
self.right.left = self.left
self.left = None
self.right = None
def append(self, node):
node.left = self
node.right = self.right
if self.right is not None:
self.right.left = node
node.right = self.right
self.right = node
def prepend(self, node):
node.left = self.left
node.right = self
if self.left is not None:
self.left.right = node
self.left = node
def iter_left(self):
current = self
while current.left is not None:
yield current.left
current = current.left
def iter_right(self):
current = self
while current.right is not None:
yield current.right
current = current.right
作为链表,对任何给定节点都有O(1)插入和删除。如果您可以通过字典或其他一些更适合的数据结构保留对每个节点的引用,这将允许您平均情况O(1)访问和快速顺序迭代。
class ListContainer(object):
def __init__(self):
self.lists = {}
self.node_mapping = {}
def append(self, node):
if node.lst_id in self.lists:
self.lists[node.lst_id].append(node)
else:
self.lists[node.lst_id] = node
self.node_mapping[node.unique_id] = node
def remove(self, node):
...
请注意,如果您的列表中只有几百个元素,那么这都是浪费精力。对于如此少的元素,纯Python数据结构可能不会比Python实现的列表数据结构更快。 Big-O表示法忽略了常数项,如果你没有处理足够的元素(例如Coppersmith-Winograd algorithm),它可能会非常大。
您可以使用嵌套在dict中的dict,而不是使用嵌套在dict中的列表:
node[node.lst_id] = {node1.unique_id: node1, node2.unique_id: node2, ... }
假设ID_TO_REMOVE
是unique_id
你可以删除它:
node_to_remove = nodes_hash[ID_TO_REMOVE]
del node_lsts[node_to_remove.lst_id][node_to_remove.unique_id]
完整代码:
class Node(object):
def __init__(self, lst_id, unique_id):
self.lst_id = lst_id
self.unique_id = unique_id
def __repr__(self):
return "[lst_id: {}, unique_id: {}]".format(self.lst_id, self.unique_id)
n1 = Node('a', 1)
n2 = Node('a', 2)
n3 = Node('b', 3)
node_lsts = {}
for node in [n1,n2,n3]:
if not node.lst_id in node_lsts:
node_lsts[node.lst_id] = {}
node_lsts[node.lst_id][node.unique_id] = node
nodes_hash = {n1.unique_id: n1, n2.unique_id: n2, n3.unique_id: n3}
ID_TO_REMOVE = 1
print("node_lsts", node_lsts)
node_to_remove = nodes_hash[ID_TO_REMOVE]
print("node_to_remove", node_to_remove)
del node_lsts[node_to_remove.lst_id][node_to_remove.unique_id]
print("node_lsts", node_lsts)
OUTPUT
node_lsts {'a': {1: [lst_id: a, unique_id: 1], 2: [lst_id: a, unique_id: 2]}, 'b': {3: [lst_id: b, unique_id: 3]}}
node_to_remove [lst_id: a, unique_id: 1]
node_lsts {'a': {2: [lst_id: a, unique_id: 2]}, 'b': {3: [lst_id: b, unique_id: 3]}}
由于我们现在使用字典,所以一切都在O(1)中完成,我们避免了当我们尝试从列表中删除元素时出现的性能问题。
以上是关于从内存位置的哈希查找中删除列表中的项目?的主要内容,如果未能解决你的问题,请参考以下文章