(本文是对http://blog.csdn.net/v_july_v 提供的微软100题的答案的理解,答案部分来自上述博客)
题目:
输入一颗二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不可以创建任何新的结点,只调整指针的指向。
10
/ \
6 14
/ \ / \
4 8 12 16
转换成双向链表:4=6=8=10=12=14=16
首先我们定义的二元查找树节点的数据结构为:
struct BSTreeNode
{
int m_nValue;
BSTreeNode *m_pLeft;
BSTreeNode *m_pRight;
};
Answer:
先来分析一下需要哪些变量,我们需要得到这个转换后的双链表的头和尾:
BSTreeNode *head,*tail
所以声明函数为:
BSTreeNode * treeToLinkedList(BSTreeNode *root)
{
BSTreeNode *head,*tail;
}
我们还需要一个功能函数,实现这个递归的转换的过程,设为:void helper(BSTreeNode *head,BSTreeNode *tail,BSTreeNode *root)
那么上面的函数就是:
BSTreeNode * treeToLinkedList(BSTreeNode *root)
{
BSTreeNode *head,*tail;
helper(head,tail,root);
return head;
}
下面需要我们好好思考该怎么写这个递归函数helper():
对于算法小白来说,这道题需要我们花心思去好好思考一下递归结束的条件是什么。
1、首先应该想到的是边界问题,比如这个root本身就是NULL的话,那么他的左右孩子节点也就是NULL;
则首先判断:
void helper(BSTreeNode *head,BSTreeNode *tail,BSTreeNode *root)
{
if(root == NULL)
{
head = NULL;
tail = NULL;
return;
}
//如果root不是NULL,那么就要对它两个儿子结点为根的子树进行递归操作,该递归操作完成的任务是:
//将head指向左子树中最小的结点,将tail指向右子树中最大的结点,
//而且需要我们找到左子树中的尾部,即左子树中最大的结点,以及右子树中最小的结点,即右子树
//这就需要我们再设两个变量:BSTreeNode *left,*right;分别指向左子树转换成双向链表的尾和右子树转换成双向链表的头
BSTreeNode *left,*right;
//下一步需要我们完成寻找左子树的尾和右子树的头的工作
helper(head,left,root->m_pLeft);
helper(right,tail,root->m_pRight);
// 处理返回的情况
if(left == NULL)
{
head = root;
}
else
{
left->m_pRight = root;
root->m_pLeft = left;
}
if(right == NULL)
{
tail = root;
}
else
{
right->m_pLeft = root;
root->m_pRight = left;
}
}
当处理过程在递归函数的调用之后,那么该递归过程一定会首先递归到该二叉树的末尾,即叶子结点,实际上是先对叶子结点进行了处理,然后再一级一级的向父结点进行同样的处理,这类似于二叉树的后序遍历,最后处理父结点;