题目:
输入一棵二叉搜索树,将该二叉搜索树转换为一个排序的双向链表。要求不能创建任何新的节点,只能调整树中指针的指向。
分析与解法:
1、由于要求链表是有序的,可以借助二叉树中序遍历,因为中序遍历算法的特点就是从小到大访问结点。当遍历访问到根结点时,假设根结点的左侧已经处理好,只需将根结点与上次访问的最近结点(左子树中最大值结点)的指针连接好即可。进而更新当前链表的最后一个结点指针。
2、由于中序遍历过程正好是转换成链表的过程,即可采用递归处理。
节点定义如下:
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
递归代码实现:
//递归的写法
TreeNode* Convert2(TreeNode* pRootOfTree, TreeNode *&pre, TreeNode *&phead)
{
if(pRootOfTree == NULL)
return NULL;
Convert2(pRootOfTree->left, pre, phead); //左孩子
if(phead == NULL) //处理链表头
phead = pRootOfTree;
pRootOfTree->left = pre;
if(pre != NULL)
pre->right = pRootOfTree; //处理上一个节点的后继。
pre = pRootOfTree;
Convert2(pRootOfTree->right, pre, phead); //右孩子
return phead;
}
TreeNode* Convert2(TreeNode* pRootOfTree)
{
TreeNode *pre = NULL; //前驱
TreeNode *phead = NULL; //头节点
return Convert2(pRootOfTree, pre, phead);
}
非递归实现:
//非递归写法
TreeNode* Convert(TreeNode* pRootOfTree)
{
TreeNode *pcur = pRootOfTree;
stack<TreeNode*> s;
TreeNode *pre = NULL; //链表的前驱节点
TreeNode *phead = NULL; //链表的头部
while(!s.empty()||pcur)
{
while(pcur)
{
s.push(pcur);
pcur = pcur->left;
}
pcur = s.top(); //拿出最左边的元素
if(phead == NULL)
phead = pcur; //最左边的元素就是链表的头节点。
pcur->left = pre; //当前节点只能知道它的前驱节点是谁,但是不知道后继节点是谁,所以这里我们用这个节点的前驱去处理前驱节点的后继。
if(pre != NULL)
pre->right = pcur; //用这个节点的前驱去处理后继。。。
pre = pcur;
s.pop();
pcur = pcur->right;
}
return phead;
}