# Design of Linked List

```python
class Node(object):
    def __init__(self, value):
        self.val = value
        self.next = None


class MyLinkedList(object):
    def __init__(self):
        """
        Initialize your data structure here.
        dummy  0  1  2  3
        -217   x  y  z  alpha
        """
        # self.dummy = None # Common dude, dummy is a Node!!!!
        self.dummy = Node(-217) 

    def getNode(self, index):
        """
        Get the index-th node in the linked list.
        """
        if index < -1:  # if index is -1, dummy will be returned
            return None
        cur = self.dummy
        i = 0
        while i <= index and cur is not None:
            cur = cur.next
            i += 1
        return cur # if index is out of length, cur stopped at the tail->next: None. So that the corner case has been considered via the return part.

    def getTail(self):
        """
        Get the last node in the linked list.
        """
        cur = self.dummy
        while (cur is not None and cur.next is not None): # if the while loop criterion is set only via cur, then "cur" will be lastNode.next: None
            cur = cur.next
        return cur

    def get(self, index):
        """
        Get the value of the index-th node in the linked list. If the index is invalid, return -1.
        :type index: int
        :rtype: int
        """
        cur = self.getNode(index)
        if cur is not None:
            return cur.val
        else:
            return -1

    def addAtHead(self, val):
        """
        Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
        :type val: int
        :rtype: void
        """
        cur = Node(val)
        #if self.length == 0:
        #    self.dummy.next = cur
        #else:
        #    cur.next = self.dummy.next  # constantly check whether each "next" you write is valid.
        #    self.dummy.next = cur
        cur.next = self.dummy.next
        self.dummy.next = cur

    def addAtTail(self, val):
        """
        Append a node of value val to the last element of the linked list.
        :type val: int
        :rtype: void
        """

        #if self.length == 0:
        #    self.addAtHead(val)
        #else:
        #    cur = Node(val)
        #    self.tail.next = cur  # constantly check whether each "next" is valid
        #    self.tail = cur
        if self.dummy.next is None:
            self.addAtHead(val)
        else:
            tail = self.getTail()
            cur = Node(val)
            tail.next = cur
        
    def addAtIndex(self, index, val):
        """
        Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
        :type index: int
        :type val: int
        :rtype: void
        """
        pre = self.getNode(index - 1) # when index is 0, it should be checked and direct to use add head. but since we can index the dummy via -1, our implementation also works fine.
        if pre is None:
            return
        cur = Node(val)
        cur.next = pre.next
        pre.next = cur


    def deleteAtIndex(self, index):
        """
        Delete the index-th node in the linked list, if the index is valid.
        :type index: int
        :rtype: void
        """
        pre = self.getNode(index - 1)
        if self.dummy.next is None or pre is None or pre.next is None: # if there is no node in the linked list; or if pre is None (index out of [-1, length - 1]); or the pre is the (length - 1)th node (because there would be no pre.next.next).
            return
        pre.next = pre.next.next



# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
```
