把二元查找树转变成排序的双向链表(JULY微软面试100题系列第一题)的算法思考

题目:把二元查找树转换成一个排序的双向链表,要求不能创建任何新的结点,只调整指针的指向。原题及原解答请见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年版全部答案集锦(含下载地址)的解法,比较麻烦又难以理解,就不贴出来了……

你可能感兴趣的:(算法题解析)