Module ARgorithmToolkit.linkedlist

The linkedlist module provides support for rendering linked lists.

linkedlist module provides a wrapper for your LinkedList nodes useful for explanation and the Forwardlist class which is useful for application.

  • The LinkedListNode class is used to represent a node.
  • The LinkedList class is used to store the head pointer.
  • The ForwardList class is a complete implementation of singly linked list

These three classes can be directly imported from the toolkit:

>>> llnode = ARgorithmToolkit.LinkedListNode(algo,7)
>>> ll = ARgorithmToolkit.LinkedList("llnode",algo,llnode)
>>> fl = ARgorithmToolkit.ForwardList("fl",algo)
Expand source code
"""The linkedlist module provides support for rendering linked lists.

linkedlist module provides a wrapper for your LinkedList nodes useful for
explanation and the Forwardlist class which is useful for application.

- The LinkedListNode class is used to represent a node.
- The LinkedList class is used to store the head pointer.
- The ForwardList class is a complete implementation of singly linked list

These three classes can be directly imported from the toolkit:

    >>> llnode = ARgorithmToolkit.LinkedListNode(algo,7)
    >>> ll = ARgorithmToolkit.LinkedList("llnode",algo,llnode)
    >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
"""

from ARgorithmToolkit.utils import ARgorithmHashable, ARgorithmStructure, State, StateSet, ARgorithmError
from ARgorithmToolkit.encoders import serialize

class LinkedListNodeState:
    """This class is used to generate states for various actions performed on
    the ``ARgorithmToolkit.linkedlist.LinkedListNode`` object.

    Attributes:

        name (str) : Name of the variable for whom we are generating states
        _id (str) : id of the variable for whom we are generating states
    """

    def __init__(self,name:str,_id:str):
        self.name = name
        self._id = _id

    def llnode_declare(self,value,_next,comments=""):
        """Generates the `llnode_declare` state when a new node is created.

        Args:
            value : The value stored in the linkedlist node
            next (LinkedListNode): The next pointer
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `llnode_declare` state
        """
        state_type = "llnode_declare"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "value" : value,
            "next" : _next.name if _next else "none"
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def llnode_iter(self,value,_next,last_value=None,comments=""):
        """Generates the `llnode_iter` state when a node is accessed or its
        value is changed.

        Args:
            value : The value stored in the linkedlist node
            next (LinkedListNode): The next pointer
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `llnode_iter` state
        """
        state_type = "llnode_iter"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "value" : value,
            "next" : _next.name if _next else "none"
        }
        if not(last_value is None):
            state_def["last_value"] = last_value
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def llnode_next(self,value,_next,last_next,comments=""):
        """Generates the `llnode_next` state when the next pointer changes.

        Args:
            value : The value stored in the linkedlist node
            next (LinkedListNode): The next pointer
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `llnode_next` state
        """
        state_type = "llnode_next"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "value" : value,
            "next" : _next.name if _next else "none",
            "last_next" : last_next.name if last_next else "none"
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def llnode_delete(self,comments=""):
        """Generates the `llnode_delete` state when a node is deleted.

        Args:
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `llnode_delete` state
        """
        state_type = "llnode_delete"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

@serialize
class LinkedListNode(ARgorithmStructure, ARgorithmHashable):
    """The LinkedListNode class is an implementation of a Linked list Node for
    which we store states. Unlike other data structure classes, in which we
    have to give a name to the instance, we dont have to provide name in the
    LinkedListNode Class.

    Attributes:
        algo (ARgorithmToolkit.utils.StateSet): The stateset that will store the states generated by the instance of LinkedListNode Class
        value: The value stored in the node
        next (LinkedListNode): The reference to next node

    Raises:
        ARgorithmError: Raised if algo is not of type StateSet

    Example:

        >>> llnode = ARgorithmToolkit.LinkedListNode(algo,7)
        >>> llnode.value = 10
        >>> temp = = ARgorithmToolkit.LinkedListNode(algo,7)
        >>> temp.next = llnode
        >>> llnode = temp
    """

    def __init__(self,algo:StateSet,value=None,comments=""):
        self.name = str(id(self))
        self._id = str(id(self))
        try:
            assert isinstance(algo,StateSet)
            self.algo = algo
        except AssertionError as e:
            raise ARgorithmError("algo should be of type StateSet") from e

        self.state_generator = LinkedListNodeState(self.name, self._id)

        self._flag = False
        self.value = value
        self.next = None
        self._flag = True

        state = self.state_generator.llnode_declare(
            self.value,self.next,comments
        )
        self.algo.add_state(state)

    def __setattr__(self,key,value):
        """The __setattr__ function is overriden to listen to state changes in
        the value of node or the next attribute.

        Raises:
            ARgorithmError: Raised if next pointer is not type None or LinkedListNode
        """
        if key == 'next' and value:
            assert isinstance(value,LinkedListNode) , ARgorithmError("next should be of type None or LinkedListNode")
        last_value = None
        last_next = None
        if key == 'value' and self._flag:
            last_value = self.value
        elif key == 'next' and self._flag:
            last_next = self.next
        self.__dict__[key] = value
        if key == 'next' and self._flag:
            if last_next or self.next:
                state = self.state_generator.llnode_next(
                    value=self.value,
                    _next=self.next,
                    last_next=last_next,
                    comments="next pointer updated"
                )
                self.algo.add_state(state)
        elif key == 'value' and self._flag:
            state = self.state_generator.llnode_iter(
                value=self.value,
                _next=self.next,
                last_value=last_value,
                comments="value updated"
            )
            self.algo.add_state(state)

    def __del__(self):
        """The __del__ function is overriden is there to listen to node
        deletion."""
        state = self.state_generator.llnode_delete(
            "Node was deleted"
        )
        self.algo.add_state(state)

    def __str__(self):
        return f"LinkedListNode({self.value}) at {self.name}"

    def __repr__(self):
        return f"LinkedListNode({self.value}) at {self.name}"

