pythonlinked-listselection-sort

Selection sort for linked list by swapping nodes


The assignment is to use selection sort by swapping nodes, not the values. When sorting algorithm changes the last node, it raises AttributeError, because it seems that first.next in def min_sort()does not seem to change and is None. Here is the code

class LinkedList:
    class Node:
        def __init__(self, data, next=None):
            self.data, self.next = data, next

    def __init__(self, seq):
        self.front = self.Node(None)
        curr = self.front
        for value in seq:
            curr.next = self.Node(value)
            curr = curr.next

    def swap(self, x, y):
        first = self.front
        while first.next is not None:
            if first.next.data == x.data:
                prevx = first
            if first.next.data == y.data:
                prevy = first
            first = first.next
        x, y = y, x
        prevx.next, prevy.next = x, y
        temp = x.next
        x.next = y.next
        y.next = temp

    def progress(self, first, reverse):
        try:
            solid = first
            while first.next is not None:
                if solid.data > first.next.data and not reverse:
                    self.swap(solid, first.next)
                elif solid.data < first.next.data and reverse:
                    self.swap(solid, first.next)
                first = first.next
        except Exception:
            pass

    def min_sort(self, reverse):
        first = self.front
        while first.next is not None:
            self.progress(first, reverse)
            first = first.next


def min_sort(seq, reverse=False):
    ll = LinkedList(seq)
    ll.min_sort(reverse)
    return ll.get_list()


if __name__ == '__main__':
    seq = (4, 30, 8, 31, 48, 19)
    lst = min_sort(seq)
    print(lst)
Traceback (most recent call last):
  File "/Users/rival/My files/Škola/FMFI UK/2. semester/Programovanie 2/projekt8/riesenie.py", line 66, in <module>
    lst = min_sort(seq)
          ^^^^^^^^^^^^^
  File "/Users/rival/My files/Škola/FMFI UK/2. semester/Programovanie 2/projekt8/riesenie.py", line 60, in min_sort
    ll.min_sort(reverse)
  File "/Users/rival/My files/Škola/FMFI UK/2. semester/Programovanie 2/projekt8/riesenie.py", line 46, in min_sort
    while first.next is not None:
          ^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'next'

I don't know how to change the reference in function min_sort so it would work


Solution

  • There are several issues:

    Here is an implementation that takes the above remarks into account:

    class LinkedList:
        class Node:
            def __init__(self, data, nxt=None):
                self.data, self.next = data, nxt
    
        def __init__(self, seq):
            self.front = None  # don't insert a dummy node
            for value in reversed(seq):
                self.front = self.Node(value, self.front)  # prepend
    
        # Don't provide the nodes to swap, but their predecessors
        def swap_after(self, prev_x, prev_y):
            if prev_x == prev_y: # Nothing to do
                return
            x = prev_x.next
            y = prev_y.next
            if x == prev_y:  # Boundary case
                prev_x.next, x.next, y.next = y, y.next, x
            elif y == prev_x:  # Mirrored boundary case
                prev_y.next, y.next, x.next = x, x.next, y
            else: # Generic case
                prev_x.next, x.next, prev_y.next, y.next = y, y.next, x, x.next
    
        # Make the list iterable
        def __iter__(self):
            curr = self.front
            while curr:
                yield curr.data
                curr = curr.next
    
        # Provide a string representation of the list
        def __repr__(self):
            return "->".join(map(repr, self))
    
        def progress(self, last_sorted, reverse):
            prev_selected = prev = last_sorted
            while prev.next:
                if (prev.next.data > prev_selected.next.data) == reverse:
                    prev_selected = prev
                prev = prev.next
            # Swap is only needed when the final selection was made
            self.swap_after(last_sorted, prev_selected)
    
        def min_sort(self, reverse):
            if not self.front:
                return
            dummy = self.Node(None, self.front)
            last_sorted = dummy
            while last_sorted.next.next:
                self.progress(last_sorted, reverse)
                last_sorted = last_sorted.next
            self.front = dummy.next
    
    def min_sort(seq, reverse=False):
        ll = LinkedList(seq)
        ll.min_sort(reverse)
        return list(ll)
    
    
    if __name__ == '__main__':
        seq = (4, 30, 8, 31, 48, 19)
        lst = min_sort(seq)
        print(lst)