题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
递归方法:
思路:
1、把树分成三部分:根结点、左子树、右子树。把左子树中最大的结点与根结点连接起来,然后把右子树中最小的结点与根结点连接起来。
2、设置一个pre指针,指向前一个遍历的结点,使当前结点与pre指针指向的结点连接起来。
3、转换后的链表是排好序的,所以要用中序遍历遍历树的结点。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
if(pRootOfTree==nullptr)
return nullptr;
//Pre指针,指向之前遍历的结点,也是转换完后最大的结点
TreeNode *PastNode=nullptr;
TreeNode *ListNode;
ConvertTree(pRootOfTree,PastNode);
//调用完ConvertTree()函数后PastNode指向了链表中最后一个结点
ListNode=PastNode;
//还要找到他的头结点
while(ListNode->left!=nullptr)
{
ListNode=ListNode->left;
}
return ListNode;
}
void ConvertTree(TreeNode *pRootOfTree,TreeNode *&PastNode)//传引用
{
if(pRootOfTree==nullptr)//递归出口
return ;
TreeNode *CurrentNode=pRootOfTree;//指向当前结点
if(pRootOfTree->left!=nullptr)//左子树不为空时,遍历左子树
ConvertTree(pRootOfTree->left,PastNode);
//连接当前结点和它上一个结点(左边结点)
CurrentNode->left=PastNode;
if(PastNode !=nullptr)
PastNode->right=CurrentNode;
PastNode = CurrentNode;//转换完后要更新Past指针
if(pRootOfTree->right!=nullptr)//右子树不为空时,遍历右子树
ConvertTree(pRootOfTree->right,PastNode);
}
};
非递归方法:
思路:
1、根据二叉树中序遍历的非递归算法,用栈来保存结点。
2、设置Pre指针,指向上一个中序遍历的上一个结点。连接当前结点与Pre指向的结点。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
if(pRootOfTree==nullptr)
return nullptr;
stack<TreeNode *> s;//用栈保存结点
TreeNode *ListHead=nullptr;//指向双向链表的头结点
TreeNode *PreNode=nullptr;//指向中序遍历的上一个结点
TreeNode *Root=pRootOfTree;
bool FirstNode=true;//判断是否是第一个结点(双向链表的头结点)
while(Root!=nullptr||!s.empty())
{
while(Root!=nullptr)
{
s.push(Root);
Root=Root->left;//转向左子树,左子结点一直入栈
}
Root=s.top();
s.pop();
if(FirstNode)
{
ListHead=PreNode=Root;
FirstNode=false;
}
else
{
Root->left=PreNode;
PreNode->right=Root;
PreNode=Root;
}
Root=Root->right;//转向右子树
}
return ListHead;
}
};