class LinkedListState:
    """This class is used to generate states for various actions performed on
    the ``ARgorithmToolkit.linkedlist.LinkedList`` object.

    Attributes:

        name (str) : Name of the variable for whom we are generating states
        _id (str) : id of the variable for whom we are generating states
    """
    def __init__(self,name:str,_id:str):
        self.name = name
        self._id = _id

    def ll_declare(self,head,comments=""):
        """Generates the `ll_declare` state when a new linkedlist is created.

        Args:
            head (LinkedListNode): The head pointer
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `ll_declare` state
        """
        state_type = "ll_declare"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "head" : head.name if head else "none"
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def ll_head(self,head,last_head=None,comments=""):
        """Generates the `ll_head` state when linkedlist head is changed.

        Args:
            head (LinkedListNode): The head pointer
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `ll_head` state
        """
        state_type = "ll_head"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "head" : head.name if head else "none"
        }
        if not (last_head is None):
            state_def["last_head"] = last_head
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

@serialize
class LinkedList(ARgorithmStructure, ARgorithmHashable):
    """The LinkedList class is used to just store the head of the linked list.

    This class is useful when programmer want to program his own List class using
    the nodes. Only contains head attribute and no methods

    Attributes:
        name (str): The name given to the linkedlist
        algo (ARgorithmToolkit.utils.StateSet): The stateset that will store the states generated by the instance of LinkedList Class
        head (LinkedListNode): The referece to head of linkedlist

    Raises:
        ARgorithmError: Raised if algo is not of type StateSet

    Example:

        >>> ll = ARgorithmToolkit.LinkedList("llnode",algo)
        >>> llnode = ARgorithmToolkit.LinkedListNode(algo,7)
        >>> ll.head = llnode
    """

    def __init__(self,name:str,algo:StateSet,head=None,comments=""):

        assert isinstance(name,str) , ARgorithmError("Name should be of type string")
        self.name = name
        self._id = str(id(self))
        try:
            assert isinstance(algo,StateSet)
            self.algo = algo
        except AssertionError as e:
            raise ARgorithmError("algo should be of type StateSet") from e
        self.state_generator = LinkedListState(self.name, self._id)

        self._flag = False
        if head:
            assert self.algo == head.algo, ARgorithmError("The head node belongs to a different StateSet")
        self.head = head
        self._flag = True

        state = self.state_generator.ll_declare(self.head,comments)
        self.algo.add_state(state)

    def __setattr__(self,key,value):
        """The __setattr__ function is overriden to listen to state changes in
        the head.

        Raises:
            ARgorithmError: Raised if head pointer is not type None or LinkedListNode
        """
        last_head = None
        if key == 'head' and value:
            assert isinstance(value,LinkedListNode) , ARgorithmError("next should be of type None or LinkedListNode")
        if key == 'head' and self._flag:
            last_head = self.head._id if self.head else "none"
        self.__dict__[key] = value
        if key == 'head' and self._flag:
            state = self.state_generator.ll_head(self.head,last_head=last_head, comments="head pointer shifts")
            self.algo.add_state(state)

    def __str__(self):
        return f"LinkedList(head at {self.head})"

    def __repr__(self):
        return f"LinkedList(head at {self.head})"

class ForwardListIterator:
    """This class is a generator that is returned each time an ForwardList has
    to be iterated.

    Yields:
        Value of ForwardList Node

    Raises:
        AssertionError: If not declared with an instance of ARgorithmToolkit.linkedlist.ForwardList
    """
    def __init__(self,forwardlist):
        assert isinstance(forwardlist,ForwardList)
        self._curr = forwardlist.head

    def __next__(self):
        if self._curr:
            data = self._curr.value
            self._curr = self._curr.next
            return data
        raise StopIteration

