123.输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
- 他人题解:首先中序遍历模板如下
-
dfs(Node cur){ if(cur==null)return; dfs(cur.left); //前 solve cur... //中 dfs(cur.right); //后 }
- 首先为了构建双向连接,我们肯定要定义当前遍历节点的前一个节点 pre。由于最后要返回链表头结点,所以定义一个头结点 head。我们在 dfs 的当前节点处理部分,根据题意很容易想到,无非就是连接前后(当前节点与左节点,或当前节点和右结点)两个节点,然后更新 pre 为当前节点,也就是
cur.left=pre, pre.right=cur, cur=pre
。但是在递归时第一次处理当前节点时,也就是头节点时,是没有 pre 给他连接的(按道理应该连接尾结点,可这时刚开始操作,还没拿到尾结点),所以就特判一下,如果 pre 为 null 说明此时在处理的是头结点,就不让 pre 连接它了,而是让 head = cur,这也正好,我们最后要返回的 head 在这一步就得到了。dfs 结束后,pre 此时是指向尾结点的,这时就可以完成之前没连接的,让 head.left = pre(此时为尾结点),然后 pre.right=head。 -
Node pre, head; public Node treeToDoublyList(Node root) { if(root == null) return null; dfs(root); head.left = pre; pre.right = head; return head; } void dfs(Node cur) { if(cur == null) return; dfs(cur.left); // 有 pre 就连,否则说明为头节点 if(pre != null) pre.right = cur; else head = cur; // cur 为头节点时先连个 null 也无所谓,反正 dfs 结束后会连正确的尾结点 // 在其他情况下就能正确连接当前节点和他的前一个节点了 cur.left = pre; pre = cur; dfs(cur.right); }