---
# System prepended metadata

title: Singly Linked List

---

# Singly Linked List

#### Linked List - 101

#### Linked List vs Arrays

#### Basic propperties:

- [x]  Print all the nodes in a given linked list.
- [x]  Give the length of the linked list 
- [x]  Print the data at a particular position of the linked list.
- [x]  Reverse a linked list.
- [ ]  Node swap
- [ ]  Remove Duplicates

#### Common Practice Problems: 


#### Cycle Detection: Floyd Algo


* [Practice Problem: Given a linked list, determine if it has a cycle in it.](https://leetcode.com/problems/linked-list-cycle/)
---


#### Linked List 

```python=
class Node:
    def __init__(self, data = 0, next = None):
        self.data = data
        self.next = next
```
The basic building block of any Linked List is the base class which generally holds two very useful information. 

* `self.data`: This is to store the data in the node. 
* `self.next`: This acts as a pointer to the next node.

#### Linked List vs Arrays

![](https://i.imgur.com/gFRNcQ6.png)


#### Insertion: 

##### **Inserting at the end of the node**

```python=
class LinkedList:
    def __init__(self):
        self.head = None
    
    def append(self, data):
        # creating a node
        new_node = Node(data)
        
        # Checking if the current head is None
        if self.head is None:
            self.head = new_node
            return

        last_node = self.head
        while last_node.next:
            last_node = last_node.next
        last_node.next = new_node
```

##### **Inserting at the start of th node**

```python=
    def prepend(self, data):
        new_node = Node(data)

        new_node.next = self.head
        self.head = new_node

```

##### **Inserting at the after a given node**

```python=
    def insert_after_node(self, prev_node, data):
        if not prev_node:
            return "Previous node is not in the list"

        new_node = Node(data)

        new_node.next = prev_node.next
        prev_node.next = new_node
```

#### Deletion:

##### **Deleting a particluar node**

```python=
class LinkedList:
    def __init__(self):
        self.head = None
    
    def delete_node(self, key):

        cur_node = self.head
        
        # If head of the node is to be deleted
        if cur_node and cur_node.data == key:
            self.head = cur_node.next
            cur_node = None
            return

        prev = None 
        # Iterate and find the node to be delted
        while cur_node and cur_node.data != key:
            prev = cur_node
            cur_node = cur_node.next
        # Node is not in the Linked List
        if cur_node is None:
            return 

        prev.next = cur_node.next
        cur_node = None
```

##### **Deleting a particluar position**

```python=
    def delete_node_at_pos(self, pos):

        cur_node = self.head

        if pos == 0:
            self.head = cur_node.next
            cur_node = None
            return

        prev = None
        count = 0
        while cur_node and count != pos:
            prev = cur_node 
            cur_node = cur_node.next
            count += 1

        if cur_node is None:
            return 

        prev.next = cur_node.next
        cur_node = None
```

#### Cycle Detection

* For cycle detection we would need two pointers. One would be slow i.e `slowptr` and the other would be fast i.e `fastptr`. 
* The `slowptr` moves one position per index and the `fastptr` moves two position per index.
* To check if the LinkedList has a cycle is  when the the `fastptr` won't reach the end of the list and would eventually overlap the `slowptr` during the iteration.
* If `slowptr` equals the `fastptr` the given Linked List has a cycle. 

![](https://i.imgur.com/wctFjtC.png)

```python=
def hasCycle(self, head):
    if head is None:
        return False
    
    slowptr = head
    fastptr = head.next
    
    """
    Checking if slowptr, fastptr and fastptr.next values exsits and are not None. 
    Otherwise the increment of slowptr and fastptr would give None and fail.
    """
    while slowptr is not None and fastptr is not None and fastptr.next is not None:
        if slowptr == fastptr:
            return True
        slowptr = slowptr.next
        fastptr = fastptr.next.next
    
    return False
```
