Convert a Binary Search Tree to a sorted Circular Doubly-Linked List in place.
You can think of the left and right pointers as synonymous to the predecessor and successor pointers in a doubly-linked list. For a circular doubly linked list, the predecessor of the first element is the last element, and the successor of the last element is the first element.
We want to do the transformation in place. After the transformation, the left pointer of the tree node should point to its predecessor, and the right pointer should point to its successor. You should return the pointer to the smallest element of the linked list.
solutions
We first DFS all the way down to find the largest value in the left subtree and the smallest value in the right subtree. These will be predecessor/successor of node. Because we don’t want to make our recursive call dependent on direction, just return both min and max.
Then, since we’ve already done all the traversals lower down in the tree by the time we return from the recursive call, we can change the pointers to make our DLL.
def treeToDoublyList(self, root: 'Optional[Node]') -> 'Optional[Node]':
if not root:
return root
# dfs returns max and min with node as root
def dfs(node):
if not node:
return None, None
lmin, rmax = None, None
if node.left:
lmin, lmax = dfs(node.left)
node.left = lmax
lmax.right = node
if node.right:
rmin, rmax = dfs(node.right)
node.right = rmin
rmin.left = node
mn = lmin if lmin else node
mx = rmax if rmax else node
return mn, mx
mn, mx = dfs(root)
# make circular
mn.left = mx
mx.right = mn
return mnA more elegant solution is to just keep a single variable, last, which tracks the previous node we’ve seen in the in-order traversal. Because we’re traversing in-order, we can always just link current node to last.
def treeToDoublyList(self, root: 'Node') -> 'Node':
def helper(node):
"""
Performs standard inorder traversal:
left -> node -> right
and links all nodes into DLL
"""
nonlocal last, first
if node:
# left
helper(node.left)
# node
if last:
# link the previous node (last)
# with the current one (node)
last.right = node
node.left = last
else:
# keep the smallest node
# to close DLL later on
# this case ONLY happens for smallest node
first = node
last = node
# right
helper(node.right)
if not root:
return None
# the smallest (first) and the largest (last) nodes
first, last = None, None
helper(root)
# close DLL
last.right = first
first.left = last
return first