class ForwardList(LinkedList):
    """The ForwardList class is proper implementation of singly linked list.

    The difference between LinkedList and ForwardList class is that ForwardList
    is a ready implementation of singly linked list. In the LinkedList class the
    programmer will have to make their own methods.

    Attributes:
        name (str): The name given to the linkedlist
        algo (ARgorithmToolkit.utils.StateSet): The stateset that will store the states generated by the instance of ForwardList Class
        head (LinkedListNode): The referece to head of linkedlist
        size (int): Number of nodes i.e size of list

    Raises:
        ARgorithmError: Raised if algo is not of type StateSet

    Example:

        >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
    """

    def __init__(self,name:str,algo:StateSet,comments=""):
        super().__init__(name,algo,comments="")
        self.size = 0

    def __len__(self):
        """overloads the len() operator to return size of list.

        Returns:
            int: size of list

        Example:

            >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
            >>> fl.push_front(1)
            >>> fl.size()
            1
        """
        return self.size

    def insert(self,value,index=0):
        """Insert node with given value at particular index. If index is not
        given,insert at front.

        Args:
            value : The value to be inserted
            index (int, optional): The index where value has to inserted . Defaults to 0.

        Example:

            >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
            >>> fl.insert(2)
            >>> fl.insert(4)
            >>> fl.insert(3,1)
            >>> fl
            ForwardList([4, 3, 2])
        """
        if self.size == 0 or index == 0:
            self.push_front(value)
        elif self.size < index:
            temp = self.head
            while temp.next:
                temp = temp.next
            curr = LinkedListNode(self.algo,value)
            temp.next = curr
            self.size += 1
        else:
            count = 1
            temp = self.head
            while index > count:
                count += 1
                temp = temp.next
            curr = LinkedListNode(self.algo,value)
            curr.next = temp.next
            temp.next = curr
            self.size += 1

    def push_front(self,value):
        """Pushes value to front.

        Args:
            value : Value to be appended to front

        Example:
            >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
            >>> fl
            ForwardList([])
            >>> fl.push_front(1)
            >>> fl
            ForwardList([1])
        """
        curr = LinkedListNode(self.algo,value)
        if self.head:
            curr.next = self.head
            self.head = curr
        else:
            curr.next = None
            self.head = curr
        self.size+=1

    def pop_front(self):
        """Pops first element of forwardlist.

        Raises:
            ARgorithmError: Raised if list is empty

        Returns:
            element: The first element of list

        Example:

            >>> fl
            ForwardList([2, 1])
            >>> fl.pop_front()
            2
        """
        if self.head is None:
            raise ARgorithmError("Empty list")
        data = self.head.value
        temp = self.head
        self.head = self.head.next
        del temp
        self.size -= 1
        return data

    def front(self):
        """Returns the first element of list.

        Raises:
            ARgorithmError: Raised when list is empty

        Returns:
            element: The first element of list

        Example:

            >>> fl
            ForwardList([2, 1])
            >>> fl.front()
            2
        """
        if self.head is None:
            raise ARgorithmError("Empty list")
        return self.head.value

    def __iter__(self):
        """Returns the generator object to iterate through elements of
        ForwardList.

        Returns:
            ForwardListIterator: Generator class for ForwardList

        Example:

            >>> [x for x in fl]
            [2, 2, 1]
        """
        return ForwardListIterator(self)

    def remove(self,value):
        """Remove elements with given value from list.

        Args:
            value : The value which has to be removed

        Raises:
            ARgorithmError: Raised if list is empty

        Example:

            >>> fl
            ForwardList([2, 2, 1])
            >>> fl.remove(2)
            >>> fl
            ForwardList([1])
        """
        if self.head is None:
            raise ARgorithmError("Empty list")
        while value == self.head.value:
            temp = self.head
            self.head = self.head.next
            del temp
            self.size -= 1
            if self.head is None:
                return
        curr = self.head
        while curr:
            if curr.next:
                if curr.next.value == value:
                    temp = curr.next
                    curr.next = curr.next.next
                    del temp
                    self.size -= 1
                    continue
            curr = curr.next

    def tolist(self):
        """Converts the ForwardList to python list.

        Returns:
            list: list of ForwardList items

        Example:

            >>> fl
            ForwardList([3, 1])
            >>> fl.tolist()
            [3, 1]
        """
        curr = self.head
        data = []
        while curr:
            data.append(curr.value)
            curr = curr.next
        return data

    def __repr__(self):
        return f"ForwardList({self.tolist()})"

    def __str__(self):
        return f"ForwardList({self.tolist()})"

Classes

class ForwardList (name: str, algo: StateSet, comments='')

The ForwardList class is proper implementation of singly linked list.

The difference between LinkedList and ForwardList class is that ForwardList is a ready implementation of singly linked list. In the LinkedList class the programmer will have to make their own methods.

Attributes

name : str
The name given to the linkedlist
algo : StateSet
The stateset that will store the states generated by the instance of ForwardList Class
head : LinkedListNode
The referece to head of linkedlist
size : int
Number of nodes i.e size of list

Raises

ARgorithmError
Raised if algo is not of type StateSet

Example

