Skip to content

Commit bde9150

Browse files
IneshAgpre-commit-ci[bot]cclauss
authored
Add XOR Linked List implementation with doctests (#13699)
* Add XOR Linked List implementation with doctests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add XOR Linked List implementation with doctests * Add XOR Linked List implementation with doctests * Add XOR Linked List implementation with doctests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * updating DIRECTORY.md * Refine docstring and variable comment in XOR linked list Updated docstring for clarity and corrected 'ids' to 'IDs'. * Refactor Node class to use dataclass Refactor Node class to use dataclass for cleaner syntax. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Christian Clauss <cclauss@me.com> Co-authored-by: cclauss <cclauss@users.noreply.github.com>
1 parent 0051e4e commit bde9150

2 files changed

Lines changed: 90 additions & 0 deletions

File tree

DIRECTORY.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@
181181
## [Computer Vision](computer_vision)
182182
* [Cnn Classification](computer_vision/cnn_classification.py)
183183
* [Flip Augmentation](computer_vision/flip_augmentation.py)
184+
* [Gramian](computer_vision/gramian.py)
184185
* [Haralick Descriptors](computer_vision/haralick_descriptors.py)
185186
* [Harris Corner](computer_vision/harris_corner.py)
186187
* [Horn Schunck](computer_vision/horn_schunck.py)
@@ -231,6 +232,7 @@
231232
* [Lempel Ziv](data_compression/lempel_ziv.py)
232233
* [Lempel Ziv Decompress](data_compression/lempel_ziv_decompress.py)
233234
* [Lz77](data_compression/lz77.py)
235+
* [Move To Front](data_compression/move_to_front.py)
234236
* [Peak Signal To Noise Ratio](data_compression/peak_signal_to_noise_ratio.py)
235237
* [Run Length Encoding](data_compression/run_length_encoding.py)
236238

@@ -324,16 +326,19 @@
324326
* [From Sequence](data_structures/linked_list/from_sequence.py)
325327
* [Has Loop](data_structures/linked_list/has_loop.py)
326328
* [Is Palindrome](data_structures/linked_list/is_palindrome.py)
329+
* [Kth Element From End](data_structures/linked_list/kth_element_from_end.py)
327330
* [Merge Sort Linked List](data_structures/linked_list/merge_sort_linked_list.py)
328331
* [Merge Two Lists](data_structures/linked_list/merge_two_lists.py)
329332
* [Middle Element Of Linked List](data_structures/linked_list/middle_element_of_linked_list.py)
333+
* [Partition Linked List](data_structures/linked_list/partition_linked_list.py)
330334
* [Print Reverse](data_structures/linked_list/print_reverse.py)
331335
* [Reverse K Group](data_structures/linked_list/reverse_k_group.py)
332336
* [Rotate To The Right](data_structures/linked_list/rotate_to_the_right.py)
333337
* [Singly Linked List](data_structures/linked_list/singly_linked_list.py)
334338
* [Skip List](data_structures/linked_list/skip_list.py)
335339
* [Sorted Linked List](data_structures/linked_list/sorted_linked_list.py)
336340
* [Swap Nodes](data_structures/linked_list/swap_nodes.py)
341+
* [Xor Linked List](data_structures/linked_list/xor_linked_list.py)
337342
* Queues
338343
* [Circular Queue](data_structures/queues/circular_queue.py)
339344
* [Circular Queue Linked List](data_structures/queues/circular_queue_linked_list.py)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""
2+
XOR Linked List implementation
3+
A memory-efficient doubly linked list that uses the XOR of node addresses.
4+
Each node stores one pointer that is the XOR of the previous and next node addresses.
5+
https://en.wikipedia.org/wiki/XOR_linked_list
6+
Example:
7+
>>> xor_list = XORLinkedList()
8+
>>> xor_list.insert(10)
9+
>>> xor_list.insert(20)
10+
>>> xor_list.insert(30)
11+
>>> xor_list.to_list()
12+
[10, 20, 30]
13+
"""
14+
15+
from dataclasses import dataclass
16+
17+
18+
@dataclass
19+
class Node:
20+
value: int
21+
both: int = 0 # XOR of prev and next node IDs
22+
23+
24+
class XORLinkedList:
25+
def __init__(self) -> None:
26+
"""Initializes an empty XOR Linked List."""
27+
# Use 'Node | None' instead of 'Optional[Node]' (per ruff UP045)
28+
self.head: Node | None = None
29+
self.tail: Node | None = None
30+
# id -> node map to simulate pointer references
31+
self._nodes: dict[int, Node] = {}
32+
33+
def _xor(self, node_a: Node | None, node_b: Node | None) -> int:
34+
"""
35+
Helper function to get the XOR of two node IDs (simulated addresses).
36+
Names 'node_a' and 'node_b' are used for descriptive parameters.
37+
"""
38+
id_a = id(node_a) if node_a else 0
39+
id_b = id(node_b) if node_b else 0
40+
return id_a ^ id_b
41+
42+
def insert(self, value: int) -> None:
43+
"""Inserts a value at the end of the list."""
44+
node = Node(value)
45+
self._nodes[id(node)] = node
46+
node_id = id(node)
47+
48+
if self.head is None:
49+
# If the list is empty, head and tail are the new node
50+
self.head = self.tail = node
51+
else:
52+
# If the list is not empty, append to the tail
53+
# The new node's pointer is just the ID of the old tail
54+
node.both = id(self.tail)
55+
if self.tail: # Type checker guard
56+
# The old tail's pointer must be updated to XOR
57+
# its previous node ID with the new node's ID.
58+
# self.tail.both was (prev_id ^ 0)
59+
# self.tail.both becomes (prev_id ^ new_node_id)
60+
self.tail.both ^= node_id
61+
self.tail = node
62+
63+
def to_list(self) -> list[int]:
64+
"""Converts the XOR list to a standard Python list (forward traversal)."""
65+
result = []
66+
prev_id = 0
67+
current = self.head
68+
while current:
69+
result.append(current.value)
70+
# Find next node's ID:
71+
# current.both = prev_id ^ next_id
72+
# so, next_id = prev_id ^ current.both
73+
current_id = id(current)
74+
next_id = prev_id ^ current.both
75+
76+
# Move forward
77+
prev_id = current_id
78+
current = self._nodes.get(next_id)
79+
return result
80+
81+
82+
if __name__ == "__main__":
83+
import doctest
84+
85+
doctest.testmod()

0 commit comments

Comments
 (0)