假設 轉后后 節點 的 left 指針 作為 next 指針, right 指針 作為 prev 指針
思路:首先可以利用的指針 即是 葉子節點 的 指針。這樣 我們 可以 不斷 把 一部分節點 移到 找到的新葉子節點 后面,比如 把 右節點 移到 左葉子幾點后面。
簡單的想, 假設 我們 把 左右子樹已經 轉換 好了, 這個時候 我們 我們 只要 把 右子樹轉換后的鏈表 添加 到 左子樹 的鏈表 后,將 左子樹的 right 指針 指向 根節點。根節點的right指針指向空。
先來 三個 節點
1 空節點 (NULL節點) : 返回空
2 只有根節點:直接返回
3 有個左孩子: 父節點 left 指針 指向 下一個節點 即 左孩子 ,不變
right 指針 保持 為空 (注意 不是 循環鏈表,所以 prev 指針 不用指向 尾節點 ), 即 父節點 保持 不變
左孩子 的 right 指針 指向 父節點 ,left 指針 指向空 不變
4 有個右孩子: 父節點 沒有 左孩子,所以 右子樹 鏈表 可以直接 加到 父節點下面 。所以 父節點 的 left 指針 指向 右孩子。right 指針 改為 指向 空
右孩子 沒有 下一個節點了,所以 left 指針 為空 不變, 由於前面有父節點,所以 right 指針 指向 父節點
5 左右孩子:先轉換 左子樹,得到 一個雙向鏈表 ,只有一個節點即左孩子,再轉換 右節點 同理。
第二步 將 右子樹 的 鏈表 加到 左子樹 的 后面,所以 左孩子的 left 指針 指向 右孩子,右孩子的 right 指針 指向 根節點的左孩子。
第三步 根節點 作為 左孩子的前一個節點 也就是 整個鏈表的首節點,right 指針指向空,左孩子的 right 指向 根節點。
為了 在 轉換 左子樹 后 ,將 右子樹 加到 左子樹形成的鏈表的后面,轉換 函數 返回 鏈表的 最后一個 節點
python 代碼:
class BTree(object):
def __init__(self,v,left=None,right=None):
self.value = v
self.left = left
self.right = right
def toDLink(self):
def _(node):
'move right node to left leaf'
assert node != None
if node.left == None and node.right == None: # only self, like S2
return node
if node.left == None: # only right , like s4
tail = _(node.right) # change right tree
node.right.right = node # right child's prev pointer point to father node
node.left = node.right # father node's next pointer point to right node
node.right = None # father prev pointer point to null
elif node.right == None: # only left , like s3
tail = _(node.left) # change left tree
node.left.right = node # left child prev pointer
else: # both , like s5
ltail = _(node.left)
rtail = _(node.right)
node.right.right = ltail
ltail.left = node.right
node.right = None
node.left.right = node
tail = rtail
return tail
_(self)
變形題: 一顆有序二叉樹,轉換為 一個 有序 雙向鏈表 (2014校招研發筆試)
思路 一樣, 只是 不將 右子樹 形成 的 鏈表 加到 左子樹形成的鏈表后 面 罷了。反過來 將 根節點 和 左子樹形成的鏈表 加到 右子樹形成的鏈表后面 ,然后 鏈表頭結點不再一定是根節點,要保存頭結點,當然也可以從尾節點回溯過去得到,只是一個正反序的問題。
總的來說 還是 二叉樹的 前序,中序 或 后序 遍歷。