>>> fl = ARgorithmToolkit.ForwardList("fl",algo)
Expand source code
class ForwardList(LinkedList):
    """The ForwardList class is proper implementation of singly linked list.

    The difference between LinkedList and ForwardList class is that ForwardList
    is a ready implementation of singly linked list. In the LinkedList class the
    programmer will have to make their own methods.

    Attributes:
        name (str): The name given to the linkedlist
        algo (ARgorithmToolkit.utils.StateSet): The stateset that will store the states generated by the instance of ForwardList Class
        head (LinkedListNode): The referece to head of linkedlist
        size (int): Number of nodes i.e size of list

    Raises:
        ARgorithmError: Raised if algo is not of type StateSet

    Example:

        >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
    """

    def __init__(self,name:str,algo:StateSet,comments=""):
        super().__init__(name,algo,comments="")
        self.size = 0

    def __len__(self):
        """overloads the len() operator to return size of list.

        Returns:
            int: size of list

        Example:

            >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
            >>> fl.push_front(1)
            >>> fl.size()
            1
        """
        return self.size

    def insert(self,value,index=0):
        """Insert node with given value at particular index. If index is not
        given,insert at front.

        Args:
            value : The value to be inserted
            index (int, optional): The index where value has to inserted . Defaults to 0.

        Example:

            >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
            >>> fl.insert(2)
            >>> fl.insert(4)
            >>> fl.insert(3,1)
            >>> fl
            ForwardList([4, 3, 2])
        """
        if self.size == 0 or index == 0:
            self.push_front(value)
        elif self.size < index:
            temp = self.head
            while temp.next:
                temp = temp.next
            curr = LinkedListNode(self.algo,value)
            temp.next = curr
            self.size += 1
        else:
            count = 1
            temp = self.head
            while index > count:
                count += 1
                temp = temp.next
            curr = LinkedListNode(self.algo,value)
            curr.next = temp.next
            temp.next = curr
            self.size += 1

    def push_front(self,value):
        """Pushes value to front.

        Args:
            value : Value to be appended to front

        Example:
            >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
            >>> fl
            ForwardList([])
            >>> fl.push_front(1)
            >>> fl
            ForwardList([1])
        """
        curr = LinkedListNode(self.algo,value)
        if self.head:
            curr.next = self.head
            self.head = curr
        else:
            curr.next = None
            self.head = curr
        self.size+=1

    def pop_front(self):
        """Pops first element of forwardlist.

        Raises:
            ARgorithmError: Raised if list is empty

        Returns:
            element: The first element of list

        Example:

            >>> fl
            ForwardList([2, 1])
            >>> fl.pop_front()
            2
        """
        if self.head is None:
            raise ARgorithmError("Empty list")
        data = self.head.value
        temp = self.head
        self.head = self.head.next
        del temp
        self.size -= 1
        return data

    def front(self):
        """Returns the first element of list.

        Raises:
            ARgorithmError: Raised when list is empty

        Returns:
            element: The first element of list

        Example:

            >>> fl
            ForwardList([2, 1])
            >>> fl.front()
            2
        """
        if self.head is None:
            raise ARgorithmError("Empty list")
        return self.head.value

    def __iter__(self):
        """Returns the generator object to iterate through elements of
        ForwardList.

        Returns:
            ForwardListIterator: Generator class for ForwardList

        Example:

            >>> [x for x in fl]
            [2, 2, 1]
        """
        return ForwardListIterator(self)

    def remove(self,value):
        """Remove elements with given value from list.

        Args:
            value : The value which has to be removed

        Raises:
            ARgorithmError: Raised if list is empty

        Example:

            >>> fl
            ForwardList([2, 2, 1])
            >>> fl.remove(2)
            >>> fl
            ForwardList([1])
        """
        if self.head is None:
            raise ARgorithmError("Empty list")
        while value == self.head.value:
            temp = self.head
            self.head = self.head.next
            del temp
            self.size -= 1
            if self.head is None:
                return
        curr = self.head
        while curr:
            if curr.next:
                if curr.next.value == value:
                    temp = curr.next
                    curr.next = curr.next.next
                    del temp
                    self.size -= 1
                    continue
            curr = curr.next

    def tolist(self):
        """Converts the ForwardList to python list.

        Returns:
            list: list of ForwardList items

        Example:

            >>> fl
            ForwardList([3, 1])
            >>> fl.tolist()
            [3, 1]
        """
        curr = self.head
        data = []
        while curr:
            data.append(curr.value)
            curr = curr.next
        return data

    def __repr__(self):
        return f"ForwardList({self.tolist()})"

    def __str__(self):
        return f"ForwardList({self.tolist()})"

Ancestors

Methods

def front(self)

Returns the first element of list.

Raises

ARgorithmError
Raised when list is empty

Returns

element
The first element of list

Example

>>> fl
ForwardList([2, 1])
>>> fl.front()
2
Expand source code
def front(self):
    """Returns the first element of list.

    Raises:
        ARgorithmError: Raised when list is empty

    Returns:
        element: The first element of list

    Example:

        >>> fl
        ForwardList([2, 1])
        >>> fl.front()
        2
    """
    if self.head is None:
        raise ARgorithmError("Empty list")
    return self.head.value
def insert(self, value, index=0)

Insert node with given value at particular index. If index is not given,insert at front.

Args

value : The value to be inserted
index : int, optional
The index where value has to inserted . Defaults to 0.

Example

