题目链接:二叉搜索树与双向链表
题目描述:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
题目要求:
1)排序链表,因为是二叉搜索树,构成排序的链表,需要进行中序遍历。
2)不能创建任何新的节点,只能调整节点指针指向,并且是原地转换。即尽量减少时间复杂度。
思路:
1)首先的思路是,对二叉搜索树进行中序遍历成一个排序数组,对数组进行遍历,给每一个节点添加前驱和后继指针。
js代码如下:
var treeToDoublyList = function (root) {
if (root == null)
return root;
let nodes = [];
midSort(root);
root = nodes[0];
const length = nodes.length;
for (let i = 0; i < length; i++) {
if (i == 0)
nodes[i].left = nodes[length - 1];
else
nodes[i].left = nodes[i - 1];
if (i == length - 1)
nodes[i].right = nodes[0];
else
nodes[i].right = nodes[i + 1];
}
return root;
function midSort(root) {
if (root == null)
return;
midSort(root.left);
nodes.push(root);
midSort(root.right);
}
};
2)第二个思路是,在中序遍历的过程中修改前驱和后继指针的指向,非递归方式。
js代码如下:
var treeToDoublyList = function (root) {
if (root == null)
return root;
let nodes = [];
let cur = root;
while (cur) {
nodes.push(cur);
cur = cur.left;
}
head = nodes[nodes.length - 1];
while (nodes.length !== 0) {
cur = nodes[nodes.length - 1];
nodes.pop();
if (cur.right) {
let p = cur.right;
while (p) {
nodes.push(p);
p = p.left;
}
}
if (nodes.length >= 1) {
cur.right = nodes[nodes.length - 1];
nodes[nodes.length - 1].left = cur;
}
}
head.left=cur;
cur.right=head;
return head;
}
3)然后看了一下题解,思路是,在中序遍历过程中修改前驱和后继指针,递归方式。
js代码如下:
var treeToDoublyList = function (root){
if(root==null)
return root;
let head=null;
let cur=null;
dfs(root);
head.left=cur;
cur.right=head;
return head;
//cur按顺序指向当前排好序的节点,
function dfs(root){
if(root==null)
return;
dfs(root.left);
if(cur!=null)
cur.right=root;
else
head=root;
root.left=cur;
cur=root;
dfs(root.right);
}
}
后两个方法中的cur都是指向当前排好序的节点中的最后一个节点。