1111[10, 20, 30]
1212"""
1313
14- # Note: This implementation simulates pointer behavior using Python's id()
15- # and a dictionary lookup (_nodes). In languages like C, this would
16- # be done with actual memory addresses and pointer arithmetic.
14+ # Note: 'from typing import Optional' is no longer needed
15+ # as we use the modern 'Node | None' syntax.
1716
1817
1918class Node :
20- def __init__ (self , value : int ):
19+ def __init__ (self , value : int ) -> None :
20+ """Initializes a Node with a value and a null pointer."""
2121 self .value = value
2222 self .both : int = 0 # XOR of prev and next node ids
2323
2424
2525class XORLinkedList :
26- def __init__ (self ):
27- # Use 'Node | None' instead of 'Optional[Node]' (per ruff UP045)
26+ def __init__ (self ) -> None :
27+ """Initializes an empty XOR Linked List."""
2828 self .head : Node | None = None
2929 self .tail : Node | None = None
3030 # id -> node map to simulate pointer references
31- # In a low-level language, we would just store/use the memory addresses.
3231 self ._nodes : dict [int , Node ] = {}
3332
34- def _get_node (self , node_id : int ) -> Node | None :
35- """Helper to retrieve a node by its simulated ID."""
36- return self ._nodes .get (node_id )
37-
38- def _get_id (self , node : Node | None ) -> int :
39- """Helper to get the simulated ID (address) of a node."""
40- return id (node ) if node else 0
41-
4233 def _xor (self , a : Node | None , b : Node | None ) -> int :
43- """Helper to XOR the IDs (addresses) of two nodes."""
44- # Use 'Node | None' instead of 'Optional[Node]' (per ruff UP045)
45- return self ._get_id (a ) ^ self ._get_id (b )
34+ """Helper function to get the XOR of two node IDs."""
35+ return (id (a ) if a else 0 ) ^ (id (b ) if b else 0 )
4636
4737 def insert (self , value : int ) -> None :
4838 """Inserts a value at the end of the list."""
4939 node = Node (value )
50- # Store the node in our simulated memory
5140 self ._nodes [id (node )] = node
5241
5342 if self .head is None :
54- # List is empty
55- self .head = node
56- self .tail = node
57- # node.both remains 0 (XOR of None and None)
43+ # If the list is empty, head and tail are the new node
44+ self .head = self .tail = node
5845 else :
59- # List is not empty, append to tail
60- # New node's 'both' points back to the old tail
61- node .both = self ._get_id (self .tail )
62-
63- # Update the old tail's 'both'
64- # old_tail.both = (ID of node before old_tail) ^ (ID of new node)
65- # We can get (ID of node before old_tail) by doing:
66- # old_tail.both ^ (ID of next node, which was None/0)
67- # So, old_tail.both ^ 0 = old_tail.both
68- # new_tail.both = old_tail.both ^ self._get_id(node)
69-
70- # Simplified:
71- # self.tail.both was (ID of prev_node) ^ 0
72- # We need it to be (ID of prev_node) ^ (ID of new node)
73- # So we XOR it with the new node's ID.
74- if self .tail : # Type checker guard
75- self .tail .both = self .tail .both ^ self ._get_id (node )
76-
77- # Update the tail pointer
46+ # If the list is not empty, append to the tail
47+ # The new node's pointer is just the ID of the old tail
48+ node .both = id (self .tail )
49+ if self .tail : # Type checker guard
50+ # The old tail's pointer must be updated to XOR
51+ # its previous node ID with the new node's ID.
52+ # self.tail.both was (prev_id ^ 0)
53+ # self.tail.both becomes (prev_id ^ new_node_id)
54+ self .tail .both ^= id (node )
7855 self .tail = node
7956
8057 def to_list (self ) -> list [int ]:
81- """Converts the XOR linked list to a standard Python list (forward)."""
58+ """Converts the XOR list to a standard Python list (forward traversal )."""
8259 result = []
60+ prev_id = 0
8361 current = self .head
84- prev_id = 0 # ID of the virtual 'None' node before head
85-
8662 while current :
8763 result .append (current .value )
88-
89- # Get the ID of the next node
90- # current.both = (ID of prev_node) ^ (ID of next_node)
91- # So, (ID of next_node) = (ID of prev_node) ^ current.both
64+ # Find next node's ID:
65+ # current.both = prev_id ^ next_id
66+ # so, next_id = prev_id ^ current.both
9267 next_id = prev_id ^ current .both
93-
94- # Move to the next node
95- prev_id = self ._get_id (current )
96- current = self ._get_node (next_id )
97-
68+
69+ # Move forward
70+ prev_id = id (current )
71+ current = self ._nodes .get (next_id )
9872 return result
9973
10074
10175if __name__ == "__main__" :
10276 import doctest
10377
104- doctest .testmod ()
105-
106- # Additional demonstration
107- xor_list = XORLinkedList ()
108- xor_list .insert (10 )
109- xor_list .insert (20 )
110- xor_list .insert (30 )
111- print (f"List contents: { xor_list .to_list ()} " ) # Output: [10, 20, 30]
112-
113- # Verify head and tail
114- if xor_list .head :
115- print (f"Head value: { xor_list .head .value } " ) # Output: 10
116- if xor_list .tail :
117- print (f"Tail value: { xor_list .tail .value } " ) # Output: 30
78+ doctest .testmod ()
0 commit comments