题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。
比如将二元查找树
10
/ \
614
/ \ / \
4812 16
转换成双向链表
4=6=8=10=12=14=16。
/*
1.二叉树中序遍历的结果与链表的顺序一致,所以可以采用中序遍历的方法来修改二叉树的指针
2.该题的关键是,如何将左子树的最大值与右子树的最小值通过根root连接起来,比如题目的8和12,这也是细节部分
3.写递归程序最重要的是弄明白递归进入的条件、递归返回的状态,如果递归进入时改变了环境,返回时应当恢复环境,就像栈的操作一样
4.使用指针变量时,要记得初始化
5.该算法没有返回链表头,而是返回了root。
*/
以下图片为测试结果:




/*节点定义*/
typedef struct node
{
char value;
struct node *left;
struct node *right;
}BSTree;
/*查找以tr为根最左边的节点,即以tr为根的二叉排序树的最小值*/
BSTree *findLeft(BSTree *tr)
{
BSTree*p = NULL;
while(tr->left)
{
p= tr->left;
tr= p;
}
return tr;
}
/*查找以tr为根最右边的节点,即以tr为根的二叉排序树的最大值*/
BSTree *findRight(BSTree *tr)
{
BSTree*p = NULL;
while(tr->right)
{
p= tr->right;
tr= p;
}
return tr;
}
/*实现将二叉排序树数转变为双链表*/
BSTree *ConvertBSTreeToList(BSTree **root)
{
if(!*root)
return (BSTree *)NULL;
BSTree*lt=NULL,*rt=NULL;
if((*root)->right)/*先处理右子树,其实先处理左子树也行*/
{
rt= ConvertBSTreeToList(&(*root)->right);/*递归进入*/
if((*root)->right)/*递归返回处理,如果该根节点的右子树有最小值,则将该最小值的节点与root连起来,否则直接处理*/
lt= findLeft((*root)->right);
if(lt)rt = lt;
if(rt)
{
rt->left= *root;
(*root)->right= rt;
}
}
if((*root)->left)
{
lt= ConvertBSTreeToList(&(*root)->left);/*递归进入*/
if((*root)->left)/*递归返回处理,如果该根节点的左子树有最大值,则将该最大值的节点与root连起来,否则直接处理*/
rt= findRight((*root)->left);
if(rt)lt = rt;
if(lt)
{
lt->right= *root;
(*root)->left= lt;
}
}
return *root;
}
/*递归创建二叉排序树,以','结束*/
void CreateBSTree(BSTree**tr)
{
BSTree*p = (BSTree *)malloc(sizeof(node));
scanf_s("%c",&p->value);
p->left= NULL;
p->right= NULL;
if(p->value != ',')
{
if(!(*tr))
{
*tr= p;
(*tr)->left= NULL;
(*tr)->right= NULL;
}
}else return;
CreateBSTree(&(*tr)->left);
CreateBSTree(&(*tr)->right);
}
int _tmain(int argc, _TCHAR* argv[])
{
BSTree*binaryTree = NULL,*list = NULL;
CreateBSTree(&binaryTree);
list= ConvertBSTreeToList(&binaryTree);
BSTree*p = list;
while(list->left)
{
p= list->left;
list= p;
}
while(p)
{
printf("%c",p->value);
p= p->right;
}
for(;;);
return 0;
}