Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@
## [Computer Vision](computer_vision)
* [Cnn Classification](computer_vision/cnn_classification.py)
* [Flip Augmentation](computer_vision/flip_augmentation.py)
* [Gramian](computer_vision/gramian.py)
* [Haralick Descriptors](computer_vision/haralick_descriptors.py)
* [Harris Corner](computer_vision/harris_corner.py)
* [Horn Schunck](computer_vision/horn_schunck.py)
Expand Down Expand Up @@ -231,6 +232,7 @@
* [Lempel Ziv](data_compression/lempel_ziv.py)
* [Lempel Ziv Decompress](data_compression/lempel_ziv_decompress.py)
* [Lz77](data_compression/lz77.py)
* [Move To Front](data_compression/move_to_front.py)
* [Peak Signal To Noise Ratio](data_compression/peak_signal_to_noise_ratio.py)
* [Run Length Encoding](data_compression/run_length_encoding.py)

Expand Down Expand Up @@ -324,16 +326,19 @@
* [From Sequence](data_structures/linked_list/from_sequence.py)
* [Has Loop](data_structures/linked_list/has_loop.py)
* [Is Palindrome](data_structures/linked_list/is_palindrome.py)
* [Kth Element From End](data_structures/linked_list/kth_element_from_end.py)
* [Merge Sort Linked List](data_structures/linked_list/merge_sort_linked_list.py)
* [Merge Two Lists](data_structures/linked_list/merge_two_lists.py)
* [Middle Element Of Linked List](data_structures/linked_list/middle_element_of_linked_list.py)
* [Partition Linked List](data_structures/linked_list/partition_linked_list.py)
* [Print Reverse](data_structures/linked_list/print_reverse.py)
* [Reverse K Group](data_structures/linked_list/reverse_k_group.py)
* [Rotate To The Right](data_structures/linked_list/rotate_to_the_right.py)
* [Singly Linked List](data_structures/linked_list/singly_linked_list.py)
* [Skip List](data_structures/linked_list/skip_list.py)
* [Sorted Linked List](data_structures/linked_list/sorted_linked_list.py)
* [Swap Nodes](data_structures/linked_list/swap_nodes.py)
* [Xor Linked List](data_structures/linked_list/xor_linked_list.py)
* Queues
* [Circular Queue](data_structures/queues/circular_queue.py)
* [Circular Queue Linked List](data_structures/queues/circular_queue_linked_list.py)
Expand Down
85 changes: 85 additions & 0 deletions data_structures/linked_list/xor_linked_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""
XOR Linked List implementation
A memory-efficient doubly linked list that uses the XOR of node addresses.
Each node stores one pointer that is the XOR of the previous and next node addresses.
https://en.wikipedia.org/wiki/XOR_linked_list
Example:
>>> xor_list = XORLinkedList()
>>> xor_list.insert(10)
>>> xor_list.insert(20)
>>> xor_list.insert(30)
>>> xor_list.to_list()
[10, 20, 30]
"""

from dataclasses import dataclass


@dataclass
class Node:
value: int
both: int = 0 # XOR of prev and next node IDs


class XORLinkedList:
def __init__(self) -> None:
"""Initializes an empty XOR Linked List."""
# 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
self._nodes: dict[int, Node] = {}

def _xor(self, node_a: Node | None, node_b: Node | None) -> int:
"""
Helper function to get the XOR of two node IDs (simulated addresses).
Names 'node_a' and 'node_b' are used for descriptive parameters.
"""
id_a = id(node_a) if node_a else 0
id_b = id(node_b) if node_b else 0
return id_a ^ id_b

def insert(self, value: int) -> None:
"""Inserts a value at the end of the list."""
node = Node(value)
self._nodes[id(node)] = node
node_id = id(node)

if self.head is None:
# If the list is empty, head and tail are the new node
self.head = self.tail = node
else:
# 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 ^= node_id
self.tail = node

def to_list(self) -> list[int]:
"""Converts the XOR list to a standard Python list (forward traversal)."""
result = []
prev_id = 0
current = self.head
while current:
result.append(current.value)
# Find next node's ID:
# current.both = prev_id ^ next_id
# so, next_id = prev_id ^ current.both
current_id = id(current)
next_id = prev_id ^ current.both

# Move forward
prev_id = current_id
current = self._nodes.get(next_id)
return result


if __name__ == "__main__":
import doctest

doctest.testmod()
Loading