(剑指Offer)面试题27:二叉搜索树与双向链表
题目:
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
二叉树的定义如下:
struct TreeNode{ int val; TreeNode* left; TreeNode* right; };
思路:
在二叉树中,每个结点都有两个指向子结点的指针,在双向链表中,每个结点也有两个指针,他们分别指向前一个结点和后一个结点。两种数据结构看起来很相似,是可以通过某种方式将二叉搜索树转换为排序的双向链表。
在二叉搜索树中,当遍历到根结点时,把二叉树看成三部分,根结点、左子树和右子树,根据排序链表的定义,根结点的左指针应该指向左子树中最大的结点,即最右边的结点;根结点的右指针应该指向右子树中最小的结点,即最左边的结点。
在把左子树、右子树都转换成排序的双向排序链表(递归)之后,再跟根结点连接起来,整棵二叉搜索树就转换成了排序的双向链表。
因此在设计递归函数时,需要返回链表的头指针和尾指针,并改变当前结点的左右指针的指向。(详见代码)
代码:
#include <iostream> using namespace std; struct TreeNode{ int val; TreeNode* left; TreeNode* right; }; TreeNode* ConvertNodes(TreeNode* pRoot,TreeNode** pTail); TreeNode* Convert(TreeNode* pRoot){ TreeNode* pTail=NULL; return ConvertNodes(pRoot,&pTail); } TreeNode* ConvertNodes(TreeNode* pRoot,TreeNode** pTail){ if(pRoot==NULL) return NULL; if(pRoot->left==NULL && pRoot->right==NULL){ *pTail=pRoot; return pRoot; } TreeNode* leftHead=pRoot; if(pRoot->left!=NULL){ leftHead=ConvertNodes(pRoot->left,pTail); pRoot->left=*pTail; if(*pTail!=NULL) (*pTail)->right=pRoot; *pTail=pRoot; } if(pRoot->right!=NULL){ TreeNode* rightHead=ConvertNodes(pRoot->right,pTail); pRoot->right=rightHead; if(rightHead!=NULL) rightHead->left=pRoot; } return leftHead; }
在线测试OJ:
http://www.nowcoder.com/books/coding-interviews/947f6eb80d944a84850b0538bf0ec3a5?rp=2
AC代码:
class Solution { public: TreeNode* Convert(TreeNode* pRootOfTree) { TreeNode* pTail=NULL; return ConvertNodes(pRootOfTree,&pTail); } TreeNode* ConvertNodes(TreeNode* pRoot,TreeNode** pTail){ if(pRoot==NULL) return NULL; if(pRoot->left==NULL && pRoot->right==NULL){ *pTail=pRoot; return pRoot; } TreeNode* leftHead=pRoot; if(pRoot->left!=NULL){ leftHead=ConvertNodes(pRoot->left,pTail); pRoot->left=*pTail; if(*pTail!=NULL) (*pTail)->right=pRoot; *pTail=pRoot; } if(pRoot->right!=NULL){ TreeNode* rightHead=ConvertNodes(pRoot->right,pTail); pRoot->right=rightHead; if(rightHead!=NULL) rightHead->left=pRoot; } return leftHead; } };