Reputation: 233
I'm having trouble implementing a deep copy method for a DoublyLinkedList
class. A deep copy is supposed to return a new, original Doubly Linked List that does not reference the original DLL (unlike a shallow copy).
Here's what I have so far:
class EmptyCollection(Exception):
pass
class DoublyLinkedList:
class Node:
def __init__(self, data=None, next=None, prev=None):
self.data = data
self.next = next
self.prev = prev
def disconnect(self):
self.data = None
self.next = None
self.prev = None
def __init__(self):
self.header = DoublyLinkedList.Node()
self.trailer = DoublyLinkedList.Node()
self.header.next = self.trailer
self.trailer.prev = self.header
self.size = 0
def __len__(self):
return self.size
def is_empty(self):
return (len(self) == 0)
def first_node(self):
if (self.is_empty()):
raise EmptyCollection("List is empty")
return self.header.next
def last_node(self):
if (self.is_empty()):
raise EmptyCollection("List is empty")
return self.trailer.prev
def add_first(self, elem):
return self.add_after(self.header, elem)
def add_last(self, elem):
return self.add_after(self.trailer.prev, elem)
def add_after(self, node, elem):
prev = node
succ = node.next
new_node = DoublyLinkedList.Node()
new_node.data = elem
new_node.prev = prev
new_node.next = succ
prev.next = new_node
succ.prev = new_node
self.size += 1
return new_node
def add_before(self, node, elem):
return self.add_after(node.prev, elem)
def delete(self, node):
prev = node.prev
succ = node.next
prev.next = succ
succ.prev = prev
self.size -= 1
data = node.data
node.disconnect()
return data
def __iter__(self):
if(self.is_empty()):
return
cursor = self.first_node()
while(cursor is not self.trailer):
yield cursor.data
cursor = cursor.next
def __str__(self):
return '[' + '<-->'.join([str(elem) for elem in self]) + ']'
def __repr__(self):
return str(self)
def deepCopy(lnk_lst):
currenthead = lnk_lst.first_node()
temp = DoublyLinkedList()
while currenthead is not lnk_lst.trailer:
temp.add_last(currenthead.data)
currenthead = currenthead.next
return temp
lnk_lst1 = DoublyLinkedList()
elem1 = DoublyLinkedList()
elem1.add_last(1)
elem1.add_last(2)
lnk_lst1.add_last(elem1)
elem2 = 3
lnk_lst1.add_last(elem2)
lnk_lst2 = deepCopy(lnk_lst1)
e1 = lnk_lst1.first_node()
e1_1 = e1.data.first_node()
e1_1.data = 10
e2 = lnk_lst2.first_node()
e2_1 = e2.data.first_node()
print(e2_1.data) #should print 1
My deep copy method seems to return a shallow copy. The output of the program should be 1 (since lnk_lst2
should not reference any elements in lnk_lst1
.)
Can someone explain how I can modify my deep copy method to produce a deep copy of the linked list and not a shallow copy?
I cannot use python's built in deep or shallow copy for this. Any help would be appreciated.
Upvotes: 4
Views: 3677
Reputation: 17332
Many basic objects can be copied with type(obj)(obj)
. E.g. dict(dct)
or list(lst)
will create a copy. Immutable types will return the same object, and that's fine. int(42)
is 42 and str("string")
is "string"
, etc.
The following solution will be limited to such types.
So let's make a use of that and let's add the DoublyLinkedList
to the set of types creating a copy (in our case a deep copy but only at the first level of nesting) this way. Modified __init__
:
def __init__(self, iterable=()):
self.header = DoublyLinkedList.Node()
self.trailer = DoublyLinkedList.Node()
self.header.next = self.trailer
self.trailer.prev = self.header
self.size = 0
for item in iterable:
self.add_last(type(item)(item))
Now we do not need the deepCopy()
any longer. The only change left to do is to replace:
lnk_lst2 = deepCopy(lnk_lst1)
by:
lnk_lst2 = DoublyLinkedList(lnk_lst1)
Upvotes: 1
Reputation: 124714
To perform a deep copy, you need to copy the embedded linked lists:
def deepCopy(lnk_lst):
currenthead = lnk_lst.first_node()
temp = DoublyLinkedList()
while currenthead is not lnk_lst.trailer:
if isinstance(currenthead.data, DoublyLinkedList):
temp.add_last(deepCopy(currenthead.data))
else:
temp.add_last(currenthead.data)
currenthead = currenthead.next
return temp
Upvotes: 2