题目描述:
将一个二叉搜索树就地转化为一个已排序的双向循环链表。可以将左右孩子指针作为双向循环链表的前驱和后继指针。
为了让您更好地理解问题,以下面的二叉搜索树为例:
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
下图显示了转化后的二叉搜索树,实线表示后继关系,虚线表示前驱关系。
解题思路
使用队列,将二叉搜索树通过中序遍历的方式,依次将节点放入队列中。由于二叉搜索树的特性,通过中序遍历得到的序列是递增的。因此,放入队列中的节点顺序就是转换后双向链表的顺序。
从队列中弹出节点,将弹出的节点与前一个节点(pre)进行连接。具体的操作是:将当前节点(cur)的左子节点指针指向前一个节点(pre),将前一个节点的右子节点指针指向当前节点。然后,更新前一个节点为当前节点。
当队列为空时,说明所有节点都已经处理完毕。此时,需要将头节点和尾节点进行连接,形成一个环形双向链表。
返回头节点。
构造双向链表时需要定义两个变量cur和pre,他们的关系如下图所示:
还需要定义一个变量last来记录最后一个节点和第一个节点(head)的前后关系
参考代码
class Node {
public int val;
public Node left;
public Node right;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val,Node _left,Node _right) {
val = _val;
left = _left;
right = _right;
}
};
*/
class Solution {
public Node treeToDoublyList(Node head) {
Queue<Node> queue = new LinkedList<Node>();
middleOrder(head, queue);
//记录最后一个节点
Node last = null;
// cur初始值为null
Node cur = null;
// pre节点初始值为head即队列的头结点
head = queue.poll();
Node pre = head;
//设置双向链表的前后关系,这是核心逻辑
while (!queue.isEmpty()) {
cur = queue.poll();
pre.right = cur ;
cur.left = pre;
pre = cur;
}
//把头结点和尾结点连接起来
if(pre!=null){
last = pre;
last.right = head;
head.left = last;
}
return head;
}
private void middleOrder(Node treeNode, Queue<Node> queue) {
// TODO Auto-generated method stub
if (treeNode == null) {
return;
}
middleOrder(treeNode.left, queue);
queue.add(treeNode);
middleOrder(treeNode.right, queue);
}
}