题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
分析:1、利用二元查找树的特点:左子树上的最大的数是整个左子树最右边的数(这个数是小于根节点的数中最大的数),右子树上最小的数是整个右子树上最左边的数(这个数是大于根节点的数中最小的数)。
2、虽热不可以创建新的节点,但可以创建指向节点的指针,来记录一些特殊的节点(如左子树的最右节点,右子树的最左节点,父节点等等)位置。
3、根节点时分为左右两部分处理。左处理部分可以用递归的方法(因为一次处理后形成的子树的根节点的左节点没有右节点,所以可以直接对新子树的根节点的左节点递归左处理),右处理部分也可以用递归的方法,左右两部分类似,是对应的。
“左处理”大体流程可以是这样的:1、从根节点开始,找到根节点的左子树的最右节点(假设用mark指向),找到以mark为根节点的子树的最左节点(用mark_left指向),用mark_parent指向mark的父节点。
2、假如mark就是根节点的左节点,直接将mark的右指针指向根节点即可;否则将mark_left的左指针指向根节点的左节点,mark的右指针指向根节点,根节点的左指针指向mark节点,并将mark_parent的右指针指向NULL。
3、终止条件是根节点的左指针为NULL(mark为NULL)。
下面程序可作为参考:
#include<stdio.h>
typedef struct bi_search_tree //定义二元查找树节点的数据结构
{
int value;
struct bi_search_tree* left;
struct bi_search_tree* right;
}bi_search_tree;
void tree2link(bi_search_tree*,bi_search_tree**);
void tree2link_left(bi_search_tree*);
void tree2link_right(bi_search_tree*);
int main(int argc,char* argv[])
{
int i;
bi_search_tree* link_root;
bi_search_tree bst[10];
bi_search_tree* root=bst; //这里手动构造二元查找树有些若,下一篇介绍构造平衡二叉树
bst[0].value=15;
bst[1].value=8;
bst[2].value=20;
bst[3].value=5;
bst[4].value=12;
bst[5].value=18;
bst[6].value=25;
bst[7].value=6;
bst[8].value=11;
bst[9].value=19;
bst[0].left=&bst[1]; bst[0].right=bst+2;
bst[1].left=&bst[3]; bst[1].right=bst+4;
bst[2].left=&bst[5]; bst[2].right=bst+6;
bst[3].left=NULL; bst[3].right=bst+7;
bst[4].left=&bst[8]; bst[4].right=NULL;
bst[5].left=NULL; bst[5].right=bst+9;
bst[6].left=NULL; bst[6].right=NULL;
bst[7].left=NULL; bst[7].right=NULL;
bst[8].left=NULL; bst[8].right=NULL;
bst[9].left=NULL; bst[9].right=NULL;
printf("before translate\n");
for(i=0;i<10;i++)
{
printf("iam=%d ",bst[i].value);
if(bst[i].left!=NULL)
printf("left=%d ",bst[i].left->value);
else
printf("left=NULL ");
if(bst[i].right!=NULL)
printf("right=%d \n",bst[i].right->value);
else
printf("right=NULL \n");
}
tree2link(root,&link_root);
printf("after translate\n");
bi_search_tree* temp=link_root;
while(temp!=NULL)
{
printf("iam=%d ",temp->value);
if(temp->left!=NULL)
printf("left=%d ",temp->left->value);
else
printf("left=NULL ");
if(temp->right!=NULL)
printf("right=%d \n",temp->right->value);
else
printf("right=NULL \n");
temp=temp->right;
}
free(root);
free(link_root)
return 0;
}
void tree2link(bi_search_tree* root,bi_search_tree** d_link_root)
{
tree2link_left(root);
tree2link_right(root);
*d_link_root=root;
while((*d_link_root)->left!=NULL) //设置双向链表的头指针
(*d_link_root)=(*d_link_root)->left;
}
void tree2link_left(bi_search_tree* root)
{
bi_search_tree* mark=root->left;
bi_search_tree* mark_left;
bi_search_tree* mark_parent=root->left;
if(mark!=NULL)
{
while((*mark).right!=NULL) //找左子树的最右节点
{
mark_parent=mark;
mark=mark->right;
}
mark_left=mark;
while(mark_left->left!=NULL) //找mark的最左节点
mark_left=mark_left->left;
if(mark==root->left)
{
mark->right=root;
}
else
{
mark_left->left=root->left;
mark->right=root;
root->left=mark;
mark_parent->right=NULL;
}
tree2link_left(mark); //递归,因为mark没有右节点
free(mark);
free(mark_left);
free(mark_parent);
}
}
void tree2link_right(bi_search_tree* root)
{
bi_search_tree* mark=root->right;
bi_search_tree* mark_right;
bi_search_tree* mark_parent=root->right;
if(mark!=NULL)
{
while(mark->left!=NULL)
{
mark_parent=mark;
mark=mark->left;
}
mark_right=mark;
while(mark_right->right!=NULL)
mark_right=mark_right->right;
if(root->right==mark)
mark->left=root;
else
{
mark_right->right=root->right;
mark->left=root;
root->right=mark;
mark_parent->left=NULL;
}
tree2link_right(mark);
free(mark);
free(mark_right);
free(mark_parent);
}
}