【问题标题】:Why can't you build a xor linked list in python 3?为什么不能在 python 3 中构建异或链表?
【发布时间】:2020-08-09 23:51:59
【问题描述】:

我想在 python 中实现一个异或链表,我搜索它以尝试更好地理解它,但我发现的唯一与 python 相关的是这个 stackoverflow 帖子How to implement an XOR Linked List in Python?,它说不可能实现一个异或链接python中的列表。它在那里说你不能弄乱位和指针。我认为我们实际上可以“搞乱位”,使用按位运算符(对于 xor 我们会有 ^ ),指针是什么意思?我们可以创建一个带有指针属性的节点类,就像我们在单链表中所做的那样:

class Node(object):
    def __init__(self, data):
        self.data = data
        self.next = None

那将是我们的带有“指针”的节点 -> .next。 那么问题来了,为什么我们不能在 python 中实现 XOR 链表?如果可以,怎么做?

【问题讨论】:

  • 你可能会弄乱 id() 的结果。看到这个答案:stackoverflow.com/a/24815841/4834
  • 我在其中一个答案中的实现使用 id() 来获取引用并使用解决方法来取消引用。

标签: python algorithm bit-manipulation xor-linkedlist


【解决方案1】:

异或链表存储两个地址的异或以节省存储空间。 这在直接操作内存地址的低级语言中很有用。在 Python 中没有这么多,因为在 Python 中你不是直接处理内存。

Python 名称(变量)是对由 Python 运行时管理的对象的引用。 但是那个引用不是内存地址。

在 CPython 中,您可以或多或少使用id() 函数获取对象的地址,但这是 CPython 的实现细节,而不是属性的语言。 此外,Python 对象比您想象的要大得多。在类 C 语言中,整数通常为 4 个字节。

Python 为“高效的数值数组”提供了array。让我们创建一个 4 字节整数数组;

In [5]: import array

In [6]: a = array.array('l', range(10))
Out[6]: array('l', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

我们来看看数组中第一项和第二项的地址有什么区别:

In [7]: id(a[1]) - id(a[0])
Out[7]: 32

所以在我的机器上,一个 4 字节整数的大小作为一个 CPython 对象实际上是 32 个字节。 这基本上是因为 Python 运行时必须在幕后做很多工作来为您管理内存。

【讨论】:

    【解决方案2】:

    我可以成功实现一个异或链表。请注意,为了设置Node 的邻居,您必须通过两个邻居。如果不这样做,则无法使用 XOR 运算 (address_store = prev_address ^ curr_address) 计算地址。

    get_by_address(address) 函数将在运行时为您提供一个具有给定id 的对象,Node.get_address(node) 将为您提供Nodeid。显然,可以在 Python 中取消引用一个对象并获得它的引用!

    def get_by_address(address, global_vars):
        if address == 0:
            return None
    
        return [x for x in global_vars.values() if id(x) == address][0]
    
    class Node(object):
        def __init__(self, data):
            self.data = data
            self.address_store = None
    
        def get_address(self):
            return id(self)
    
        def set_neighbors(self, prev_node=None, next_node=None):
            local_address = self.get_address()
    
            if prev_node == None:
                prev_address = 0
            else:
                prev_address = prev_node.get_address()
    
            if next_node == None:
                next_address = 0
            else:
                next_address = next_node.get_address()
    
            self.address_store = prev_address ^ next_address
    
        def get_next(self, prev_node, global_vars):
            if self.address_store == None:
                raise Exception('set_neighbors not called yet, no next node!')
    
            if prev_node == None:
                prev_address = 0
            else:
                prev_address = prev_node.get_address()
    
            next_address = self.address_store ^ prev_address
    
            return get_by_address(address=next_address, global_vars=global_vars)
    
        def get_prev(self, next_node, global_vars):
            if self.address_store == None:
                raise Exception('set_neighbors not called yet, no next node!')
    
            if next_node == None:
                next_address = 0
            else:
                next_address = next_node.get_address()
    
            prev_address = self.address_store ^ next_address
    
            return get_by_address(prev_address, global_vars=global_vars)
    
    node1 = Node(data=1)
    node2 = Node(data=2)
    node3 = Node(data=3)
    
    node1.set_neighbors(prev_node=None, next_node=node2)
    node2.set_neighbors(prev_node=node1, next_node=node3)
    node3.set_neighbors(prev_node=node2, next_node=None)
    
    curr_node = node1
    prev_node = None
    
    print('Traversing forwards:')
    
    print(str(None), '<->', end=' ')
    
    while curr_node != None:
        print(curr_node.data, '<->', end=' '),
    
        prev_node_temp = curr_node
        curr_node = curr_node.get_next(prev_node=prev_node, global_vars=globals())
        prev_node = prev_node_temp
    
    print(str(None))
    
    curr_node = node3
    prev_node = None
    
    print('Traversing backwards:')
    
    print(str(None), '<->', end=' ')
    
    while curr_node != None:
        print(curr_node.data, '<->', end=' '),
    
        prev_node_temp = curr_node
        curr_node = curr_node.get_next(prev_node=prev_node, global_vars=globals())
        prev_node = prev_node_temp
    
    print(str(None))
    

    输出:

    Traversing forwards:
    None <-> 1 <-> 2 <-> 3 <-> None
    Traversing backwards:
    None <-> 3 <-> 2 <-> 1 <-> None
    

    【讨论】:

      猜你喜欢
      • 2017-09-19
      • 1970-01-01
      • 1970-01-01
      • 2021-05-06
      • 1970-01-01
      • 1970-01-01
      • 2020-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多