class SLinkedList:
\"\"\"Singly linked list with access to front and end, and with storedsize.
\"\"\"
#-------------------------- nested _Node class--------------------------
class _Node:
__slots__ = '_element', '_next' # streamline memory usage
def __init__(self, element, next):
self._element = element
self._next = next
#------------------------------- queue methods-------------------------------
def __init__(self):
\"\"\"Create an empty list.\"\"\"
self._head = None
self._tail = None
self._size = 0
def __len__(self):
\"\"\"Return the number of elements in the list.\"\"\"
return self._size
def isEmpty(self):
\"\"\"Return True if the list is empty.\"\"\"
return self._size == 0
 Â
# READ THIS!
def __repr__(self):
plist = []
current = self._head
# This is how to traverse a list:
while current != None: # use a while-loop.
plist.append(current._element) # process the stored element.
current = current._next # jump to the next node.
return \"SLinkedList(%s)\" % repr(plist)
def first(self):
\"\"\"Return but do not remove the first element.
Raise EmptyError if the list is empty.
\"\"\"
if self.isEmpty():
raise EmptyError('The SLinkedList is empty')
return self._head._element
 Â
def deleteFirst(self):
\"\"\"Remove and return the first element.
Raise EmptyError if the list is empty.
\"\"\"
if self.isEmpty():
raise EmptyError('The SLinkedList is empty')
answer = self._head._element
self._head = self._head._next
self._size -= 1
if self.isEmpty(): # special case when list is empty
self._tail = None # removed head had been the tail
return answer
 Â
def addFirst(self, e):
\"\"\"Add element e to the front of the list.\"\"\"
self._head = self._Node(e, self._head) # create and link a newnode
if self._tail == None: # special case when list was empty
self._tail = self._head # added head is the tail
self._size += 1
 Â
def addLast(self, e):
\"\"\"Add e to the end of the list.\"\"\"
newest = self._Node(e, None) # node will be new tail node
if self.isEmpty():
self._head = newest # special case: previously empty
else:
self._tail._next = newest
self._tail = newest # update reference to tail node
self._size += 1
 Â
def last(self):
\"\"\"Return but do not remove the last element.
Raise EmptyError if the list is empty.
\"\"\"
if self.isEmpty():
raise EmptyError('The SLinkedList is empty')
return self._tail._element
 Â
def _nodeAtIndex(self, index):
\"\"\"Returns the reference to the node at the given index;
If index is out of range, raise IndexError
\"\"\"
# PROBLEM 2
# You can assume that index is non-negative.
# You need to traverse the list and stop at the requiredindex.
# YOUR CODE HERE
raise NotImplementedError()
 Â
def __getitem__(self, index):
aNode = self._nodeAtIndex(index)
return aNode._element
 Â
def __setitem__(self, index, value):
# PROBLEM 3
# YOUR CODE HERE
raise NotImplementedError()
 Â
def deleteLast(self):
\"\"\"Remove and return the last element. Runs in O(n) time.
Raise EmptyError if the list is empty.
\"\"\"
# PROBLEM 4
# Your code should handle three cases:
# a list of size 0, size 1 and size >=2.
# If the list is of size >= 2
# you need to traverse the list and stop at the second lastnode;
# that node contains a reference to the last node;
# this reference needs to be copied/assigned to self._tail
# YOUR CODE HERE
 Â