题目:把二元查找树转换成一个排序的双向链表,要求不能创建任何新的结点,只调整指针的指向。原题及原解答请见JULY的博客“结构之法 算法之道”的微软面试100题2010年版全部答案集锦(含下载地址)。
最初看到这一题,觉得思路很乱,然后开始反思。
1.这是关于树的题目,一般考查递归算法和树的遍历;
2.这是二元查找树,那么其从小到大的顺序就是树的前序遍历列表,换句话说,如果题目允许我们重新建立结点,通过前序遍历依次创建一个一个结点,自然就得到了解决;
3.然而题目要求不能创建任何新结点,再仔细一想,未必需要创建结点,在前序遍历中,如果我们能在访问当前结点时获得前一结点,那么就能自然链接起来。
这一思路形成之后,也就形成了下面的代码:
/*入口函数,返回排序双向链表的头指针*/
BSTreeNoe * changeTreeToLinkList ( BSTreeNode *Tree ) {
BSTreeNode *former=NULL, *head=Tree;
if ( ! Tree) return NULL;
InOrderTraverse ( Tree, former );
while ( head->m_pLeft != NULL ) head=head->m_pLeft;
return head;
}
/*中序遍历*/
void InOrderTraverse ( BSTreeNode *Tree, BSTreeNode * &former) {
if ( Tree->m_pLeft ) InOrderTraverse ( Tree->m_pLeft, former );
visit ( Tree, former );
if ( Tree->m_pRight) InOrderTraverse ( Tree->m_pRight, former );
}
/*访问结点,修改former的值,使其成为下一个将被访问结点的前驱结点*/
void visit ( BSTreeNode *Tree, BSTreeNode * &former) {
if ( former==NULL ) {
former=Tree;
}else{
former->m_pRight=Tree;
Tree->m_pLeft=former;
former=Tree;
}
}
这样就形成了第一种解法;接着开始思考有没有第二种解法?这是关于树的题目,一般就是要找规律,以一个树结点及其左右子树的角度去思考。
1.如果结点A有左子树,那么A的前驱应是左子树的最大结点,且A树的最小结点是其左子树的最小结点;
2.如果结点A没有左子树,那么A必然是某个结点的前驱;且A树的最小结点就是A;
3.如果结点A有右子树,那么A的后继应是右子树的最小结点,且A树的最大结点是其右子树的最大结点;
4.如果结点A没有右子树,那么A必然是某个结点的后继,且A树的最大结点就是A;
理解起来压力好大……这样会形成第二种解法,也就是微软面试100题2010年版全部答案集锦(含下载地址)的解法,比较麻烦又难以理解,就不贴出来了……