From dd57c9014871177ea93853e14bc2fa3f83265024 Mon Sep 17 00:00:00 2001 From: IneshAg Date: Wed, 22 Oct 2025 22:16:20 +0530 Subject: [PATCH 1/6] Add XOR Linked List implementation with doctests --- .../linked_list/xor_linked_list.py | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 data_structures/linked_list/xor_linked_list.py diff --git a/data_structures/linked_list/xor_linked_list.py b/data_structures/linked_list/xor_linked_list.py new file mode 100644 index 000000000000..ead7d3d0dc8b --- /dev/null +++ b/data_structures/linked_list/xor_linked_list.py @@ -0,0 +1,58 @@ +""" +XOR Linked List implementation + +A memory-efficient doubly linked list using XOR of node addresses. +Each node stores one pointer that is the XOR of previous and next node addresses. + +Example: +>>> xor_list = XORLinkedList() +>>> xor_list.insert(10) +>>> xor_list.insert(20) +>>> xor_list.insert(30) +>>> xor_list.to_list() +[10, 20, 30] +""" + +from typing import Optional + + +class Node: + def __init__(self, value: int): + self.value = value + self.both: int = 0 # XOR of prev and next node ids + + +class XORLinkedList: + def __init__(self): + self.head: Optional[Node] = None + self.tail: Optional[Node] = None + self._nodes = {} # id → node map to simulate pointer references + + def _xor(self, a: Optional[Node], b: Optional[Node]) -> int: + return (id(a) if a else 0) ^ (id(b) if b else 0) + + def insert(self, value: int) -> None: + node = Node(value) + self._nodes[id(node)] = node + if self.head is None: + self.head = self.tail = node + else: + node.both = id(self.tail) + self.tail.both ^= id(node) + self.tail = node + + def to_list(self) -> list[int]: + result = [] + prev_id = 0 + current = self.head + while current: + result.append(current.value) + next_id = prev_id ^ current.both + prev_id = id(current) + current = self._nodes.get(next_id) + return result + + +if __name__ == "__main__": + import doctest + doctest.testmod() From 02407fc930d4b956cf434a2290cf84aca4bf2352 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 22 Oct 2025 16:52:22 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/linked_list/xor_linked_list.py | 1 + 1 file changed, 1 insertion(+) diff --git a/data_structures/linked_list/xor_linked_list.py b/data_structures/linked_list/xor_linked_list.py index ead7d3d0dc8b..5d478bb293dd 100644 --- a/data_structures/linked_list/xor_linked_list.py +++ b/data_structures/linked_list/xor_linked_list.py @@ -55,4 +55,5 @@ def to_list(self) -> list[int]: if __name__ == "__main__": import doctest + doctest.testmod() From a96c4d55f8b54809106b260c800e55970ff7ab69 Mon Sep 17 00:00:00 2001 From: IneshAg Date: Wed, 22 Oct 2025 22:23:15 +0530 Subject: [PATCH 3/6] Add XOR Linked List implementation with doctests --- data_structures/linked_list/xor_linked_list.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data_structures/linked_list/xor_linked_list.py b/data_structures/linked_list/xor_linked_list.py index ead7d3d0dc8b..266a95f0f1bd 100644 --- a/data_structures/linked_list/xor_linked_list.py +++ b/data_structures/linked_list/xor_linked_list.py @@ -17,17 +17,18 @@ class Node: - def __init__(self, value: int): + def __init__(self, value: int) -> None: self.value = value self.both: int = 0 # XOR of prev and next node ids class XORLinkedList: - def __init__(self): + def __init__(self) -> None: self.head: Optional[Node] = None self.tail: Optional[Node] = None self._nodes = {} # id → node map to simulate pointer references + def _xor(self, a: Optional[Node], b: Optional[Node]) -> int: return (id(a) if a else 0) ^ (id(b) if b else 0) From 695649780026391870202303a381286ee664ac0d Mon Sep 17 00:00:00 2001 From: IneshAg Date: Wed, 22 Oct 2025 22:25:33 +0530 Subject: [PATCH 4/6] Add XOR Linked List implementation with doctests --- .../linked_list/xor_linked_list.py | 90 +++++++++++++++---- 1 file changed, 74 insertions(+), 16 deletions(-) diff --git a/data_structures/linked_list/xor_linked_list.py b/data_structures/linked_list/xor_linked_list.py index 266a95f0f1bd..cd260dd9ace1 100644 --- a/data_structures/linked_list/xor_linked_list.py +++ b/data_structures/linked_list/xor_linked_list.py @@ -1,9 +1,7 @@ """ XOR Linked List implementation - A memory-efficient doubly linked list using XOR of node addresses. Each node stores one pointer that is the XOR of previous and next node addresses. - Example: >>> xor_list = XORLinkedList() >>> xor_list.insert(10) @@ -13,47 +11,107 @@ [10, 20, 30] """ -from typing import Optional +# Note: This implementation simulates pointer behavior using Python's id() +# and a dictionary lookup (_nodes). In languages like C, this would +# be done with actual memory addresses and pointer arithmetic. class Node: - def __init__(self, value: int) -> None: + def __init__(self, value: int): self.value = value self.both: int = 0 # XOR of prev and next node ids class XORLinkedList: - def __init__(self) -> None: - self.head: Optional[Node] = None - self.tail: Optional[Node] = None - self._nodes = {} # id → node map to simulate pointer references + def __init__(self): + # Use 'Node | None' instead of 'Optional[Node]' (per ruff UP045) + self.head: Node | None = None + self.tail: Node | None = None + # id -> node map to simulate pointer references + # In a low-level language, we would just store/use the memory addresses. + self._nodes: dict[int, Node] = {} + def _get_node(self, node_id: int) -> Node | None: + """Helper to retrieve a node by its simulated ID.""" + return self._nodes.get(node_id) - def _xor(self, a: Optional[Node], b: Optional[Node]) -> int: - return (id(a) if a else 0) ^ (id(b) if b else 0) + def _get_id(self, node: Node | None) -> int: + """Helper to get the simulated ID (address) of a node.""" + return id(node) if node else 0 + + def _xor(self, a: Node | None, b: Node | None) -> int: + """Helper to XOR the IDs (addresses) of two nodes.""" + # Use 'Node | None' instead of 'Optional[Node]' (per ruff UP045) + return self._get_id(a) ^ self._get_id(b) def insert(self, value: int) -> None: + """Inserts a value at the end of the list.""" node = Node(value) + # Store the node in our simulated memory self._nodes[id(node)] = node + if self.head is None: - self.head = self.tail = node + # List is empty + self.head = node + self.tail = node + # node.both remains 0 (XOR of None and None) else: - node.both = id(self.tail) - self.tail.both ^= id(node) + # List is not empty, append to tail + # New node's 'both' points back to the old tail + node.both = self._get_id(self.tail) + + # Update the old tail's 'both' + # old_tail.both = (ID of node before old_tail) ^ (ID of new node) + # We can get (ID of node before old_tail) by doing: + # old_tail.both ^ (ID of next node, which was None/0) + # So, old_tail.both ^ 0 = old_tail.both + # new_tail.both = old_tail.both ^ self._get_id(node) + + # Simplified: + # self.tail.both was (ID of prev_node) ^ 0 + # We need it to be (ID of prev_node) ^ (ID of new node) + # So we XOR it with the new node's ID. + if self.tail: # Type checker guard + self.tail.both = self.tail.both ^ self._get_id(node) + + # Update the tail pointer self.tail = node def to_list(self) -> list[int]: + """Converts the XOR linked list to a standard Python list (forward).""" result = [] - prev_id = 0 current = self.head + prev_id = 0 # ID of the virtual 'None' node before head + while current: result.append(current.value) + + # Get the ID of the next node + # current.both = (ID of prev_node) ^ (ID of next_node) + # So, (ID of next_node) = (ID of prev_node) ^ current.both next_id = prev_id ^ current.both - prev_id = id(current) - current = self._nodes.get(next_id) + + # Move to the next node + prev_id = self._get_id(current) + current = self._get_node(next_id) + return result if __name__ == "__main__": import doctest + doctest.testmod() + + # Additional demonstration + xor_list = XORLinkedList() + xor_list.insert(10) + xor_list.insert(20) + xor_list.insert(30) + print(f"List contents: {xor_list.to_list()}") # Output: [10, 20, 30] + + # Verify head and tail + if xor_list.head: + print(f"Head value: {xor_list.head.value}") # Output: 10 + if xor_list.tail: + print(f"Tail value: {xor_list.tail.value}") # Output: 30 \ No newline at end of file From 08fd580cf726d9b9b64179215ccf18a4cc50d7d8 Mon Sep 17 00:00:00 2001 From: IneshAg Date: Wed, 22 Oct 2025 22:27:03 +0530 Subject: [PATCH 5/6] Add XOR Linked List implementation with doctests --- .../linked_list/xor_linked_list.py | 97 ++++++------------- 1 file changed, 29 insertions(+), 68 deletions(-) diff --git a/data_structures/linked_list/xor_linked_list.py b/data_structures/linked_list/xor_linked_list.py index cd260dd9ace1..7cbcd6ea17ad 100644 --- a/data_structures/linked_list/xor_linked_list.py +++ b/data_structures/linked_list/xor_linked_list.py @@ -11,107 +11,68 @@ [10, 20, 30] """ -# Note: This implementation simulates pointer behavior using Python's id() -# and a dictionary lookup (_nodes). In languages like C, this would -# be done with actual memory addresses and pointer arithmetic. +# Note: 'from typing import Optional' is no longer needed +# as we use the modern 'Node | None' syntax. class Node: - def __init__(self, value: int): + def __init__(self, value: int) -> None: + """Initializes a Node with a value and a null pointer.""" self.value = value self.both: int = 0 # XOR of prev and next node ids class XORLinkedList: - def __init__(self): - # Use 'Node | None' instead of 'Optional[Node]' (per ruff UP045) + def __init__(self) -> None: + """Initializes an empty XOR Linked List.""" self.head: Node | None = None self.tail: Node | None = None # id -> node map to simulate pointer references - # In a low-level language, we would just store/use the memory addresses. self._nodes: dict[int, Node] = {} - def _get_node(self, node_id: int) -> Node | None: - """Helper to retrieve a node by its simulated ID.""" - return self._nodes.get(node_id) - - def _get_id(self, node: Node | None) -> int: - """Helper to get the simulated ID (address) of a node.""" - return id(node) if node else 0 - def _xor(self, a: Node | None, b: Node | None) -> int: - """Helper to XOR the IDs (addresses) of two nodes.""" - # Use 'Node | None' instead of 'Optional[Node]' (per ruff UP045) - return self._get_id(a) ^ self._get_id(b) + """Helper function to get the XOR of two node IDs.""" + return (id(a) if a else 0) ^ (id(b) if b else 0) def insert(self, value: int) -> None: """Inserts a value at the end of the list.""" node = Node(value) - # Store the node in our simulated memory self._nodes[id(node)] = node if self.head is None: - # List is empty - self.head = node - self.tail = node - # node.both remains 0 (XOR of None and None) + # If the list is empty, head and tail are the new node + self.head = self.tail = node else: - # List is not empty, append to tail - # New node's 'both' points back to the old tail - node.both = self._get_id(self.tail) - - # Update the old tail's 'both' - # old_tail.both = (ID of node before old_tail) ^ (ID of new node) - # We can get (ID of node before old_tail) by doing: - # old_tail.both ^ (ID of next node, which was None/0) - # So, old_tail.both ^ 0 = old_tail.both - # new_tail.both = old_tail.both ^ self._get_id(node) - - # Simplified: - # self.tail.both was (ID of prev_node) ^ 0 - # We need it to be (ID of prev_node) ^ (ID of new node) - # So we XOR it with the new node's ID. - if self.tail: # Type checker guard - self.tail.both = self.tail.both ^ self._get_id(node) - - # Update the tail pointer + # If the list is not empty, append to the tail + # The new node's pointer is just the ID of the old tail + node.both = id(self.tail) + if self.tail: # Type checker guard + # The old tail's pointer must be updated to XOR + # its previous node ID with the new node's ID. + # self.tail.both was (prev_id ^ 0) + # self.tail.both becomes (prev_id ^ new_node_id) + self.tail.both ^= id(node) self.tail = node def to_list(self) -> list[int]: - """Converts the XOR linked list to a standard Python list (forward).""" + """Converts the XOR list to a standard Python list (forward traversal).""" result = [] + prev_id = 0 current = self.head - prev_id = 0 # ID of the virtual 'None' node before head - while current: result.append(current.value) - - # Get the ID of the next node - # current.both = (ID of prev_node) ^ (ID of next_node) - # So, (ID of next_node) = (ID of prev_node) ^ current.both + # Find next node's ID: + # current.both = prev_id ^ next_id + # so, next_id = prev_id ^ current.both next_id = prev_id ^ current.both - - # Move to the next node - prev_id = self._get_id(current) - current = self._get_node(next_id) - + + # Move forward + prev_id = id(current) + current = self._nodes.get(next_id) return result if __name__ == "__main__": import doctest - doctest.testmod() - - # Additional demonstration - xor_list = XORLinkedList() - xor_list.insert(10) - xor_list.insert(20) - xor_list.insert(30) - print(f"List contents: {xor_list.to_list()}") # Output: [10, 20, 30] - - # Verify head and tail - if xor_list.head: - print(f"Head value: {xor_list.head.value}") # Output: 10 - if xor_list.tail: - print(f"Tail value: {xor_list.tail.value}") # Output: 30 \ No newline at end of file + doctest.testmod() \ No newline at end of file From 3d35bbc47c73a07b53305d556735bbf1650a5138 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 22 Oct 2025 17:05:16 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/linked_list/xor_linked_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/linked_list/xor_linked_list.py b/data_structures/linked_list/xor_linked_list.py index d60892bd7c5d..ee6fdf79452b 100644 --- a/data_structures/linked_list/xor_linked_list.py +++ b/data_structures/linked_list/xor_linked_list.py @@ -82,4 +82,4 @@ def to_list(self) -> list[int]: if __name__ == "__main__": import doctest - doctest.testmod() \ No newline at end of file + doctest.testmod()