>>> fl = ARgorithmToolkit.ForwardList("fl",algo)
>>> fl.insert(2)
>>> fl.insert(4)
>>> fl.insert(3,1)
>>> fl
ForwardList([4, 3, 2])
Expand source code
def insert(self,value,index=0):
    """Insert node with given value at particular index. If index is not
    given,insert at front.

    Args:
        value : The value to be inserted
        index (int, optional): The index where value has to inserted . Defaults to 0.

    Example:

        >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
        >>> fl.insert(2)
        >>> fl.insert(4)
        >>> fl.insert(3,1)
        >>> fl
        ForwardList([4, 3, 2])
    """
    if self.size == 0 or index == 0:
        self.push_front(value)
    elif self.size < index:
        temp = self.head
        while temp.next:
            temp = temp.next
        curr = LinkedListNode(self.algo,value)
        temp.next = curr
        self.size += 1
    else:
        count = 1
        temp = self.head
        while index > count:
            count += 1
            temp = temp.next
        curr = LinkedListNode(self.algo,value)
        curr.next = temp.next
        temp.next = curr
        self.size += 1
def pop_front(self)

Pops first element of forwardlist.

Raises

ARgorithmError
Raised if list is empty

Returns

element
The first element of list

Example

>>> fl
ForwardList([2, 1])
>>> fl.pop_front()
2
Expand source code
def pop_front(self):
    """Pops first element of forwardlist.

    Raises:
        ARgorithmError: Raised if list is empty

    Returns:
        element: The first element of list

    Example:

        >>> fl
        ForwardList([2, 1])
        >>> fl.pop_front()
        2
    """
    if self.head is None:
        raise ARgorithmError("Empty list")
    data = self.head.value
    temp = self.head
    self.head = self.head.next
    del temp
    self.size -= 1
    return data
def push_front(self, value)

Pushes value to front.

Args

value : Value to be appended to front

Example

>>> fl = ARgorithmToolkit.ForwardList("fl",algo)
>>> fl
ForwardList([])
>>> fl.push_front(1)
>>> fl
ForwardList([1])
Expand source code
def push_front(self,value):
    """Pushes value to front.

    Args:
        value : Value to be appended to front

    Example:
        >>> fl = ARgorithmToolkit.ForwardList("fl",algo)
        >>> fl
        ForwardList([])
        >>> fl.push_front(1)
        >>> fl
        ForwardList([1])
    """
    curr = LinkedListNode(self.algo,value)
    if self.head:
        curr.next = self.head
        self.head = curr
    else:
        curr.next = None
        self.head = curr
    self.size+=1
def remove(self, value)

Remove elements with given value from list.

Args

value : The value which has to be removed

Raises

ARgorithmError
Raised if list is empty

Example

>>> fl
ForwardList([2, 2, 1])
>>> fl.remove(2)
>>> fl
ForwardList([1])
Expand source code
def remove(self,value):
    """Remove elements with given value from list.

    Args:
        value : The value which has to be removed

    Raises:
        ARgorithmError: Raised if list is empty

    Example:

        >>> fl
        ForwardList([2, 2, 1])
        >>> fl.remove(2)
        >>> fl
        ForwardList([1])
    """
    if self.head is None:
        raise ARgorithmError("Empty list")
    while value == self.head.value:
        temp = self.head
        self.head = self.head.next
        del temp
        self.size -= 1
        if self.head is None:
            return
    curr = self.head
    while curr:
        if curr.next:
            if curr.next.value == value:
                temp = curr.next
                curr.next = curr.next.next
                del temp
                self.size -= 1
                continue
        curr = curr.next
def tolist(self)

Converts the ForwardList to python list.

Returns

list
list of ForwardList items

Example

>>> fl
ForwardList([3, 1])
>>> fl.tolist()
[3, 1]
Expand source code
def tolist(self):
    """Converts the ForwardList to python list.

    Returns:
        list: list of ForwardList items

    Example:

        >>> fl
        ForwardList([3, 1])
        >>> fl.tolist()
        [3, 1]
    """
    curr = self.head
    data = []
    while curr:
        data.append(curr.value)
        curr = curr.next
    return data

Inherited members

class ForwardListIterator (forwardlist)

This class is a generator that is returned each time an ForwardList has to be iterated.

Yields

Value of ForwardList Node

Raises

AssertionError
If not declared with an instance of ARgorithmToolkit.linkedlist.ForwardList
Expand source code
class ForwardListIterator:
    """This class is a generator that is returned each time an ForwardList has
    to be iterated.

    Yields:
        Value of ForwardList Node

    Raises:
        AssertionError: If not declared with an instance of ARgorithmToolkit.linkedlist.ForwardList
    """
    def __init__(self,forwardlist):
        assert isinstance(forwardlist,ForwardList)
        self._curr = forwardlist.head

    def __next__(self):
        if self._curr:
            data = self._curr.value
            self._curr = self._curr.next
            return data
        raise StopIteration
class LinkedList (name: str, algo: StateSet, head=None, comments='')

The LinkedList class is used to just store the head of the linked list.

This class is useful when programmer want to program his own List class using the nodes. Only contains head attribute and no methods

Attributes

name : str
The name given to the linkedlist
algo : StateSet
The stateset that will store the states generated by the instance of LinkedList Class
head : LinkedListNode
The referece to head of linkedlist

