1. 题目
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表,要求不能创建任何新的节点,只能调整树种节点指针的指向。比如,输入图中二叉搜索树,则输出转换之后的排序双向链表。二叉树节点的定义如下:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pNext;
BinaryTreeNode* m_pSibling;
}
python 版
class BinaryTreeNode(object):
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
二叉搜索树
2. 解题思路
题目中明确要求不能使用额外的空间,只能调整指针的指向来实现。
双向链表是排序好的。
- 首先,我们需要知道什么是二叉搜索树呢?
回答:二叉搜索树,是指左子树的节点的值都小于根节点的值,右子树的节点的值都大于根节点的值,而且对于每一个子树都成立。
当我们了解了二叉搜索树的这个特点之后,很明显,当使用中序遍历(左根右)来遍历二叉树的时候,得到的就是已经排好序的节点的顺序。
所以,最困难的地方就是如何调整每一个节点的两个指针的指向呢?而且,最难的就是,将左子树的最大节点和根节点连接起来,将右子树的最小节点和根节点连接起来。
3. 代码实现
class BinaryTreeNode(object):
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
def convert(root):
"""
使用3个指针,
1指针指向树中的当前节点
2指针指向链表中的头节点
3指针指向链表中的尾节点
"""
last = None # 指针3
print(id(last))
convert_node(root,last)
# print('last是',last)
print(id(last))
head = last # 指针2
# 此时last指向链表的尾节点,需要遍历一遍链表获得链表的头节点
while head != None and head.left != None:
head = head.left
return head
def convert_node(node, plast):
"""
将树中的节点转成链表中的节点,
因为链表是从小到大排序好的,因此链表的尾节点是小于当前节点的最大的一个节点
中序遍历:左-根-右
"""
if node is None:
return
cur = node # 指针1,指向二叉树中当前节点
if cur.left:
convert_node(cur.left, plast)
cur.left = plast
if plast:
plast.right = cur
last = cur
print('此时',id(plast))
if cur.right:
convert_node(cur.right, plast)
if __name__ == '__main__':
node10 = BinaryTreeNode(10)
node6 = BinaryTreeNode(6)
node4 = BinaryTreeNode(4)
node8 = BinaryTreeNode(8)
node14 = BinaryTreeNode(14)
node12 = BinaryTreeNode(12)
node16 = BinaryTreeNode(16)
node10.left = node6
node10.right = node14
node6.left = node4
node6.right = node8
node14.left = node12
node14.right = node16
res = convert(node10)
node = res
while node:
print(node.value)
node = node.right
但是上面的代码有些问题,那就是最后plast是指向最后一个节点的,但是这个plast是convert_node函数中的局部变量,而且它是不可变对象,因此在函数convert_node中修改的一直是plast的引用,而原始的last的应用一直都是指向None的。因此,必须要将last变成可变对象才能在其他函数中修改这个last,否则,一定是改变的plast的引用,而不是last。
当last是不可变对象时:
当last是可变对象时:
class BinaryTreeNode(object):
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
def convert(root):
"""
使用3个指针,
1指针指向树中的当前节点
2指针指向链表中的头节点
3指针指向链表中的尾节点
"""
last = [None] # 指针3
convert_node(root,last)
# print('last是',last)
print(id(last))
head = last[0] # 指针2
# 此时last指向链表的尾节点,需要遍历一遍链表获得链表的头节点
while head != None and head.left != None:
head = head.left
return head
def convert_node(node, plast):
"""
将树中的节点转成链表中的节点,
因为链表是从小到大排序好的,因此链表的尾节点是小于当前节点的最大的一个节点
中序遍历:左-根-右
"""
if node is None:
return
cur = node # 指针1,指向二叉树中当前节点
if cur.left:
convert_node(cur.left, plast)
cur.left = plast[0]
if plast[0]:
plast[0].right = cur
plast[0] = cur
if cur.right:
convert_node(cur.right, plast)
if __name__ == '__main__':
node10 = BinaryTreeNode(10)
node6 = BinaryTreeNode(6)
node4 = BinaryTreeNode(4)
node8 = BinaryTreeNode(8)
node14 = BinaryTreeNode(14)
node12 = BinaryTreeNode(12)
node16 = BinaryTreeNode(16)
node10.left = node6
node10.right = node14
node6.left = node4
node6.right = node8
node14.left = node12
node14.right = node16
res = convert(node10)
node = res
while node:
print(node.value)
node = node.right
4. 总结
目前只使用了递归实现,后期有时间的话再做循环实现的。本题要注意的是,递归实现的时候,传入的不可变对象和可变对象得到的结果是不同的。
5. 参考文献
[1] 剑指offer丛书