【问题标题】:Algorithm to delete a node from the middle从中间删除一个节点的算法
【发布时间】:2023-04-06 12:34:01
【问题描述】:

我正在阅读《Cracking the Coding Interview》和做练习题,但我被困在这个问题上:

“实现一个算法来删除中间的节点(即除第一个和最后一个节点之外的任何节点,不一定是确切的中间)或单链表,只允许访问该节点。

示例 输入:链表中的节点 a->b->c->d->e->f 结果:什么都没有返回,但是新的链表看起来像 a->b->d->e->f"

这是我的代码:

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

    def __str__(self):
        return str(self.data)


class LinkedList():
    def __init__(self, head = None):
        self.head = head

    def insert(self, data):
        new_node = Node(data)
        new_node.nextnode = self.head
        self.head = new_node

    def remove(self, data):
        current = self.head
        absent = True
        if current == None: print('List is empty')
        if current.data == data:
            self.head = current.nextnode
            absent = False
        while current.nextnode:
            if current.nextnode.data == data:
                absent = False
                if current.nextnode.nextnode:
                    current.nextnode = current.nextnode.nextnode
                else: current.nextnode = None
            else: current = current.nextnode
        if absent: print('Element not in list')

    def size(self):
        current = self.head
        size = 0
        while current:
            current = current.nextnode
            size += 1
        return size

    def find(self, data):
        current = self.head
        if current == None: print('List is empty')
        search = True
        while current and search:
            if current.data == data:
                print(current)
                search = False
            current = current.nextnode
        if search: print('Not found')

def print_list(self):
    current = self.head
    while current:
        print(current, end = ' ')
        current = current.nextnode
    print('')    


node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node1.nextnode = node2
node2.nextnode = node3
node3.nextnode = node4
list1 = LinkedList(node1)
list1.insert(2 ****EDITED node2 to 2 here****)
print_list(list1)

def delmid(ll, n):
    current = ll.head
    if current == n:
        print('Can\'t delete first node')
        return
    while current.nextnode:
        if current.nextnode == n:
            if current.nextnode.nextnode:
                current.nextnode = current.nextnode.nextnode
                return
            else:
                print('Can\'t delete last node')
                return

delmid(list1, node2)
print_list(list1)

我不明白为什么它似乎不认为 ll.head 和 node2 是相同的......如果我去掉 list1.insert(node2) 这条线,它确实有效......

我不明白...

编辑:在阅读了书中解决方案的第一句话之后,显然我还是做错了......“只允许访问该节点”意味着你不知道列表的头部......返回到绘图板...

【问题讨论】:

    标签: python algorithm linked-list nodes


    【解决方案1】:

    因为你的插入方法不对:

    def insert(self, data):
        new_node = Node(data)
        new_node.nextnode = self.head
        self.head = new_node
    

    您的方法不会将node2 本身插入 作为节点:它会创建一个新节点,并将node2 作为有效负载(数据)。那是不同的东西。

    你可以定义一个方法:

    def insert_node(self, node):
        node.nextnode = self.head
        self.head = new_node
    

    尽管如此,这将创建一个循环,因为现在node1 将指向node2 和node2tonode1`。所以生成的链表将是一个包含两个元素的圆角列表,例如:

    node1  -->  node2
      ^---------/
    

    编辑:因为你解决了那个问题。你的delmid方法也有问题。

    主要问题是在您的while 循环中您需要遍历链表,而您不这样做:当前始终保持不变,所以:

    def delmid(ll, n):
        current = ll.head
        if current == n:
            print('Can\'t delete first node')
            return
        while current.nextnode:
            if current.nextnode == n:
                if current.nextnode.nextnode:
                    current.nextnode = current.nextnode.nextnode
                    return
                else:
                    print('Can\'t delete last node')
                    return
            current = current.nextnode

    应该解决这个问题。

    【讨论】:

    • 哦,对不起,我的初始代码有 list1.insert(2) 而不是 list1.insert(node2),但它仍然无法正常工作,所以我正在更改它以查看可能是在插入 "2 " 即使它现在是链表的一部分,它仍然不被视为节点
    • @Raksha:你delmid 的问题是你没有遍历链表。
    • ooooooooooh,我在输入问题时遇到了问题......我想说“所以忽略 delmid 函数,list1.insert(2) 不会导致list1.head == node2`? "这将取决于list1.head.nextnode 是什么,不是吗.....因为node2.nextnode = node3,所以除了3之外的任何东西都会使它们不相等
    • @Raksha: no insert(2) 将创建一个 新节点,它也恰好具有 值 2,但因此有两个不同的节点现在价值2。
    • 但是值2且nextnode = node3的节点不是和node2一样吗?
    【解决方案2】:

    插入操作

    您误解了自己的insert-implementation。 list1.insert(node2) 插入一个带有node2 的新节点作为content:

    def insert(self, data):
        new_node = Node(data)    #  <== wrap node2 into another node instance
        new_node.nextnode = self.head
        self.head = new_node
    

    节点比较

    ==-operator 在内部通过调用方法__eq__(self, other) 工作。在您的情况下,您没有为此方法提供和实现,因此默认值用于按所有变量进行比较,其中包括nextnode。因此,如果两个节点完全相同,则它们只能相等。要更正此问题,请使用Node 中的自定义比较方法:

        def __eq__(self, other):
            return type(other) is Node && other.data == self.data
    

    此__eq__ 方法将首先检查other 肯定是Node 类型,然后通过存储在每个实例中的data 进行比较。

    德尔米德

    比实际问题更进一步:

    while current.nextnode:
        if current.nextnode == n:
            if current.nextnode.nextnode:
                current.nextnode = current.nextnode.nextnode
                return
            else:
                print('Can\'t delete last node')
                return
    

    此循环将无限运行,除非列表的大小最多为 1。通过 current = current.nextnode 修复此步骤通过列表。

    改善 Delmid

    此任务的实际目的是让您习惯另一种操作链表的方式:交换。

    您可以检查n 既不是第一个也不是最后一个节点,而不是在整个列表中搜索n 的前任,将值替换为其连续节点的值并删除连续节点:

    def delmid(ll, n):
        if ll.head == n:
            print('Can\'t delete first node')
            return
        if n.nextnode is None:
            print('Can\'t delete last node')
            return
    
        # swap values
        tmp = n.data
        n.data = n.nextnode.data
        n.nextnode.data = tmp
    
        # remove node
        n.nextnode = n.nextnode.nextnode
    

    【讨论】:

    • 对不起,我现在让每个人都感到困惑,包括我自己 %\ ...我的初始代码有 list1.insert(2) 而不是 list1.insert(node2),但它仍然不是工作,所以我正在更改它以查看是否可能在插入“2”之后它仍然不被视为节点,即使它现在是链表的一部分。是的,该功能目前在几个地方都被破坏了,我只是想一次解决一个问题
    • @Raksha 我刚刚在测试期间注意到了这一点。我将添加有关如何解决该问题的说明。
    • 我想我刚刚回答了我自己的问题....list1.head == node2 仅在第二个节点与node2.nextnode = node3 相同的列表中...让我快速测试...
    • @Raksha 差不多,是的。已经在我的回答中指出了这一点,包括解决方案
    • 是的,我总是忘记输入current = current.nextnode >.
    猜你喜欢
    • 2012-09-18
    • 1970-01-01
    • 1970-01-01
    • 2014-04-27
    • 2015-02-26
    • 2011-06-06
    • 2017-03-04
    • 2014-12-14
    相关资源
    最近更新 更多