在链表中实现`__remove__`

时间:2016-06-12 19:20:08

标签: python linked-list

创建双向链表类,我遇到了从列表中删除值的问题。我不确定如何修复__remove__方法以使此代码正常工作。是否存在由于我的哨兵节点而未更新的循环?我尝试将其与我的__delitem__身体相似,或者我应该尝试调用此方法?下面是我的课程代码。

class LinkedList:
    class Node:
        def __init__(self, val, prior=None, next=None):
            self.val = val
            self.prior = prior
            self.next  = next

    def __init__(self):
        self.head = LinkedList.Node(None) # sentinel node (never to be removed)
        self.head.prior = self.head.next = self.head # set up "circular" topology
        self.length = 0


    ### subscript-based access ###

    def _normalize_idx(self, idx):
        nidx = idx
        if nidx < 0:
            nidx += len(self)
            if nidx < -1:
                raise IndexError  
        return nidx

    def __getitem__(self, idx):
        """Implements `x = self[idx]`"""
        nidx = self._normalize_idx(idx)
        currNode = self.head.next
        for i in range(nidx):
            currNode = currNode.next
        if nidx >= len(self):
            raise IndexError
        return currNode.val


    def __setitem__(self, idx, value):
        """Implements `self[idx] = x`"""
        nidx = self._normalize_idx(idx)
        currNode = self.head.next
        if nidx >= len(self):
            raise IndexError
        for i in range(nidx):
            currNode = currNode.next
        currNode.val = value

    def __delitem__(self, idx):
        """Implements `del self[idx]`"""
        nidx = self._normalize_idx(idx)
        currNode = self.head.next
        if nidx >= len(self):
            raise IndexError
        for i in range(nidx):
            currNode = currNode.next
        currNode.prior.next = currNode.next #unlink currNode from its neighbors
        currNode.next.prior = currNode.prior
        self.length -= 1 #the del item has to decrease the size by 1 because of sentinel node


    ### single-element manipulation ###

    def insert(self, idx, value):
        """Inserts value at position idx, shifting the original elements down the
        list, as needed. Note that inserting a value at len(self) --- equivalent
        to appending the value --- is permitted. Raises IndexError if idx is invalid."""
        nidx = self._normalize_idx(idx)
        currNode = self.head.next
        for i in range(nidx):
            currNode = currNode.next
        newNode = LinkedList.Node(value, currNode.prior, currNode)
        newNode.prior.next = newNode
        currNode.prior = newNode
        self.length += 1

    def remove(self, value):
        """Removes the first (closest to the front) instance of value from the
        list. Raises a ValueError if value is not found in the list."""
        nidx = self._normalize_idx(0)
        currNode = self.head.next
        for i in range(nidx):
            currNode = currNode.next
            if currNode.val != value:
                raise ValueError
            elif currNode.val == value:
                currNode.prior.next = currNode.next
                currNode.next.prior = currNode.prior
                self.length -= 1

    def __len__(self):
        """Implements `len(self)`"""
        return self.length

使用以下代码测试此类,我收到一条错误,说明789! = 653.调试器指向测试用例代码tc.assertEqual(data[i], lst[i])中的一行,复制的数据似乎是迭代的:

# test single-element manipulation
from unittest import TestCase
import random

tc = TestCase()
lst = LinkedList()
data = []

for _ in range(100):
    to_ins = random.randrange(1000)
    ins_idx = random.randrange(len(data)+1)
    data.insert(ins_idx, to_ins)
    lst.insert(ins_idx, to_ins)

for _ in range(25):
    to_rem = data[random.randrange(len(data))]
    data.remove(to_rem)
    lst.remove(to_rem)

for i in range(25):
    tc.assertEqual(data[i], lst[i])

with tc.assertRaises(ValueError):
    lst.remove(9999)

1 个答案:

答案 0 :(得分:0)

您的问题是,for循环永远不会运行,因为nidx为零且range(0)为空。您不需要此功能中的任何索引。只需使用一个while循环,当你到达列表末尾时,就不会让你四处走动:

def remove(self, value):
    """Removes the first (closest to the front) instance of value from the
    list. Raises a ValueError if value is not found in the list."""
    currNode = self.head.next
    while currNode != self.head:
        if currNode.val == value:
            currNode.prior.next = currNode.next
            currNode.next.prior = currNode.prior
            self.length -= 1
            return
        currNode = currNode.next
    raise ValueError("Value not found")