Data structure -- linked list

Keywords: Python data structure linked list

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).
The entry node of the linked list is called the head node of the linked list, that is, head.
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.
Circular list: linked list.
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.
Linked list definition:

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

Remove linked list elements

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]

def solution(head, val):
	pre_head = ListNode(-1)
    pre_head.next = head
    pre = pre_head
    while pre:
        if pre.next and pre.next.val == val:
            pre.next = pre.next.next
        else:
            pre = pre.next
    return pre_head.next	

Reverse linked list

Reverse a single linked list.
Example: input: 1 - > 2 - > 3 - > 4 - > 5 - > null output: 5 - > 4 - > 3 - > 2 - > 1 - > null

def solution(head):
	pre = None
	cur = head
	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.
Input: head = [1,2,3,4]
Output: [2,1,4,3]

def solution(head):
	pre = ListNode(-1)
	pre.next = head
	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

Give you a linked list, delete the penultimate node of the linked list, and return the head 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)
	pre.next = head
	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

Linked list intersection

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):
	cur_a, cur_b = 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

Circular linked list II

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):
	slow, fast = head, head
	while fast and fast.next:
		slow = slow.next
		fast = fast.next.next
		if slow == fast:
			p = head
			q = slow
			while p != q:
				p = p.next
				q = q.next
			return p
	return None

Design a linked list

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

class MyLinkedList:
	def __init__(self):
		self._head = ListNode(0)
		self._count = 0
	def get(self, index):
		if 0 <= index < self._count:
			node = self._head
			for _ in range(index+1):
				node = node.next
			return node
		else:
			return -1
	def addAHead(self, val):
		self.addAIndex(0, val)
	def addATail(self, val):
		self.addAIndex(self._count, val)
	def addAIndex(self, index, val):
		if index < 0:
			index = 0
		elif index > self._count:
			return
		self._count += 1
		add_node = ListNode(val)
		pre_node, cur_node = None, self._head
		for _ in range(index + 1):
			pre_node, cur_node = cur_node, cur_node.next
		else:
			pre_node.next, add_node.next = add_node, cur_node
	def delAIndex(self, index):
		if 0 <= index < self.count:
			self._count -= 1
			pre_node, cur_node = None, self.head
		for _ in range(index+1):
			pre_node, cur_node = cur_node, cur_node.next
		else:
			pre_node, cur_node = cur_node.next, None

# Double linked list
# Compared with single linked list, Node adds prev attribute
class Node:
    
    def __init__(self, val):
        self.val = val
        self.prev = None
        self.next = None


class MyLinkedList:

    def __init__(self):
        self._head, self._tail = Node(0), Node(0)  # Virtual node
        self._head.next, self._tail.prev = self._tail, self._head
        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
            node = self._head   
            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

    def addAtHead(self, val: int) -> None:
        """
        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.
        """
        self._update(self._head, self._head.next, val)

    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