Raises

ARgorithmError
Raised if algo is not of type StateSet

Example

>>> ll = ARgorithmToolkit.LinkedList("llnode",algo)
>>> llnode = ARgorithmToolkit.LinkedListNode(algo,7)
>>> ll.head = llnode
Expand source code
class LinkedList(ARgorithmStructure, ARgorithmHashable):
    """The LinkedList class is used to just store the head of the linked list.

    This class is useful when programmer want to program his own List class using
    the nodes. Only contains head attribute and no methods

    Attributes:
        name (str): The name given to the linkedlist
        algo (ARgorithmToolkit.utils.StateSet): The stateset that will store the states generated by the instance of LinkedList Class
        head (LinkedListNode): The referece to head of linkedlist

    Raises:
        ARgorithmError: Raised if algo is not of type StateSet

    Example:

        >>> ll = ARgorithmToolkit.LinkedList("llnode",algo)
        >>> llnode = ARgorithmToolkit.LinkedListNode(algo,7)
        >>> ll.head = llnode
    """

    def __init__(self,name:str,algo:StateSet,head=None,comments=""):

        assert isinstance(name,str) , ARgorithmError("Name should be of type string")
        self.name = name
        self._id = str(id(self))
        try:
            assert isinstance(algo,StateSet)
            self.algo = algo
        except AssertionError as e:
            raise ARgorithmError("algo should be of type StateSet") from e
        self.state_generator = LinkedListState(self.name, self._id)

        self._flag = False
        if head:
            assert self.algo == head.algo, ARgorithmError("The head node belongs to a different StateSet")
        self.head = head
        self._flag = True

        state = self.state_generator.ll_declare(self.head,comments)
        self.algo.add_state(state)

    def __setattr__(self,key,value):
        """The __setattr__ function is overriden to listen to state changes in
        the head.

        Raises:
            ARgorithmError: Raised if head pointer is not type None or LinkedListNode
        """
        last_head = None
        if key == 'head' and value:
            assert isinstance(value,LinkedListNode) , ARgorithmError("next should be of type None or LinkedListNode")
        if key == 'head' and self._flag:
            last_head = self.head._id if self.head else "none"
        self.__dict__[key] = value
        if key == 'head' and self._flag:
            state = self.state_generator.ll_head(self.head,last_head=last_head, comments="head pointer shifts")
            self.algo.add_state(state)

    def __str__(self):
        return f"LinkedList(head at {self.head})"

    def __repr__(self):
        return f"LinkedList(head at {self.head})"

Ancestors

Subclasses

Methods

def to_json(self)

Creates a string representing a reference to ARgorithmObject for use in application.

Expand source code
def to_json(self):
    """Creates a string representing a reference to ARgorithmObject for use
    in application."""
    class_name = type(self).__name__
    obj_id = id(self)
    return f"$ARgorithmToolkit.{class_name}:{obj_id}"
class LinkedListNode (algo: StateSet, value=None, comments='')

The LinkedListNode class is an implementation of a Linked list Node for which we store states. Unlike other data structure classes, in which we have to give a name to the instance, we dont have to provide name in the LinkedListNode Class.

Attributes

algo : StateSet
The stateset that will store the states generated by the instance of LinkedListNode Class
value
The value stored in the node
next : LinkedListNode
The reference to next node

Raises

ARgorithmError
Raised if algo is not of type StateSet

Example

>>> llnode = ARgorithmToolkit.LinkedListNode(algo,7)
>>> llnode.value = 10
>>> temp = = ARgorithmToolkit.LinkedListNode(algo,7)
>>> temp.next = llnode
>>> llnode = temp
Expand source code
class LinkedListNode(ARgorithmStructure, ARgorithmHashable):
    """The LinkedListNode class is an implementation of a Linked list Node for
    which we store states. Unlike other data structure classes, in which we
    have to give a name to the instance, we dont have to provide name in the
    LinkedListNode Class.

    Attributes:
        algo (ARgorithmToolkit.utils.StateSet): The stateset that will store the states generated by the instance of LinkedListNode Class
        value: The value stored in the node
        next (LinkedListNode): The reference to next node

    Raises:
        ARgorithmError: Raised if algo is not of type StateSet

    Example:

        >>> llnode = ARgorithmToolkit.LinkedListNode(algo,7)
        >>> llnode.value = 10
        >>> temp = = ARgorithmToolkit.LinkedListNode(algo,7)
        >>> temp.next = llnode
        >>> llnode = temp
    """

    def __init__(self,algo:StateSet,value=None,comments=""):
        self.name = str(id(self))
        self._id = str(id(self))
        try:
            assert isinstance(algo,StateSet)
            self.algo = algo
        except AssertionError as e:
            raise ARgorithmError("algo should be of type StateSet") from e

        self.state_generator = LinkedListNodeState(self.name, self._id)

        self._flag = False
        self.value = value
        self.next = None
        self._flag = True

        state = self.state_generator.llnode_declare(
            self.value,self.next,comments
        )
        self.algo.add_state(state)

    def __setattr__(self,key,value):
        """The __setattr__ function is overriden to listen to state changes in
        the value of node or the next attribute.

        Raises:
            ARgorithmError: Raised if next pointer is not type None or LinkedListNode
        """
        if key == 'next' and value:
            assert isinstance(value,LinkedListNode) , ARgorithmError("next should be of type None or LinkedListNode")
        last_value = None
        last_next = None
        if key == 'value' and self._flag:
            last_value = self.value
        elif key == 'next' and self._flag:
            last_next = self.next
        self.__dict__[key] = value
        if key == 'next' and self._flag:
            if last_next or self.next:
                state = self.state_generator.llnode_next(
                    value=self.value,
                    _next=self.next,
                    last_next=last_next,
                    comments="next pointer updated"
                )
                self.algo.add_state(state)
        elif key == 'value' and self._flag:
            state = self.state_generator.llnode_iter(
                value=self.value,
                _next=self.next,
                last_value=last_value,
                comments="value updated"
            )
            self.algo.add_state(state)

    def __del__(self):
        """The __del__ function is overriden is there to listen to node
        deletion."""
        state = self.state_generator.llnode_delete(
            "Node was deleted"
        )
        self.algo.add_state(state)

    def __str__(self):
        return f"LinkedListNode({self.value}) at {self.name}"

    def __repr__(self):
        return f"LinkedListNode({self.value}) at {self.name}"

