This commit is contained in:
2023-09-22 09:51:10 -04:00
commit 1af8bd1e54
32 changed files with 346400 additions and 0 deletions

35
1-linked-list/README.md Normal file
View File

@ -0,0 +1,35 @@
Single Linked List
===========
Wikipedia on [Linked Lists](http://en.wikipedia.org/wiki/Linked_list).
CS50 on [Linked Lists](https://www.youtube.com/watch?v=5nsKtQuT6E8)
A linked list is a common data structure, where nodes are grouped to form a sequence. Each node holds data and a pointer to another node.
###Visualization
|42|-> |55|-> |4|-> |39|-> None
A linked last can be advantageous over an array because it is dynamic - to insert or delete a node in the middle of the list, we don't need to re-index the entire list, like an array. We only need to alter a pointer.
For example, to insert `|79|` after `|4|` in the list above, pseudocode would look this:
79 = new node
79.next should point to 4.next (i.e. 4.next points to 39)
# after insertion:
- 4.next should point to 79
- 79.next should point to 39
- 39.next should still point to None
###Implementation
Do not use lists or dictionaries. That's cheating. Create this using classes only. You will want a Node class and a LinkedList class.
Create your data structures and the following methods that allow your linked list to:
- insert
- search (First iteratively then recursively)
- delete
- print backwards

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,132 @@
class Node:
def __init__( self, payLoad, next=None ):
self.payLoad = payLoad
self.next = next
class LinkedList:
head = None
def __init__( self, *args ):
for item in args:
self.insert( item )
# allow print to work correctly.
# def __str__(self):
# return self.print()
# allow += and + operates to work correctly
def __add__( self, item ):
self.insert( item )
return self
# allow the in operator to work
def __iter__(self):
current = self.head
while current:
yield current.payLoad
current = current.next
# allow the len() function to be used
def __len__( self ):
return self.find( None )['count']
# internal method check if node is a node object
def __check_Node( self, node ):
if not isinstance(node, Node):
return Node(node)
return node
def find( self, match ):
''' Searches the list for a matching node. If found it will return the
current node, last node as Node objects and position as an int.
If nothing is found, it will return None, the last node as a Node
object, and the full length of the list as an int.
This function will ONLY return the first match.
setting match to None will find the end of the list and return the
last node as return['last']
This method does alot of the heavy lifting.
'''
current = self.head
last = None
count = 0
while current:
if current.payLoad == match:
return {'current': current, 'last': last, 'count': count}
last = current
current = current.next
count += 1
return {'current': current, 'last': last, 'count': count}
def insert( self, item, after=None ):
# check to see if adding a whole LinkedList
if isinstance(item, self.__class__):
self.find(None)['last'].next = item.head
return self
item = self.__check_Node( item )
# figures out the position of the node
previous_node = self.find(after)['current'] if after else self.find(None)['last']
# if the after node isnt found, do nothing.
if not previous_node: return None;
item.next = previous_node.next
previous_node.next = item
return item
def print_right( self ):
def rec( current ):
if not current: return 'None'
return rec( current.next ) + ' <= ' + current.payLoad
return( rec( self.head ) + ' <= head' )
def __str__( self ):
current = self.head
out = 'head' + ' => '
while current:
out += current.payLoad + ' => '
current = current.next
return out + 'None'
def __repr__( self ):
return self.__str__()
def delete( self, payLoad ):
match, before, count = self.find( payLoad )
if match:
before.next = match.next
return match
return None
if __name__ == '__main__':
l2 = LinkedList('a')
l2.insert('b')
l2.insert('c')
l2 += Node('d')
l2.insert('1', 'c')
print(l2)
l = LinkedList( Node('1') )
l.insert( Node('2'))
l.insert( Node('3'))
l.insert( Node('4'))
l += Node('5')
l.insert('a')
l3 = l + l2
print( l.print_right() )

Binary file not shown.

View File

@ -0,0 +1,142 @@
class Node:
def __init__(self, payLoad, next=None):
self.payLoad = payLoad
self.next = next
def __str__(self):
return str(self.payLoad)
def __repr__(self):
return self.__str__()
class LinkedList:
def __init__(self, item):
self.next = self.next = self.__check_Node(item)
self.head = self.next
def __repr__(self):
return self.__str__()
def __add__(self, item):
'''allow += and + operates to work correctly'''
if item is self: return False
self.push( item )
return self
def __iter__(self):
'''allow the in operator to work'''
current = self.next
while isinstance(current, Node):
yield current
current = current.next
def __len__(self):
'''allow the len() function to be used'''
return self.find( None )['count']
def __str__(self):
'''allow print to work correctly'''
current = self.next
out = 'Head' + ' => '
for current in self:
# while current:
out += str(current.payLoad) + ' => '
current = current.next
return out + 'None'
def __check_Node(self, node):
'''internal method check if node is a node object'''
if isinstance(node, self.__class__):
return node.head
if not isinstance(node, Node):
return Node(node)
return node
def find(self, match):
''' Searches the list for a matching node. If found it will return the
current node, last node as Node objects and position as an int.
If nothing is found, it will return None, the last node as a Node
object, and the full length of the list as an int.
This function will **ONLY** return the first match.
setting match to None will find the end of the list and return the
last node as return['last']
This method does alot of the heavy lifting.
'''
current = self.next
last = None
count = 0
while current:
if current.payLoad == match:
return {'current': current, 'last': last, 'count': count}
last = current
current = current.next
count += 1
return {'current': current, 'last': last, 'count': count}
def insert(self, *items, after=False):
# figures out the position of the node
previous_node = self.find(after)['current'] if after != False else self
for item in items[:: -1]:
if isinstance(item, self.__class__):
item = item.next
item = self.__check_Node( item )
item.next = previous_node.next
previous_node.next = item
return self
def push(self, item):
last_node = self.find(None)['last']
node = self.__check_Node(item)
last_node.next = node;
def print_right(self):
def rec(current):
if not current: return 'None'
return rec( current.next ) + ' <= ' + current.payLoad
return rec( self.next ) + ' <= Head'
def delete(self, payLoad):
match = self.find( payLoad )
if match['current']:
match['last'].next = match['current'].next
return match['current'];
return None
if __name__ == '__main__':
''' Some testing stuff '''
l1 = LinkedList('b')
l1.insert('a')
l1.push('c')
print(l1)
l2 = LinkedList('1')
l2.push('2')
print(l2)
l1 +=l2
print(l1)