# Data structure -- linked list

Keywords: Python data structure linked list

Single linked list: a linked list refers to a linear structure connected in series through pointers. Each node consists of two parts, one is the data field, the other is the pointer field (storing pointers to the next node), and the pointer field of the last node points to null (null pointer).
Double linked list: each node has two pointer fields, one pointing to the next node and the other pointing to the previous node.
Double linked list can be queried forward or backward.
Storage mode of linked list: the linked list is not continuously distributed in memory. The linked list is linked to each node in memory through the pointer of the pointer field. That is, the linked list is scattered on an address in memory.

```class ListNode:
def __init__(self, val):
self.val = val
self.next = None
```

Delete all nodes in the linked list equal to the given value val.

```# Input: head = [1,2,6,3,4,5,6], val = 6
# Output: [1,2,3,4,5]

while pre:
if pre.next and pre.next.val == val:
pre.next = pre.next.next
else:
pre = pre.next
```

Example: input: 1 - > 2 - > 3 - > 4 - > 5 - > null output: 5 - > 4 - > 3 - > 2 - > 1 - > null

```def solution(head):
pre = None
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp

return pre
```

# Exchange the nodes in the linked list

Given a linked list, two adjacent nodes are exchanged, and the exchanged linked list is returned. You can't just change the value inside the node, but you need to actually exchange nodes.
Output: [2,1,4,3]

```def solution(head):
pre = ListNode(-1)
res = pre
while pre.next and pre.next.next:
cur = pre.next
tmp = pre.next.next

cur.next = tmp.next
pre.next = tmp
tmp.next = cur

pre = pre.next.next
return res.next
```

# Delete the penultimate node of the linked list

Advanced: can you try using one scan?
Input: head = [1,2,3,4,5], n = 2 output: [1,2,3,5]

```def solution(head, n):
pre = ListNode(0)
slow, fast = pre, pre
for i in range(n):
fast = fast.next
while fast:
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return pre.next
```

Given two (one-way) linked lists, determine whether they intersect and return the intersection. Note that the definition of intersection is based on the reference of the node, not the value of the node. In other words, if the k-th node of a linked list and the j-th node of another linked list are the same node (the references are exactly the same), the two linked lists intersect.
Input: listA = [4,1,8,4,5], listB = [5,0,1,8,4,5]
Output: Reference of the node with value = 8

```def solution(heada, headb):
while cur_a != cur_b:
cur_a = cur_a.next if cur_a else headb
cur_b = cur_b.next if cur_b else heada
return cur_a
```

Given a linked list, return the first node from the linked list into the ring. If the linked list is acyclic, null is returned.

In order to represent the rings in a given linked list, the integer pos is used to represent the position where the tail of the linked list is connected to the linked list (the index starts from 0). If pos is - 1, there is no ring in the linked list.

```def solution(head):
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
q = slow
while p != q:
p = p.next
q = q.next
return p
return None
```

Implement these functions in the linked list class:

get(index): get the value of the index node in the linked list. Returns - 1 if the index is invalid.
addAtHead(val): add a node with value val before the first element of the linked list. After insertion, the new node will become the first node in the linked list.
addAtTail(val): append the node with value val to the last element of the linked list.
addAtIndex(index,val): add a node with value val before the index node in the linked list. If the index is equal to the length of the linked list, the node will be attached to the end of the linked list. If the index is greater than the length of the linked list, the node will not be inserted. If the index is less than 0, the node is inserted in the header.
Delete atindex (index): if the index is valid, delete the index node in the linked list.

```# Single linked list
class ListNode:
def __init__(self,val):
self.val = val
self.next = None

def __init__(self):
self._count = 0
def get(self, index):
if 0 <= index < self._count:
for _ in range(index+1):
node = node.next
return node
else:
return -1
if index < 0:
index = 0
elif index > self._count:
return
self._count += 1
for _ in range(index + 1):
pre_node, cur_node = cur_node, cur_node.next
else:
def delAIndex(self, index):
if 0 <= index < self.count:
self._count -= 1
for _ in range(index+1):
pre_node, cur_node = cur_node, cur_node.next
else:
pre_node, cur_node = cur_node.next, None

class Node:

def __init__(self, val):
self.val = val
self.prev = None
self.next = None

def __init__(self):
self._head, self._tail = Node(0), Node(0)  # Virtual node
self._count = 0  # Number of nodes added

def _get_node(self, index: int) -> Node:
# When index is less than_ When count//2, use_ head lookup is faster, and vice versa_ tail faster
if index >= self._count // 2:
# Use prev to find forward
node = self._tail
for _ in range(self._count - index):
node = node.prev
else:
# Use next to look back
for _ in range(index + 1):
node = node.next
return node

def get(self, index: int) -> int:
"""
Get the value of the index-th node in the linked list. If the index is invalid, return -1.
"""
if 0 <= index < self._count:
node = self._get_node(index)
return node.val
else:
return -1

"""
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.
"""

def addAtTail(self, val: int) -> None:
"""
Append a node of value val to the last element of the linked list.
"""
self._update(self._tail.prev, self._tail, val)

def addAtIndex(self, index: int, val: int) -> None:
"""
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.
"""
if index < 0:
index = 0
elif index > self._count:
return
node = self._get_node(index)
self._update(node.prev, node, val)

def _update(self, prev: Node, next: Node, val: int) -> None:
"""
Update node
:param prev: Relative to the previous node of the update
:param next: Relative to the last node updated
:param val:  Node value to add
"""
# Count accumulation
self._count += 1
node = Node(val)
prev.next, next.prev = node, node
node.prev, node.next = prev, next

def deleteAtIndex(self, index: int) -> None:
"""
Delete the index-th node in the linked list, if the index is valid.
"""
if 0 <= index < self._count:
node = self._get_node(index)
# Count - 1
self._count -= 1
node.prev.next, node.next.prev = node.next, node.prev
```

Posted by kks_krishna on Wed, 06 Oct 2021 21:12:57 -0700