二分搜索树的数据结构为:
1 struct BinaryTreeNode 2 { 3 int nValue; 4 5 BinaryTreeNode *pLeft; 6 BinaryTreeNode *pRight; 7 };
首先我们来通过一个简单的例子来获取直接的感官,将这颗排序二叉树
转变为排序的双向链表应为:
可以很清楚的发现转换完成的双向链表的顺序其实就是二叉搜索树的中序遍历的顺序,因此这个题我们可以借助中序遍历来完成。因为二叉树的结构很符合递归的思想,因此基本上所有关于二叉树的问题都可以用递归来完成,这个问题也不例外。我们假设中序遍历到达根节点10时,它的左子树已经转换成了排序双向链表,并且处在链表最末端的节点时链表中值最大的节点(即8),我们将这个节点和根节点10连接起来,则10成为了链表中的最后一个节点。然后利用跟左子树同样的思想,将右子树转换成排序双向链表并将其连接在10的后面,则整个转换过程完成。
基于以上分析,可以写出下面代码:
1 BinaryTreeNode *Convert(BinaryTreeNode *pRootOfTree) 2 { 3 assert (pRootOfTree != NULL); 4 5 BinaryTreeNode *pLastNodeInList = NULL; 6 7 ConvertNode (pRootOfTree, &pLastNodeInList); 8 9 // pLastNodeInList指向双向链表尾结点 10 // 我们需要返回头结点 11 BinaryTreeNode *pHeadOfList = pLastNodeInList; 12 13 while ((pHeadOfList != NULL) && (pHeadOfList->pLeft != NULL)) 14 { 15 pHeadOfList = pHeadOfList->pLeft; 16 } 17 18 return (pHeadOfList); 19 }
ConvertNode函数的实现:
1 void ConvertNode(BinaryTreeNode *pNode, BinaryTreeNode **pLastNodeInList) 2 { 3 assert (pLastNodeInList != NULL); 4 5 if (NULL == pNode) 6 { 7 return; 8 } 9 10 BinaryTreeNode *pCurrent = pNode; 11 12 // 理解递归算法的核心就是我们要相信它能完成我们给它假设的任务 13 // 那么在这里我们就要相信pCurrent的左子树已经被转换成了一个排序的双向链表 14 // ,并且pLastNodeInList指向了这个链表的最后一个节点 15 if (pCurrent->pLeft != NULL) 16 { 17 ConvertNode (pCurrent->pLeft, pLastNodeInList); 18 } 19 20 // 接下来的任务就是将pCurrent这个节点加入这个链表的末尾 21 // 首先将pCurrent的左指针指向这个链表的最后一个节点 22 pCurrent->pLeft = *pLastNodeInList; 23 24 if (*pLastNodeInList != NULL) 25 { 26 // 然后若这个链表不为空,即pCurrent不是链表的首节点 27 // ,那么我们还需要将链表末尾节点的右指针指向pCurrent,才算完整的将pCurrent节点连入到链表的末尾 28 (*pLastNodeInList)->pRight = pCurrent; 29 } 30 31 // 更新pLastNodeInList指针的指向,使其始终指向链表的最后一个节点 32 *pLastNodeInList = pCurrent; 33 34 if (pCurrent->pRight != NULL) 35 { 36 // 如果pCurrent的右子树不为空,则按照左子树的方式来处理右子树 37 ConvertNode (pCurrent->pRight, pLastNodeInList); 38 } 39 }