在处理二叉树的过程中,对于二叉树指向问题一直是比较棘手的问题,常见做法就是将二叉树用(前中后层序)遍历的形式进行转换,对于较为复杂的问题,如何去解决呢?
我们介绍到一种分治思想
问题:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
这个问题如果我们去研究更改指向的规律,很容易将我们自身绕进去。
我们给定一个这样的BST树,如果我们来研究如何将其更改指向到接下来这张图
我们是无法通过找规律旋转出来的。
但是我们会一种做法:
中序遍历
我们可以用一个容器,将遍历后的结果放到一个容器里面,然后对这个容器进行操作,就能得到一个想要的链表。来看代码:
void Inorder(TreeNode* root, vector<TreeNode*> & vec)
{
if(root == nullptr)
{
return;
}
else
{
Inorder(root-> left,vec);
vec.push_back(root);
Inorder(root->right,vec);
}
}
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree) {
if(nullptr == pRootOfTree)
{
return nullptr;
}
vector<TreeNode*> vec;
Inorder(pRootOfTree,vec);
if(vec.size() == 1)
{return vec[0];}
for(size_t i = 1;i < vec.size() - 1;++i)
{
vec[i]->left = vec[i-1];
vec[i]->right = vec[i+1];
}
vec[0]->right = vec[1];
vec[vec.size() - 1]->left = vec[vec.size() - 2];
vec[vec.size() - 1]->right = NULL;
return vec[0];
}
};
另一种做法:
分治
我们无法得知全部实现转换,但是我们可以实现部分。
我们可以保证每一个节点都是满足这个情况
class Solution {
public:
void Convert(TreeNode* Root , TreeNode*& prev)
{
if(nullptr == Root)
{
return;
}
Convert(Root->left, prev);
Root->left = prev;
if(prev)
{
prev->right = Root;
}
prev = Root;
Convert(Root->right,prev);
}
TreeNode* Convert(TreeNode* pRootOfTree) {
if(pRootOfTree == nullptr)
{
return nullptr;
}
TreeNode* head = pRootOfTree;
while(head->left)
{
head = head->left;
}
TreeNode* prev = nullptr;
Convert(pRootOfTree, prev);
return head;
}
};
我在当时看完别人所写的分治代码后很不明白为啥这个prev初始化是nullptr,如果是让这个prev表示前一个节点,那么这个root对应的前一个节点是nullptr,所写代码应该是
if(prev)
prev->left = root;
但是我们来看这个代码:
Convert(Root->left, prev);
这行代码会一直递归走到最左边的节点,直到这个节点为NULL。
然后回退到最左边那个节点,此时prev表示root上一步的节点,也就是说root的上一步的节点为nulltptr,这也就是为什么这个prev不能随便初始化的原因。这个prev是需要进行考虑初始化的,并不是随便的赋值。