Search code examples
pythonpython-3.xduplicatescircular-list

How to remove duplicates from circular linked list


My code is given below. It appends some numbers to the circular list. My program works fine. It gives an exact output of [5,3,3] or any numbers entered. But I want to make some changes in the output. without adding any new function what kind of changes to make in the def append(....) and def add_before(...) so it gives a unique number which means it gets rid of the duplicates. for example, will give [5,3]

class CirList:
    def __init__(self):
        head_node = NodeDLL(None)
        head_node.next = head_node
        head_node.prev = head_node
        self.__head = head_node

    def append(self, item):
        curr = self.__head
        new_node = NodeDLL(item, curr, curr.get_prev())
        curr.set_prev(new_node)
        new_node.get_prev().set_next(new_node)

    def add_before(self, item, old_item):
        curr = self.__head.next
        found = False
        while curr.get_data() != None and not found:
            if curr.get_data() == old_item:
                found = True  
            else:
                curr = curr.get_next()
        if found:
            new_node = NodeDLL(item, curr, curr.get_prev())
            curr.set_prev(new_node)
            new_node.get_prev().set_next(new_node)
        return found
    def remove(self, item):
        curr = self.__head.next
        found = False
        while curr.get_data() != None and not found:
            if curr.get_data() == item:
                found = True
            else:
                curr = curr.get_next()
        if found:       
            curr.get_prev().set_next(curr.get_next())
            curr.get_next().set_prev(curr.get_prev())
    def printall(self):
        curr = self.__head.next
        while curr.get_data() != None:
            print(curr.get_data(), end=" ")
            curr = curr.get_next()
        print()
    def __str__(self):
        result = "["
        curr = self.__head.next 
        while curr.get_data() != None:
            result += str(curr.get_data()) + " "
            curr = curr.get_next()
        result = result.rstrip(" ")
        result += "]"
        return result 

Test

listA = CirList()
listA.append(5)
listA.append(3)
listA.append(3)
print(listA)

Solution

  • Two options (I can think of):

    Don't add duplicates:

    class CirList:
        def __init__(self):
            head_node = NodeDLL(None)
            head_node.next = head_node
            head_node.prev = head_node
            self.__head = head_node
            self._knownNumbers = set() # optimized lookup if number known
    
        def append(self, item):
            if item not in self._knownNumbers: # only add if not known
                self.__knownNumbers__.add(item)
                curr = self.__head
                new_node = NodeDLL(item, curr, curr.get_prev())
                curr.set_prev(new_node)
                new_node.get_prev().set_next(new_node)
    
        def add_before(self, item, old_item):
            if item not in self._knownNumbers: # only add if not known
                self.__knownNumbers__.add(item)
                curr = self.__head.next
                found = False
                while curr.get_data() != None and not found:
                    if curr.get_data() == old_item:
                        found = True  
                    else:
                        curr = curr.get_next()
                if found:
                    new_node = NodeDLL(item, curr, curr.get_prev())
                    curr.set_prev(new_node)
                    new_node.get_prev().set_next(new_node)
                return found
        def remove(self, item):
            self._knownNumbers.remove(item) # forget this number again
            curr = self.__head.next
            found = False
            while curr.get_data() != None and not found:
                if curr.get_data() == item:
                    found = True
                else:
                    curr = curr.get_next()
            if found:       
                curr.get_prev().set_next(curr.get_next())
                curr.get_next().set_prev(curr.get_prev())
    

    Or simply do not print duplicates:

    def __str__(self):
        result = "["
        curr = self.__head.next
        known = set() # keep what we added already
        while curr.get_data() != None:
            if curr.get_data() not in known: # only add if not yet added
                result += str(curr.get_data()) + " "
                known.add(curr.get_data())   # remember this one
            curr = curr.get_next()
        result = result.rstrip(" ")
        result += "]"
        return result 
    

    You would have to modify your printall() accordingly if you want it to mimic this behaviour - you would still store all duplicates though so does not make much sense to me, unless you create a seperate def printNoDuplicates(self) specificly for this purpose.