Combining linked lists iteratively - python

I'm trying to combine two linked lists iteratively, but what I have right now is giving me the reverse of the result. Is there a way to combine the lists in the correct order without having to reverse if after the result list is created?
class Link:
empty = ()
def __init__(self, first, rest=empty):
assert rest is Link.empty or isinstance(rest, Link)
self.first = first
self.rest = rest
def __add__(self, lst):
"""
>>>s = Link(1, Link(2))
>>>s + Link(3,Link(4))
Link(1,Link(2,Link(3,Link(4))))
"""
result = Link.empty
while self is not Link.empty:
result = Link(self.first,result)
self = self.rest
while lst is not Link.empty:
result = Link(lst.first, result)
lst = lst.rest
return result

Conceptually, to combine two linked lists, all you need to do is find the tail of the first list, and connect it with the head of the second list, and then return the head of the first list. The major problem with the current code is that you do not keep around the head of the first list.
I'm assuming that you want the __add__ method to create a copy made up of self followed by lst, so simply create copies of the Links from self first and then lst and attach them as you iterate. Like so:
def __add__(self, lst):
result = Link(self.first)
cur = result
self = self.rest
# Copy our list
while self is not Link.empty:
cur.rest = Link(self.first)
cur = cur.rest
self = self.rest
# Copy and connect the Links in lst
while lst is not Link.empty:
cur.rest = Link(lst.first)
cur = cur.rest
lst = lst.rest
return result
To diagnose what's wrong with the current code, consider stepping through with an example. Assume self is Link(1,Link(2)).
result = Link.empty
while self is not Link.empty:
result = Link(self.first,result)
What's result now?
Link(self.first,result)
is Link(1, Link.empty)
self = self.rest
Now self is Link(2,())
result = Link(self.first,result)
What's result now?
Link(self.first,result)
is Link(2, Link(1, Link.empty))
Oops. Found the problem; you are connecting the links in reverse.

Avoid changing self, find the end of the first list, and add the second list to it.
def __add__(self, lst):
current = self
while current.rest != self.empty:
current = current.rest
current.rest = lst
return self
Or, if you prefer to return a new linked list:
def __add__(self, lst):
new_list = Link(self.first)
new_link = new_list
current = self
while current.rest != self.empty:
new_link.rest = Link(current.first)
new_link = new_link.rest
current = current.rest
current = lst
while current != self.empty:
new_link.rest = Link(current.first)
new_link = new_link.rest
current = current.rest
return new_list
Note: this will make references to each Link.first value (not independent copies).

Related

How do you populate values into a class in python

I have a code that works for merging 2 linked lists for leetcode. However, upon testing it, I am facing a bottleneck. How do I populate the ListNode with a list? the following outputs just 1 whatever, not the merged linked list.
from typing import Optional
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def __str__(self):
return str(self.val)
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
place_holder = ListNode()
tmp = place_holder
while list1 and list2:
if list1.val < list2.val:
tmp.next = list1
list1 = list1.next
else:
tmp.next = list2
list2 = list2.next
tmp = tmp.next
if list1 is None:
tmp.next = list2
if list2 is None:
tmp.next = list1
return place_holder.next
#input the two integer lists
l1 = [1, 2, 4]
l2 = [1, 3, 4]
list1 = ListNode(l1[0])
list2 = ListNode(l2[0])
list_result = Solution().mergeTwoLists(list1, list2)
print(list_result)
Fix your __str__ so it prints the whole linked list:
def __str__(self):
s = f"({str(self.val)})"
if self.next:
s += f" -> {self.next}" # be careful not to build any circular lists...
return s
and now you can see the actual result of your merge function:
(1) -> (1)
which is 100% correct (at least for these inputs) because you merged the lists (1) and (1).
Writing a function that lets you turn a list of multiple numbers into a single linked list will make it easier to test this logic with longer inputs. One option would be to just do this in your ListNode constructor:
from typing import List, Optional, Union
class ListNode:
def __init__(self, val: int = 0, *vals: int) -> None:
self.val = val
self.next = ListNode(*vals) if vals else None
def __str__(self) -> str:
s = f"({str(self.val)})"
if self.next:
s += f" -> {self.next}"
return s
Now you can do:
list1 = ListNode(1, 2, 4)
list2 = ListNode(1, 3, 4)
list_result = Solution().mergeTwoLists(list1, list2)
print(list_result) # (1) -> (1) -> (2) -> (3) -> (4) -> (4)
You need a way to convert a regular Python list to a linked list. Your nodes are initialized with one integer each (never mind that it came from l1 and l2), so they can't grow any next elements by themselves. To fix it, add a static method to ListNode that accepts a list:
class ListNode:
#static
def fromList(lst):
if not lst:
return None
return ListNode(lst[0], next=ListNode.fromList(lst[1:]))
This will recursively convert a Python list into a linked list. Then you can initialize your linked lists like this:
list1 = ListNode.fromList(l1)
list2 = (same)
You need to convert your list value into a List value. (I recommend using separate classes for nodes and the list that consists of those nodes.)
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
def __str__(self):
return str(self.val)
class List:
def __init__(self, values=None):
# Dummy node that is independent of any actual
# data. You can store the length (or really, any
# metadata you like) in the dummy node.
self.head = ListNode(0)
if values is None:
values = []
for x in values:
self.append(x)
def append(self, value):
...
list1 = List(l1)
list2 = List(l2)
You'll need to implement List.append, and possibly some other methods. It's better to do all the pointer wrangling in List itself and to provide methods for mergeTwoLists to construct the resulting List.

