diff --git a/DIRECTORY.md b/DIRECTORY.md index a6800acdac4a..a2de2029c773 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -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) @@ -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) @@ -324,9 +326,11 @@ * [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) @@ -334,6 +338,7 @@ * [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) 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..3de6e12c910e --- /dev/null +++ b/data_structures/linked_list/xor_linked_list.py @@ -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()