递归版
由于二叉搜索树本身是有序的,利用中序遍历可以从小到大得到树中的元素,因此在中序遍历的递归过程中,每次保存上一次遍历过的节点,同时将其构造为双向链表,注意最后返回的根节点是中间节点,不是头节点。
TreeNode* pre(TreeNode* root)
{
TreeNode*last;
if (root != NULL)
{
if (root->left != NULL)
{
last = pre(root->left);
while (last->right != NULL) last = last->right;
last->right = root;
root->left = last;
}
if (root->right != NULL)
{
last = pre(root->right);
while (last->left != NULL) last = last->left;
last->left = root;
root->right = last;
}
}
return root;
}
TreeNode* Convert(TreeNode* pRootOfTree)
{
if (pRootOfTree == NULL) return NULL;
if (pRootOfTree->left == NULL && pRootOfTree->right == NULL) return pRootOfTree;
TreeNode* root = NULL;
root=pre(pRootOfTree);
return root;
}
非递归版
其实就是在中序遍历的非递归版中,用栈模拟递归,当前栈顶元素与上次弹出的元素构造双向链表,由于中序遍历中上次弹出的元素必定是小于当前栈顶元素的,因此取上次弹出的元素与当前栈顶的元素构造双向链表能得到最终有序的双向链表。
关键在于非递归的中序遍历的构造。
TreeNode* Convert(TreeNode* pRootOfTree)
{
if (pRootOfTree == NULL) return NULL;
if (pRootOfTree->left == NULL && pRootOfTree->right == NULL) return pRootOfTree;
TreeNode* root = pRootOfTree;
TreeNode* last = NULL;
stack<TreeNode*> NodeStack;
bool isfirst = true;
do
{
while (root ) //这个循环的头很精妙,保证了右节点能够入栈
{
NodeStack.push(root);
if (root->left == NULL && isfirst)
{
last = root; //主要为了给last赋初值
isfirst = false;
}
root = root->left;
}
root = NodeStack.top();
NodeStack.pop();
// cout << root->val;
if (root != last)
{
root->left = last;
last->right = root;
last = root;
}
root = root->right;
} while (!NodeStack.empty()||root!=NULL);
while (last->left) last = last->left;
return last;
}
总的来说,不管递归还是非递归,理解上都有一点难度。递归直观但要注意边界条件,递归转非递归的写法需要多多斟酌。