单链接列表删除

问题描述 投票:1回答:4

我正在做单链接列表实现,我记得Linus Torvalds谈论它here

在单链表中,为了删除节点,我们应该访问前一个节点,然后更改它当前指向的节点。

喜欢这个enter image description here

所以我们应该有权访问上一个节点。

但是Linus Torvalds通过使用C语言中的地址概念删除了特殊情况。因此,头部也有“前一个东西”,即指向头部的头部地址。所以他使用C的指针和地址功能来删除特例。

正常的代码与特殊情况enter image description here

具有特殊情况的代码成为正常情况enter image description here

我认为单链表中的这种特殊情况删除不能在python中完成,因为我们没有指针的概念(因此我不能在头之前走一步)?我对吗 ?

python c linked-list singly-linked-list
4个回答
2
投票

当然你可以用Python做到这一点。他说的是你有一些数据结构代表列表本身并指向列表的头部,你操作它就像处理第一个列表项时列表项中的指针一样。

现在Python不是C所以实现会有所不同,但原则适用。列表本身与第一个项目不是同一个对象,列表项目不应该与列表整体具有相同的方法,因此对它们使用不同类型的对象是有意义的。

但是,它们都可以使用同名属性(例如next)指向下一个项目。因此,当您遍历列表,并且您位于第一个项目时,“上一个”项目就是列表本身,如果您需要删除第一个项目,则您正在操纵其next属性。

当然,在现实世界中,除了作为练习外,你永远不会编写自己的Python链表列表。内置的list效率更高。


1
投票

你不能在Python中使用Linus的特定技巧,因为,众所周知,Python没有指针(如此)或地址操作符。但是,您仍然可以通过为列表提供虚拟头节点来消除列表头的特殊情况。您可以将其作为列表设计的固有部分,或者只需创建一个额外的节点并将其作为下一个节点引用第一个数据承载节点即可实现。无论哪种方式,您可能要删除的所有节点都是内部节点,而不是特殊情况。


1
投票

我在阅读你的问题时的第一个想法是:你为什么要在python中建立一个单链表? Python提供了丰富的集合类型,您可以使用它们而不必担心它们是作为单链表实现,还是作为双链表实现,还是作为一些非递归数据结构(通常更容易处理)。

但是你的问题的答案是:Python当然可以建立一个单链表。例如,以下代码就是这样做的:

class Node:
    def __init__(self, x, next):
        self.x = x
        self.next = next

    def __str__(self):
        return "<{}, {!s}>".format(self.x, self.next)

n = Node(1, None)
n = Node(2, n)
n = Node(3, n)
print(n)  # output: <3, <2, <1, None>>>

n.next.next = n.next.next.next
print(n)  # output: <3, <2, None>>

与C的区别在于:我们没有malloc()或使用指针,因为python为我们处理内存。 Python有引用而不是指针,它们相似但更安全,更易于使用。

但是,在实现链接列表之前,您应该考虑您对集合的要求,也许您可​​以从内置插件或集合模块中选择一个好的。


0
投票

你需要两个级别的间接来做Linus建议的方式,但是你可以通过引用一个存储对象或类似东西(索引的索引?)的对象来创建它。 。也就是说,我不认为它如此优雅或有效地映射到Python,并且使用一个对象来表示链接结构中的单个链接可能非常浪费。

在Python的情况下,我只是进行额外的分支来检查你从头部移除的情况,除非有一些我不知道的技巧。

至于自己实现链表,我实际上发现许多标准库不够的用例。这是一个例子:

enter image description here

...网格可能有10,000个单元格。标准库提供的大多数链接列表未经过优化,无法以每个列表32位索引的大小存储10,000多个链接列表,因为它们试图提供允许链接列表单独使用的接口(不使用单独的后备数据结构,用于存储,如数组)。通常,链表的最有效使用是不拥有内存或管理任何资源的链表。它只是以已经在另一个数据结构中分配和管理的辅助方式链接数据,对于n-ary树中的128位(16字节)树节点,其中元素可以存储在层次结构的任何级别:

struct TreeNode
{
     int32 parent;       // parent index or -1 for no parent
     int32 first_child;  // first child of this node or -1
     int32 next_sibling; // next child for the parent node or -1
     int32 element;      // element data stored in this node or -1
                         // if no data is associated
};

因此,有很多用例来实现自己的链表和其他链接结构,这些结构对于更狭隘的用例(网格数据结构,八叉树,四叉树,图形等)来说效率更高,但同样,我不要认为你可以在不容易使用两个或更多级指针间接的语言中使用这个技巧。 Python本身只有一个用于对象 - 与Java和C#相同。您需要类似“对对象的引用的引用”或“对象的索引的索引”或“对象的对象引用的索引”之类的东西。

链接列表通常在不允许您管理所有内容存储在内存中的语言中也不是那么有用,因为您最终可能会通过链接列表获得缓存未命中,否则如果每个列表节点在内存中都是碎片化的是GC循环后的情况,例如对于链接列表来说非常有效,就像Linux内核的情况一样,要求您能够真正控制每个节点驻留在内存中的位置,这样列表遍历实际上大部分(如果不是完全的话)只是迭代通过连续的块来实现。记忆。否则你通常会更好地使用小数组,即使这意味着线性时间删除和插入/从中间插入。

© www.soinside.com 2019 - 2024. All rights reserved.