I have recently tried converting a singly linked list from a C program into my own python program. I have tested the code myself but I am still unsure if the program has been converted properly. I would like someone to peer review my code to see if there are any errors in methodology, too many methods, any missing methods, etc.
I have tried implementing some of my own singly linked list operations based from the advice from this website: https://afteracademy.com/blog/types-of-linked-list-and-operation-on-linked-list
The original C Program: https://people.eng.unimelb.edu.au/ammoffat/ppsaa/c/listops.c
My own python code:
class Node():
# Node for a single linked list
def __init__(self, data):
self.data = data
self.next = None
class LinkedList():
def __init__(self):
self.head = None
self.foot = None
def length(self):
'''Returns the length of a linked list.'''
current_node = self.head
node_total = 0
while (current_node != None):
node_total += 1
current_node = current_node.next
return node_total
def is_empty_list(self):
'''Checks if a linked list is empty.'''
return self.head == None
def stack_insert(self, data):
'''Inserts a node at the HEAD of the list;
LIFO (Last In, First Out).'''
new_node = Node(data)
# Makes new_node.next point to next node (defualt None if 1st insertion)
new_node.next = self.head
# Makes the HEAD of linked list point to new node
self.head = new_node
if (self.foot == None):
# First insertion into linked list; node becomes HEAD & FOOT
self.foot = new_node
def queue_append(self, data):
'''Appends a node at the FOOT of the list;
FIFO (First In, First Out).'''
new_node = Node(data)
if (self.head == None):
# First insertion into linked list; node becomes HEAD & FOOT
self.head = self.foot = new_node
else:
# Makes the original last node point to the newly appended node
self.foot.next = new_node
# Makes the newly appended list as the official FOOT of the linked list
self.foot = new_node
def insert_after(self, data, index):
'''Inserts a NEW node AFTER a specific node indicated by index.'''
# Need to ensure provided index is within range
if (index < 0):
print("ERROR: 'insert_after' Index cannot be negative!")
return
elif (index > (self.length() -1)):
print("ERROR: 'insert_after' Index exceeds linked list range!")
return
# Use stack_insert to insert as first item
elif (self.is_empty_list()) or (index == 0):
self.stack_insert(data)
return
# Use queue_insert to append as last item
elif (index == (self.length() -1)):
self.queue_append(data)
return
new_node = Node(data)
prior_node = self.head
current_node = self.head
search_index = 0
# Keep traversering through nodes until desired node
while (search_index != index):
prior_node = current_node
current_node = current_node.next
search_index += 1
# Makes prior node is point to target node
prior_node = current_node
# Makes current node point to the node AFTER target node (default None of last node)
current_node = current_node.next
# Makes target node point to newly added node
prior_node.next = new_node
# Makes newly added node point to original node that WAS AFTER target node
new_node.next = current_node
def delete_head(self):
'''Deletes the HEAD node.'''
# Linked list is empty
if self.is_empty_list():
return
old_head = self.head
# Adjusts the head pointer to step past original HEAD
self.head = self.head.next
if (self.head == None):
# The only node just got deleted
self.foot = None
def delete_foot(self):
'''Deletes the FOOT node.'''
# Linked list is empty
if self.is_empty_list():
return
old_foot = self.foot
prior_node = self.head
current_node = self.head
# Need to keep cycling until final node is reached
while (current_node.next != None):
prior_node = current_node
current_node = current_node.next
# Adjust newly FOOT node to point to nothing
prior_node.next = None
# Makes linked list forget about original FOOT node
self.foot = prior_node
def delete_node(self, index):
'''Deletes a target node via index.'''
# Linked list is empty
if self.is_empty_list():
return
# Need to ensure index is within proper range
elif (index < 0):
print("ERROR: 'delete_node' Index cannot be negative!")
return
elif (index > (self.length() -1)):
print("ERROR: 'delete_node' Index exceeds linked list range")
return
prior_node = self.head
current_node = self.head
search_index = 0
# Keep travsersing though nodes until desired node
while (search_index != index):
prior_node = current_node
current_node = current_node.next
search_index += 1
# Adjusts node PRIOR to target node to point to the node the AFTER target node
prior_node.next = current_node.next
def update_node(self, new_data, index):
'''Updates target node data via index.'''
# Linked list is empty
if self.is_empty_list():
print("ERROR: 'update_node' Linked list is empty; no node data to update!")
return
# Need to ensure index is within proper range
elif (index < 0):
print("ERROR: 'update_node' Index cannot be negative!")
return
elif (index > (self.length() -1)):
print("ERROR: 'update_node' Index exceeds linked list range!")
current_node = self.head
search_index = 0
# Keep traversing through nodes until desired node
while (search_index != index):
current_node = current_node.next
search_index += 1
# Can now change data
current_node.data = new_data
def get_node_data(self, index):
'''Extracts that data from a specific node via index.'''
# Linked list is empty
if self.is_empty_list():
print("ERROR: 'update_node' Linked list is empty; no node data to update!")
return
# Need to ensure index is within proper range
elif (index < 0):
print("ERROR: 'update_node' Index cannot be negative!")
return
elif (index > (self.length() -1)):
print("ERROR: 'update_node' Index exceeds linked list range!")
# Index matches HEAD or FOOT
if (index == 0):
return self.head.data
elif (index == (self.length() -1)):
return self.foot.data
current_node = self.head
search_index = 0
# Keep traversing though nodes until desired node
while (search_index != index):
current_node = current_node.next
search_index += 1
return current_node.data