Ancestors

Methods

def to_json(self)

Creates a string representing a reference to ARgorithmObject for use in application.

Expand source code
def to_json(self):
    """Creates a string representing a reference to ARgorithmObject for use
    in application."""
    class_name = type(self).__name__
    obj_id = id(self)
    return f"$ARgorithmToolkit.{class_name}:{obj_id}"
class LinkedListNodeState (name: str, _id: str)

This class is used to generate states for various actions performed on the LinkedListNode object.

Attributes

name (str) : Name of the variable for whom we are generating states _id (str) : id of the variable for whom we are generating states

Expand source code
class LinkedListNodeState:
    """This class is used to generate states for various actions performed on
    the ``ARgorithmToolkit.linkedlist.LinkedListNode`` object.

    Attributes:

        name (str) : Name of the variable for whom we are generating states
        _id (str) : id of the variable for whom we are generating states
    """

    def __init__(self,name:str,_id:str):
        self.name = name
        self._id = _id

    def llnode_declare(self,value,_next,comments=""):
        """Generates the `llnode_declare` state when a new node is created.

        Args:
            value : The value stored in the linkedlist node
            next (LinkedListNode): The next pointer
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `llnode_declare` state
        """
        state_type = "llnode_declare"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "value" : value,
            "next" : _next.name if _next else "none"
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def llnode_iter(self,value,_next,last_value=None,comments=""):
        """Generates the `llnode_iter` state when a node is accessed or its
        value is changed.

        Args:
            value : The value stored in the linkedlist node
            next (LinkedListNode): The next pointer
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `llnode_iter` state
        """
        state_type = "llnode_iter"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "value" : value,
            "next" : _next.name if _next else "none"
        }
        if not(last_value is None):
            state_def["last_value"] = last_value
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def llnode_next(self,value,_next,last_next,comments=""):
        """Generates the `llnode_next` state when the next pointer changes.

        Args:
            value : The value stored in the linkedlist node
            next (LinkedListNode): The next pointer
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `llnode_next` state
        """
        state_type = "llnode_next"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "value" : value,
            "next" : _next.name if _next else "none",
            "last_next" : last_next.name if last_next else "none"
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def llnode_delete(self,comments=""):
        """Generates the `llnode_delete` state when a node is deleted.

        Args:
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `llnode_delete` state
        """
        state_type = "llnode_delete"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

Methods

def llnode_declare(self, value, _next, comments='')

Generates the llnode_declare state when a new node is created.

Args

value : The value stored in the linkedlist node
next : LinkedListNode
The next pointer
comments : str, optional
Comments for descriptive purpose. Defaults to "".

Returns

State
Returns the llnode_declare state
Expand source code
def llnode_declare(self,value,_next,comments=""):
    """Generates the `llnode_declare` state when a new node is created.

    Args:
        value : The value stored in the linkedlist node
        next (LinkedListNode): The next pointer
        comments (str, optional): Comments for descriptive purpose. Defaults to "".

    Returns:
        State: Returns the `llnode_declare` state
    """
    state_type = "llnode_declare"
    state_def = {
        "id" : self._id,
        "variable_name" : self.name,
        "value" : value,
        "next" : _next.name if _next else "none"
    }
    return State(
        state_type=state_type,
        state_def=state_def,
        comments=comments
    )
def llnode_delete(self, comments='')

Generates the llnode_delete state when a node is deleted.

Args

comments : str, optional
Comments for descriptive purpose. Defaults to "".

Returns

State
Returns the llnode_delete state
Expand source code
def llnode_delete(self,comments=""):
    """Generates the `llnode_delete` state when a node is deleted.

    Args:
        comments (str, optional): Comments for descriptive purpose. Defaults to "".

    Returns:
        State: Returns the `llnode_delete` state
    """
    state_type = "llnode_delete"
    state_def = {
        "id" : self._id,
        "variable_name" : self.name,
    }
    return State(
        state_type=state_type,
        state_def=state_def,
        comments=comments
    )
