搜索二叉树就是如下图:

转换成双向链表,如下图:

有三种解法:
1 增加一个额外的数据结构,记录头尾节点
2 通过查找尾节点,连接头尾节点
3 构成循环链表
我觉得原书说的有点 嗦,其实归结最终的思想是:
需要知道左右子树的头尾节点,就可以把根节点和左右子树节点连接成双向链表了。
方法一如下,使用额外数据结构记录头尾节点:
//data structures
struct BiNode
{
int val;
BiNode *node1;
BiNode *node2;
BiNode():node1(nullptr), node2(nullptr), val(0){}
BiNode(int x):node1(nullptr), node2(nullptr), val(x){}
};
struct NodePair
{
BiNode *head;
BiNode *tail;
NodePair():head(nullptr), tail(nullptr){}
NodePair(BiNode *h, BiNode *t):head(h), tail(t){}
};
//solution 1: solve with additional data structure
void concat(BiNode *x, BiNode *y)
{
x->node2 = y;
y->node1 = x;
}
NodePair *convert(BiNode *root)
{
if (root == nullptr) return nullptr;
NodePair *part1 = convert(root->node1);
NodePair *part2 = convert(root->node2);
if (part1) concat(part1->tail, root);
if (part2) concat(root ,part2->head);
return new NodePair
(part1==nullptr root:part1->head, part2==nullptr root:part2->tail);
}
方法二,因为头节点都是知道的,所以可以查找尾节点,增加个getTail的函数就可以了。不过时间复杂度是O(n*n)。前面的是O(n)
//solution 2:
BiNode *getTail(BiNode *r)
{
if (!r) return nullptr;
while (r->node2)
{
r = r->node2;
}
return r;
}
//关键就是保留或者取得每一次递归回来的头尾指针
BiNode *convert2(BiNode *root)
{
if (!root) return nullptr;
BiNode *part1 = convert2(root->node1);
BiNode *part2 = convert2(root->node2);
if (part1) concat(getTail(part1), root);
if (part2) concat(root, part2);//注意:而不是getTail(part2));
return part1==nullptr root:part1;
}
方法三最困难,因为概念转换不容易,如果对递归不够熟悉,那么就很容易出错。
注意下面程序注释的地方:
//solution 3
BiNode *convertToCircle(BiNode *root)
{
if (!root) return nullptr;
BiNode *p1 = convertToCircle(root->node1);
BiNode *p2 = convertToCircle(root->node2);
if (!(root->node1) && !(root->node2))
{
root->node1 = root;
root->node2 = root;
return root;
}
//假设之前的p1 和 p2都已经是double linklist了,然后再计算
//注意:这个关键的假设,才能处理好递归;而不是按照原来的二叉树来思考下面的计算
BiNode *tail;// = p2 p2->node1:nullptr;
if (p2)//因为已经假设是double linklist了,那么两个node1和node2都肯定不会为空
{
tail = p2->node1;
}
//join left to right
if (p1) concat(p1->node1, root);
else concat(p2->node1, root);
//join right to left
if (p2) concat(root, p2);
else concat(root, p1);
if (p1 && p2) concat(tail, p1);
return p1 p1:root;
}
也可以改成这样,我觉得逻辑更清晰一点:
BiNode *convertToCircle2(BiNode *root)
{
if (!root) return nullptr;
BiNode *p1 = convertToCircle2(root->node1);
BiNode *p2 = convertToCircle2(root->node2);
if (!p1 && !p2)
{
root->node1 = root;
root->node2 = root;
return root;
}
if (p1 && p2)
{
BiNode *tail = p2->node1;
concat(p1->node1, root);
concat(root, p2);
concat(tail, p1);
}
else if (p1 && !p2)
{
concat(p1->node1, root);
concat(root, p1);
}
else if (!p1 && p2)
{
concat(p2->node1, root);
concat(root, p2);
}
return p1 p1:root;
}
把循环链表转换成不循环的:
BiNode *deCircle(BiNode *r)
{
BiNode *h = convertToCircle(r);
h->node1->node2 = nullptr;
h->node1 = nullptr;
return h;
}
BiNode *deCircle2(BiNode *r)
{
BiNode *h = convertToCircle2(r);
h->node1->node2 = nullptr;
h->node1 = nullptr;
return h;
}
测试程序:
//helper functions
void printBST(BiNode *r)
{
if (!r) return;
printBST(r->node1);
cout<
val<<" ";
printBST(r->node2);
}
void printDouLink(BiNode *d)
{
while (d)
{
cout<
val<<" "; d = d->node2; } cout<
head; //solution 2 //root = co