Recursive Alternative/Merge Linked List Function with Multiple Linked List as Arguments?

I'm having trouble working with recursive linked list function with multiple linked list arguments.
So far I have came up with below, with a single linked list and works fine.
def recursive_ll(ll):
if ll == None:
return None
elif ll.next == None:
return LN(ll.value)
else:
return_ll = LN(ll.value, recursive_ll(ll.next))
if return_ll.value == return_ll.next.value:
return_ll = return_ll.next
return return_ll
Result will be:
ll = list_to_ll(['x','g','f','n'])
print(str_ll(recursive_ll(ll)))
x->g->f->n->None
But I am really confused with how I can create recursive linked list function with multiple linked lists as arguments.
For example, def recursive_ll(ll): will be def recursive_ll(ll, ll2):
And returned result would be
ll = recursive_ll(['a','x','b','e'])
ll2 = recursive_ll(['d','f','m'])
a->d->x->f->b->m->e->None
Again, desired result below, combined from two linked list:
a->d->x->f->b->m->e->None
Any help/suggestions will be much appreciated!
You should use classes instead of simple functions as helpers. And accept any iterable as the source for a linked list. If you implement iterators on the linked list class, that would allow trivial conversion between any iterable and a linked list.
The linked list class could be:
class LL:
class iter:
def __init__(self, ll):
self.cur = ll.front
def __iter__(self):
return self
def __next__(self):
if self.cur is None:
raise StopIteration()
val = self.cur.value
self.cur = self.cur.next
return val
def __init__(self, l):
self.front = last = None
for v in l:
ln = LN(v)
if last is None:
self.front = ln
else:
last.next = ln
last = ln
def __str__(self):
answer = ''
for val in self.iter_elt():
answer += str(val) + '->'
return answer + 'None'
def __repr__(self):
return str(self.__class__) + ':' + str(self)
def __iter__(self):
return LL.iter(self)
This immediately allows:
>>> print(LL('abcd'))
a->b->c->d->None
>>> list(LL('abcd'))
['a', 'b', 'c', 'd']
Once this is done, you can declare a Recursive Linked List as a subclass of a Linked List which allows to extract the elements in a merge order if it contains Linked Lists.
You should first add a new method iter_elt in LL class that just calls iter and use that in __str__ to ease the subclassing:
class LL:
...
def __str__(self):
answer = ''
for val in self.iter_elt():
answer += str(val) + '->'
return answer + 'None'
...
def iter_elt(self):
return self.__iter__()
Because now, it is enough to override iter_elt in RLL, and build an iterator that will scan its sublists repeatedly calling iter_elt on them if possible else iter, until all are exhausted. Code could be:
class RLL(LL):
class iter:
def __init__(self, rll):
self.iters = LL(i.iter_elt() if hasattr(i, 'iter_elt') else iter(i)
for i in rll)
self.cur = self.iters.front
self.prev = None
def __iter__(self):
return self
def __next__(self):
try:
elt = next(self.cur.value)
self.prev = self.cur
self.cur = self.cur.next
if self.cur is None:
self.cur = self.iters.front
self.prev = None
except StopIteration:
self.cur = self.cur.next
if self.cur is None:
if self.prev is None:
raise
self.cur = self.iters.front
self.prev = None
else:
if self.prev is None:
self.iters.front = self.cur
else:
self.prev.next = self.cur
elt = self.__next__()
return elt
def iter_elt(self):
return RLL.iter(self)
I totally agree with #Serge Ballesta that you should create a LinkedList class to do this, here's how it could be done the procedural way you're doing things.
Also note that it's not done recursively—but rather "pythonically".
from itertools import chain, zip_longest
class LN:
def __init__(self, value, next=None):
self.value = value
self.next = next
def list_to_ll(l):
if l == []:
return None
front = rear = LN(l[0])
for v in l[1:]:
rear.next = LN(v)
rear = rear.next
return front
def iterate(ll):
while ll is not None:
yield ll.value
ll = ll.next
def str_ll(ll):
return '->'.join(str(v) for v in iterate(ll)) + '->None'
def alternate(ll_1, ll_2):
_NULL = object()
chained = chain.from_iterable(zip_longest(iterate(ll_1), iterate(ll_2),
fillvalue=_NULL))
return list_to_ll(list(v for v in chained if v is not _NULL))
if __name__ == '__main__':
ll_1 = list_to_ll(['a','x','b','e'])
ll_2 = list_to_ll(['d','f','m'])
print(str_ll(alternate(ll_1, ll_2))) # -> a->d->x->f->b->m->e->None

