class Link:
def __init__(self, value):
self.val = value
self.next = None
def __repr__(self):
return f"{self.val} "
def __str__(self):
return self.__repr__()
# TODO : Implement Non-recursive solutions and string representations in recursive solutions.
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
self.length = 0
def __str__(self):
curr = self.head
linklist = ""
while curr:
linklist += str(curr) + ' '
curr = curr.next
return 'Linklist : ' + linklist
def __len__(self):
curr = self.head
next = self.head
size = 0
while curr and next:
if not next.next:
size += 1
return size
else:
size += 2
curr = curr.next
next = next.next.next
return size
def insert(self, key):
if not self.head:
self.head = Link(key)
self.tail = self.head
else:
node = Link(key)
self.tail.next = node
self.tail = node
self.length += 1
def delete(self, key):
if not self.head:
return False
elif self.head.val == key:
self.head = self.head.next
else:
curr = self.head
prev = None
while curr and curr.val != key:
prev = curr
curr = curr.next
if curr:
prev.next = curr.next
self.length -= 1
return True
return False
def print_reverse(self, node):
if node:
self.print_reverse(node.next)
print(str(node))
def do_reverse(self):
prev = None
curr = self.head
n = None
while curr:
n = curr.next
curr.next = prev
prev = curr
curr = n
self.head = prev
def delete_a_node_pointer(self):
pass
def find_middle_element(self):
curr = self.head
next = self.head
while curr and next:
if not next.next:
return curr.val,
elif next.next and not next.next.next:
return curr.val, curr.next.val
curr = curr.next
next = next.next.next
def hascycle(self):
slow = self.head
fast = self.head
while slow and fast and fast.next:
slow = slow.next
fast = fast.next.next
if fast is slow:
return True
return False
def create_a_cycle(self):
index = 0
curr = self.head
while curr:
if index == 4:
break
curr = curr.next
index += 1
self.tail.next = curr
def find_start_of_the_cycle(self):
slow = self.head
fast = self.head
cycle = False
while slow and fast and fast.next:
slow = slow.next
fast = fast.next.next
if fast is slow:
cycle = True
break
if cycle:
curr = self.head
while curr and fast and curr is not fast:
curr = curr.next
fast = fast.next
return curr
else:
return None
def removeNthFromEnd(self, n):
pass
def test_main():
linklist = LinkedList()
linklist.insert(2)
# linklist.insert(4)
# linklist.insert(3)
# linklist.insert(-3)
#linklist.insert(-92)
print(str(linklist))
# linklist.delete(2)
# linklist.delete(3)
# linklist.delete(4)
# Don't print once the list has a cycle as it will loop for forever
#linklist.create_a_cycle()
# print(str(linklist))
print('HasCycle : ' , linklist.hascycle())
print('Cycle : ', str(linklist.tail), '->', linklist.find_start_of_the_cycle())
print('Middle Element : ', linklist.find_middle_element())
linklist.do_reverse()
print('Reversed', str(linklist))
print('Length LinkedList : ', str(len(linklist)))
if __name__ == '__main__':
test_main()
-
\$\begingroup\$ (Please tag reinventing-the-wheel.) \$\endgroup\$greybeard– greybeard2019-02-16 07:41:52 +00:00Commented Feb 16, 2019 at 7:41
-
1\$\begingroup\$ @greybeard You can do that yourself too... \$\endgroup\$Peilonrayz– Peilonrayz ♦2019-02-16 12:04:17 +00:00Commented Feb 16, 2019 at 12:04
2 Answers
A few things I'd add to @greybeard's answer (though I'll first emphasize: Add Docstrings):
It's a LinkedList, I'd expect to be able to iterate over it. There should be an
__iter__function here.You rely heavily on knowing what your values are (
headandtail), so you should hide them as private variables (_headand_tail) to indicate that external code should not access or modify them.You keep a
lengthattribute, but when__len__is called, you go through the expensive task of re-computing this anyway. If you trust this value, return it; if not, then don't bother keeping it.You have functions to detect and manage cycles in your linked list, but many of your other functions (including
__len__) don't check if they're trapped in one. This creates a ripe field for getting code locked in an infinite loop.print_reverserelies on recursion, which won't work for lists of more than a few thousand items.do_reverseis really vague, but seems to reverse the list; in Python, this is usually defined as__reversed__delete_a_node_pointer... does nothing, throws no errors, and takes no argument. Delete this, or at leastraise NotImplementedError()create_a_cyclegoes to element 4... for no explicable reason. This should be an argument.You support creating a cycle mid-list (that is, tail points to somewhere in the middle of the list), but then elsewhere in your code treat
tail.nextas properly pointing tohead(particularly ininsert... and it should be used indelete, that's probably a bug that it's not there). Either keep your linked list as a single ring or support middle-cycles, you can't really do both.
-
\$\begingroup\$ About creating cycle's mid-list : I needed it that way. Also there's no way to delete the list if it has cycles. The strategy would be to remove the loop and then delete any node. \$\endgroup\$piepi– piepi2019-02-16 22:56:15 +00:00Commented Feb 16, 2019 at 22:56
The code presented lacks doc strings.
This has consequences: How is anyone supposed to form an opinion on, say, create_a_cycle() (or even removeNthFromEnd())?
- interface
(I'm preoccupied by exposure to SIMSET at an impressible agelinklooks almost as good assucc.)
after a while, I see test support mixed freely with class interface - don't - use of a reserved built-in symbol (
next) as a variable name - don't
(Increate_a_cycle(), you manage to walk a list with a single reference. You don't even use both in__len__()andfind_middle_element(). (Indelete(, key), there is the less readable alternative of usingsucc.succ(seenextavoided).)) __len__():
It looks possible to do source level loop unrolling - but almost never a good idea.
First of all, it impedes readability, especially if not commented properly.
A stripped-down shot at an unrolled __len__() (if not implementing a built-in, there would need to be a docstring…):
def __len__(self):
# unrolled to follow two links per trip
curr = self.head
size = 0
while curr:
succ = curr.succ
if not succ:
return size + 1
size += 2
curr = succ.succ
return size