0

I'm creating a LinkedList class to get a better feel for the python language and its doubly linked nodes. My overall task being to not make use of python's built-in list data structure, while also trying to optimize the time efficiency of the code. What would be the best way to go about fixing what I would assume is my getitem or setitem method body.

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


### prepend and append

    def prepend(self, value):
        n = LinkedList.Node(value, prior=self.head, next=self.head.next)
        self.head.next.prior = self.head.next = n
        self.length += 1

    def append(self, value):
        n = LinkedList.Node(value, prior=self.head.prior, next=self.head)
        n.prior.next = n.next.prior = n
        self.length += 1


### subscript-based access ###

    def _normalize_idx(self, idx):
        nidx = idx
        if nidx < 0:
            nidx += len(self)
            if nidx < 0:
                nidx = 0
        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[nidx]
        if nidx >= len(self):
            raise IndexError
        currNode = 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+1, len(self)):
            self[i-1] = self[i]
        del self[len(self)-1]

Testing this code using:

    # test subscript-based access
from unittest import TestCase
import random

tc = TestCase()
data = [1, 2, 3, 4]
lst = LinkedList()
for d in data:
    lst.append(d)

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

with tc.assertRaises(IndexError):
    x = lst[100]

with tc.assertRaises(IndexError):
    lst[100] = 0

with tc.assertRaises(IndexError):
    del lst[100]

lst[1] = data[1] = 20
del data[0]
del lst[0]

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

I'd get an error saying 1 != 20. Writing these class methods always seems to trip me up, what might I be missing? I'm not exactly sure how this differs from the typical array backed list. And I'm not sure where this 20 value is coming from.

1 Answers1

1

I'd get an error saying 1 != 20

That's a true statement, though, so your problem exists in how you set the data of your list. It wasn't updated, but the Python list was.

I'm not sure where this 20 value is coming from

Umm... lst[1] = data[1] = 20, perhaps?

Anyways, I don't think your setItem function is correct. The curNode variable there is only a value, and not a Node object reference based upon the getItem method, so therefore, currNode = value is not actually updating the list, only the local variable scoped to that function.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • I guess I'm not sure on how to set the item at the specified index then. If I were to alter the code adding something like `currNode = self.head[nidx]` I'll get an error, but I'm not sure how else to identify the proper node –  Jun 11 '16 at 18:42
  • You'll have to iterate over the list of Node objects much like you've done with getItem. Then instead of `return curNode.val`, you set its value. – OneCricketeer Jun 11 '16 at 18:47