1.题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
2.1 解题思路
题目给定一棵二叉搜索树,并要求在原节点基础上将其变成排好序的双向链表,并返回值最小的节点。按照题意需要完成两步:第一步对二叉搜索树的节点进行排序,第二步将节点连接成双向链表。由于题目给定的是二叉搜索树,因此可以二叉搜索树中序遍历便能够从小到大获取到节点,利用这一性质便能够完成第一步,遍历同时将节点放入队列中,用于组装双向链表。
获取到排好序的节点队列之后便开始组装双向链表,队列的第一个节点便是需要返回的头节点,之后节点的 left 指向队列中当前节点的前一个节点, right 只想队列中当前节点的下一个节点,直到队列为空。此时再把对头节点和队尾节点连接上就完成题目要求。
以题目给出示例为例,首先进行中序遍历,得到节点队列 [1, 2, 3, 4, 5]
然后在从队列中获取头节点,再依次遍历队列,将上一节点 pre 的 right 指向队列弹出的当前节点 curr,再将当前节点的 left 指向上一节点。完成这一操作后将 pre 指向当前节点,继续便利队列,直到队列中的节点全部弹出。
最后一步就是将收尾节点进行连接,此时完成双向循环链表组装。
2.2 代码
class Solution {
Queue<Node> queue = new LinkedList<>();
public Node treeToDoublyList(Node root) {
if (root == null) {
return null;
}
process(root);
// 弹出队头节点作为头节点,并使用 pre 指向前一个节点
Node head = queue.poll();
Node pre = head;
while (!queue.isEmpty()) {
// 从队列弹出队头,然后将前一节点和当前节点进行连接
Node curr = queue.poll();
pre.right = curr;
curr.left = pre;
pre = curr;
}
// 队列弹出完成后进行收尾连接
pre.right = head;
head.left = pre;
return head;
}
public void process(Node root) {
if (root == null) {
return;
}
process(root.left);
// 中序遍历,将节点放入队列中
queue.offer(root);
process(root.right);
}
}
2.3 测试结果
通过测试
3.总结
- 利用二叉搜索树中序遍历性质获取排序后的节点队列
- 再使用节点队列组装双向循环链表