def llnode_iter(self, value, _next, last_value=None, comments='')

Generates the llnode_iter state when a node is accessed or its value is changed.

Args

value : The value stored in the linkedlist node
next : LinkedListNode
The next pointer
comments : str, optional
Comments for descriptive purpose. Defaults to "".

Returns

State
Returns the llnode_iter state
Expand source code
def llnode_iter(self,value,_next,last_value=None,comments=""):
    """Generates the `llnode_iter` state when a node is accessed or its
    value is changed.

    Args:
        value : The value stored in the linkedlist node
        next (LinkedListNode): The next pointer
        comments (str, optional): Comments for descriptive purpose. Defaults to "".

    Returns:
        State: Returns the `llnode_iter` state
    """
    state_type = "llnode_iter"
    state_def = {
        "id" : self._id,
        "variable_name" : self.name,
        "value" : value,
        "next" : _next.name if _next else "none"
    }
    if not(last_value is None):
        state_def["last_value"] = last_value
    return State(
        state_type=state_type,
        state_def=state_def,
        comments=comments
    )
def llnode_next(self, value, _next, last_next, comments='')

Generates the llnode_next state when the next pointer changes.

Args

value : The value stored in the linkedlist node
next : LinkedListNode
The next pointer
comments : str, optional
Comments for descriptive purpose. Defaults to "".

Returns

State
Returns the llnode_next state
Expand source code
def llnode_next(self,value,_next,last_next,comments=""):
    """Generates the `llnode_next` state when the next pointer changes.

    Args:
        value : The value stored in the linkedlist node
        next (LinkedListNode): The next pointer
        comments (str, optional): Comments for descriptive purpose. Defaults to "".

    Returns:
        State: Returns the `llnode_next` state
    """
    state_type = "llnode_next"
    state_def = {
        "id" : self._id,
        "variable_name" : self.name,
        "value" : value,
        "next" : _next.name if _next else "none",
        "last_next" : last_next.name if last_next else "none"
    }
    return State(
        state_type=state_type,
        state_def=state_def,
        comments=comments
    )
class LinkedListState (name: str, _id: str)

This class is used to generate states for various actions performed on the LinkedList object.

Attributes

name (str) : Name of the variable for whom we are generating states _id (str) : id of the variable for whom we are generating states

Expand source code
class LinkedListState:
    """This class is used to generate states for various actions performed on
    the ``ARgorithmToolkit.linkedlist.LinkedList`` object.

    Attributes:

        name (str) : Name of the variable for whom we are generating states
        _id (str) : id of the variable for whom we are generating states
    """
    def __init__(self,name:str,_id:str):
        self.name = name
        self._id = _id

    def ll_declare(self,head,comments=""):
        """Generates the `ll_declare` state when a new linkedlist is created.

        Args:
            head (LinkedListNode): The head pointer
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `ll_declare` state
        """
        state_type = "ll_declare"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "head" : head.name if head else "none"
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def ll_head(self,head,last_head=None,comments=""):
        """Generates the `ll_head` state when linkedlist head is changed.

        Args:
            head (LinkedListNode): The head pointer
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `ll_head` state
        """
        state_type = "ll_head"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "head" : head.name if head else "none"
        }
        if not (last_head is None):
            state_def["last_head"] = last_head
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

Methods

def ll_declare(self, head, comments='')

Generates the ll_declare state when a new linkedlist is created.

Args

head : LinkedListNode
The head pointer
comments : str, optional
Comments for descriptive purpose. Defaults to "".

Returns

State
Returns the ll_declare state
Expand source code
def ll_declare(self,head,comments=""):
    """Generates the `ll_declare` state when a new linkedlist is created.

    Args:
        head (LinkedListNode): The head pointer
        comments (str, optional): Comments for descriptive purpose. Defaults to "".

    Returns:
        State: Returns the `ll_declare` state
    """
    state_type = "ll_declare"
    state_def = {
        "id" : self._id,
        "variable_name" : self.name,
        "head" : head.name if head else "none"
    }
    return State(
        state_type=state_type,
        state_def=state_def,
        comments=comments
    )
def ll_head(self, head, last_head=None, comments='')

Generates the ll_head state when linkedlist head is changed.

Args

head : LinkedListNode
The head pointer
comments : str, optional
Comments for descriptive purpose. Defaults to "".

Returns

State
Returns the ll_head state
Expand source code
def ll_head(self,head,last_head=None,comments=""):
    """Generates the `ll_head` state when linkedlist head is changed.

    Args:
        head (LinkedListNode): The head pointer
        comments (str, optional): Comments for descriptive purpose. Defaults to "".

    Returns:
        State: Returns the `ll_head` state
    """
    state_type = "ll_head"
    state_def = {
        "id" : self._id,
        "variable_name" : self.name,
        "head" : head.name if head else "none"
    }
    if not (last_head is None):
        state_def["last_head"] = last_head
    return State(
        state_type=state_type,
        state_def=state_def,
        comments=comments
    )