繁体   English   中英

单链接列表删除

[英]Singly-Linked List remove

我当时正在执行单链列表,并且我记得Linus Torvalds在这里谈论它。

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

像这样 在此处输入图片说明

因此,我们应该可以使用任何方式访问上一个节点。

但是莱纳斯·托瓦尔兹(Linus Torvalds)通过使用C语言中的地址概念来删除特殊情况。因此,头也具有“先前的事物”,即头的地址指向头。 因此,他使用了C的指针和地址功能来删除特殊情况。

特殊情况下的普通代码 在此处输入图片说明

特殊情况下的代码变成普通情况 在此处输入图片说明

我认为单链列表中的这种特殊情况下的删除无法在python中完成,因为我们没有指针的概念(因此,我将无法走到前面)。 我对吗 ?

当然,您可以在Python中执行此操作。 他的意思是,您具有一些数据结构,该数据结构表示列表本身并指向列表的开头,并且您在处理第一个列表项时就像在列表项中使用指针一样对其进行操作。

现在,Python不是C,因此实现会有所不同,但是原理仍然适用。 列表本身与第一个项目不是同一对象,并且列表项不应该与整个列表具有相同的方法,因此有必要为它们使用不同种类的对象。

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

当然,在现实世界中,除非作为练习,否则您永远不会编写自己的Python链表类。 内置list更加有效。

您不能在Python中使用Linus的特定技巧,因为众所周知,Python没有指针(这样)或地址运算符。 但是,您仍然可以通过为列表赋予虚拟头节点来消除列表头的特殊情况。 您可以将其作为列表设计的固有部分来执行,也可以仅通过创建一个额外的节点并将其引用为第一个数据承载节点作为下一个节点来进行。 无论哪种方式,您可能要删除的所有节点都是内部节点,而不是特殊情况。

在阅读您的问题时,我的第一个想法是:为什么要在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有引用而不是指针,它们很相似,但更安全,更易于使用。

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

您需要按照Linus的建议进行两级间接操作,但是您可能可以在Python中做到这一点,也许是通过对对象的引用来存储对象的引用或此类对象(索引的索引?)。 。 也就是说,我认为它不能如此优雅或高效地映射到Python,并且仅使用一个对象来表示链接结构中的单个链接可能会非常浪费。

在Python的情况下,我只需要执行额外的分支来检查您是否要从头部移开,除非我缺少一些技巧。

至于自己实现链表,我实际上发现了很多用例,其中标准库不足以满足需求。 这是一个例子:

在此处输入图片说明

...网格可能有10,000个单元格。 标准库提供的大多数链表都没有经过优化,无法以每个列表32位索引的大小存储10,000+个链表,因为它们试图提供允许隔离使用链表的接口(而不是使用单独的后备数据结构,以像数组一样存储)。 通常,最有效地使用链表是不拥有内存或管理任何资源的链表。 它只是以已经在另一数据结构中分配和管理的辅助方式链接数据,例如对于n元树中的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内核中那样,则您必须能够对每个节点在内存中的位置进行真正的控制,以便在大多数情况下可以遍历列表不完全是,只是遍历连续的内存块。 否则,您通常最好使用小型数组,即使这意味着线性时间删除和从中间插入/从中间插入也是如此。

暂无
暂无

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

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