Using single linked lists, how to swap nodes in python?

Currently, I've been trying to rearrange a linked list based on my main function switch(myList,index).
def createList(plist):
linkedList = None
# goes backwards, adding each element to the beginning
# of the list.
for index in range(len(plist)-1, -1, -1):
linkedList = insertValueHead(linkedList, plist[index])
return linkedList
def insertValueHead(linkedList, value):
newnode = {}
newnode["data"] = value
#set the next pointer of this new node to the head of the list, linkedList
#newnode is now the head of the list
newnode["next"] = linkedList
return newnode
def listString(linkedList):
ptr = linkedList
str1 = ''
while ptr != None:
str1 += str(ptr['data'])
ptr = ptr['next']
if ptr != None:
str1 += "->"
str1 = str1
return str1
def switch(j, i):
head = j
currentItem = j[0] # The head again
prevItem = 1 # The item that links to tempItem
for x in range(i): # Find the item to swap
prevItem = currentItem
currentItem = currentItem['next']
currentItem = currentItem['next']
temp = currentItem['next']
currentItem['next'] = head['next']
head['next'] = prevItem['next']
prevItem['next'] = temp
def testSwitch():
#test code to ensure that switch() is working correctly.
myList = createList([10, 20, 30, 40, 50, 60])
print "The initial list", listString(myList)
myList = switch(myList, 2)
print "Switching the 1 and the 2. Resulting list is ", listString(myList)
testSwitch()
This should yield a list with swapped elements. However, when I run it this is the output:
The initial list 10->20->30->40->50->60
Switching the 1 and the 2. Resulting list is
This is then followed by the error:
currentItem = currentItem['next']
TypeError: list indices must be integers, not str
What am I doing wrong? I can't seem to figure it out...
The simply-linked list is not a very useful construct, if you need to support switch operation. On a doubly linked list, if the nodes have the pointers forward and backward, then it is very easy, but on singly linked list you need to scan the list at least once. Also, your code is so messy that no one can really debug it. Thus
use class-based lists instead having items of a Node subclass, say.
for switch operation you seriously want to have doubly linked list.
Maybe use the linux linked list convention, where the ends are a list node too
Something like
class Node(object):
prev = None
next = None
class List(object):
def __init__(self):
self.head = self
self.tail = self
self.prev = self
self.next = self
self.nil = self
def insert_head(self, node):
node.next = self.head.next
self.head.next.prev = node
node.prev = self.head
self.head.next = node
def __iter__(self):
current = self.head.next
while current != self.nil:
yield current
current = current.next
def __str__(self): # the "list_string" op
items = []
return ' -> '.join(map(str, self))
class TestNode(Node):
def __init__(self, value):
self.value = value
def __repr__(self):
return repr(self.value)
list = List()
list.insert_head(TestNode('a'))
list.insert_head(TestNode('b'))
print(list)
Your indentation isn't proper, that's why you are getting the issue.
def switch(j, i):
head = j
currentItem = j[0] # The head again
prevItem = 1 # The item that links to tempItem
for x in range(i): # Find the item to swap
prevItem = currentItem
currentItem = currentItem['next']
currentItem = currentItem['next']
temp = currentItem['next']
currentItem['next'] = head['next']
head['next'] = prevItem['next']
prevItem['next'] = temp
Give an indent of four spaces inside a function or a loop. You can't assign j[0] to current item as it's a dict.

