题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
思路
二叉搜索树具有这样的性质:其左子树上的节点的值都小于等于根节点的值, 其右子树上的节点的值都大于等于根节点的值;
题目要求:获得一个排序的双向链表,要求不创建任何新的节点,只调整树中节点指针的指向。
立即想到中序遍历可得到二叉搜索树的升序序列。可以在中序遍历二叉树的非递归算法的基础上, 利用pre变量存储节点的前驱,head存放中序遍历的第一个节点,tail存放中序遍历的最后一个节点, 将二叉搜索树串联成一个双链表。
C++代码(详细注释)
class Solution {
public:
Node *head, *tail;//head存放双链表的头结点,tail存放双链表的尾节点
Node* treeToDoublyList(Node* root) {
if(!root) return NULL;//防止越界
inOrder(root);//中序遍历改造二叉搜索树
head->left = tail;//使头结点的前驱指向尾节点
tail->right = head;//使尾节点的后继指向头节点
return head;
}
void inOrder(Node* root){//中序遍历改造二叉搜索树
if(!root)return ;
stack<Node*> stk;//用一个栈存放遍历时得到的节点
//本算法的核心思想就在于:利用栈进行的二叉树中序遍历过程
//节点出栈的顺序和中序遍历的顺序是完全一致的
Node* pre = NULL;//pre代表前驱节点
while(!empty(stk) || root){//当栈不空或root不为空时循环继续
while(root){//沿左孩子走下去
stk.push(root);
root = root->left;
}
root = stk.top();//此时root->left == NULL
if(!pre)//若前驱为空代表root为中序遍历的第一个节点
head = root;
else
pre->right = root;//将前驱的right指向root
root->left = pre;//将root的left指向前驱
pre = root;//前驱移动至root
stk.pop();//栈顶元素 == root,此时root已经被加入链表中,将栈顶元素出栈
root = root->right;//root走至其右孩子处
if(empty(stk) && !root)//若栈空且root也为空
//则树中所有节点都已经被遍历过,pre此时代表最后一个节点
tail = pre;
}
}
};
本文正在参与「掘金 3 月闯关活动」,点击查看活动详情。