Implementation of a Trie in Python

I programmed a Trie as a class in python. The search and insert function are clear, but now i tried to programm the python function __str__, that i can print it on the screen. But my function doesn't work!
class Trie(object):
def __init__(self):
self.children = {}
self.val = None
def __str__(self):
s = ''
if self.children == {}: return ' | '
for i in self.children:
s = s + i + self.children[i].__str__()
return s
def insert(self, key, val):
if not key:
self.val = val
return
elif key[0] not in self.children:
self.children[key[0]] = Trie()
self.children[key[0]].insert(key[1:], val)
Now if I create a Object of Trie:
tr = Trie()
tr.insert('hallo', 54)
tr.insert('hello', 69)
tr.insert('hellas', 99)
And when i now print the Trie, occures the problem that the entries hello and hellas aren't completely.
print tr
hallo | ellas | o
How can i solve that problem?.
Why not have str actually dump out the data in the format that it is stored:
def __str__(self):
if self.children == {}:
s = str(self.val)
else:
s = '{'
comma = False
for i in self.children:
if comma:
s = s + ','
else:
comma = True
s = s + "'" + i + "':" + self.children[i].__str__()
s = s + '}'
return s
Which results in:
{'h':{'a':{'l':{'l':{'o':54}}},'e':{'l':{'l':{'a':{'s':99},'o':69}}}}}
There are several issues you're running into. The first is that if you have several children at the same level, you'll only be prefixing one of them with the initial part of the string, and just showing the suffix of the others. Another issue is that you're only showing leaf nodes, even though you can have terminal values that are not at a leaf (consider what happens when you use both "foo" and "foobar" as keys into a Trie). Finally, you're not outputting the values at all.
To solve the first issue, I suggest using a recursive generator that does the traversal of the Trie. Separating the traversal from __str__ makes things easier since the generator can simply yield each value we come across, rather than needing to build up a string as we go. The __str__ method can assemble the final result easily using str.join.
For the second issue, you should yield the current node's key and value whenever self.val is not None, rather than only at leaf nodes. As long as you don't have any way to remove values, all leaf nodes will have a value, but we don't actually need any special casing to detect that.
And for the final issue, I suggest using string formatting to make a key:value pair. (I suppose you can skip this if you really don't need the values.)
Here's some code:
def traverse(self, prefix=""):
if self.val is not None:
yield "{}:{}".format(prefix, self.val)
for letter, child in self.children.items():
yield from child.traverse(prefix + letter)
def __str__(self):
return " | ".join(self.traverse())
If you're using a version of Python before 3.3, you'll need to replace the yield from statement with an explicit loop to yield the items from the recursive calls:
for item in child.traverse(prefix + letter)
yield item
Example output:
>>> t = Trie()
>>> t.insert("foo", 5)
>>> t.insert("bar", 10)
>>> t.insert("foobar", 100)
>>> str(t)
'bar:10 | foo:5 | foobar:100'
You could go with a simpler representation that just provides a summary of what the structure contains:
class Trie:
def __init__(self):
self.__final = False
self.__nodes = {}
def __repr__(self):
return 'Trie<len={}, final={}>'.format(len(self), self.__final)
def __getstate__(self):
return self.__final, self.__nodes
def __setstate__(self, state):
self.__final, self.__nodes = state
def __len__(self):
return len(self.__nodes)
def __bool__(self):
return self.__final
def __contains__(self, array):
try:
return self[array]
except KeyError:
return False
def __iter__(self):
yield self
for node in self.__nodes.values():
yield from node
def __getitem__(self, array):
return self.__get(array, False)
def create(self, array):
self.__get(array, True).__final = True
def read(self):
yield from self.__read([])
def update(self, array):
self[array].__final = True
def delete(self, array):
self[array].__final = False
def prune(self):
for key, value in tuple(self.__nodes.items()):
if not value.prune():
del self.__nodes[key]
if not len(self):
self.delete([])
return self
def __get(self, array, create):
if array:
head, *tail = array
if create and head not in self.__nodes:
self.__nodes[head] = Trie()
return self.__nodes[head].__get(tail, create)
return self
def __read(self, name):
if self.__final:
yield name
for key, value in self.__nodes.items():
yield from value.__read(name + [key])
Instead of your current strategy for printing, I suggest the following strategy instead:
Keep a list of all characters in order that you have traversed so far. When descending to one of your children, push its character on the end of its list. When returning, pop the end character off of the list. When you are at a leaf node, print the contents of the list as a string.
So say you have a trie built out of hello and hellas. This means that as you descend to hello, you build a list h, e, l, l, o, and at the leaf node you print hello, return once to get (hell), push a, s and at the next leaf you print hellas. This way you re-print letters earlier in the tree rather than having no memory of what they were and missing them.
(Another possiblity is to just descend the tree, and whenever you reach a leaf node go to your parent, your parent's parent, your parent's parent's parent... etc, keeping track of what letters you encounter, reversing the list you make and printing that out. But it may be less efficient.)

Changing characters and reversing chained lists. (python)

Well, I was supposed to do the following:
Using the class Node (classic construction)...
class No:
def __init__(self, valor, prox):
self.valor = valor
self.prox = prox
to make a function that when called will swap the 2nd and 3rd characters of a chained list and add a backward chained list to the end of the original one. So if we do function(list), being lista = No(1, No(4, No(2, None))) (1>4>2) it will return (1>2>4>4>2>1).
The problem with that is that I solved the problem by adding the terms to regular lists and messing with them there. However, then I found out I was supposed to only use chained lists (that node class I put above) and now I'm a bit clueless...
Code for the wrong solution:
class No:
def __init__(self, valor, prox):
self.valor = valor
self.prox = prox
def printLista(lista):
global lista1
lista1 = []
while lista:
lista1.append(lista.valor)
lista = lista.prox
return lista1
def printbackwards(lista):
global lista2
if lista == None: return
printbackwards(lista.prox)
lista2.append(lista.valor)
def swapprint(lista):
global lista1, lista2
i = 0
lista2 = []
printlist(lista)
printbackwards(lista)
for i in range(len(lista1)):
print lista1[i], lista2[i],
lista = No(3, No(1, No(4, No(2, None))))
swapprint(lista)
class No:
def __init__(self,a,b):
self.val = a
self.next = b
def __str__(self):
return "%s->%s"%(self.val,self.next)
def swapandReverse(lista):
n2 = lista.next #2nd element
n2.val,n2.next.val = n2.next.val,n2.val #swap 2,3
n = lista #root node
v = [] #hold our values
while n.next:
v.append(n.val) #add our value to list
n = n.next #move to next node
v.append(n.val) #append value of last node in the list
while len(v): #as long as we have values left in list
n.next = No(v.pop(-1),None) #set next to new node with our val
n = n.next
lista = No(3,No(1,No(4,No(2,None))))
print lista
swapandReverse(lista)
print lista
at least something like that
It shouldn't be necessary to use global variables for your linked-list operations. Instead, you just need to recurse in the right way, and return any values up the call-stack. I'm not sure if I've understood what you're supposed to do, since your print functions don't actually print anything, but here's what you can do if you are supposed to create a new list from an old one:
class Node(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
def __str__(self): # borrowed from Joran Beasley's answer
return "%s->%s" % (self.value, self.next)
def reverse_linked_list(lst, tail=None):
if lst is None:
return tail
else:
return reverse_linked_list(lst.next, Node(lst.value, tail))
def swap_23_linked_list(lst):
try:
second = lst.next
third = second.next
except AttributeError: # probably lst or lst.next is None!
raise ValueError("list is too sort to swap second and third values")
new_third = Node(second.value, third.next) # reuse all the nodes past third!
new_second = Node(third.value, new_third)
new_first = Node(lst.value, new_second)
return new_first
Example usage:
>>> list_1 = Node(3, Node(1, Node(4, Node(2))))
>>> print(list_1)
3->1->4->2->None
>>> list_2 = reverse_linked_list(list_1)
>>> print(list_2)
2->4->1->3->None
>>> list_3 = swap_23_linked_list(list_2)
>>> print(list_3)
2->1->4->3->None

Categories