这章我们详细聊带线索的二叉树,首先在有一棵结点为 n 的二叉树的情况下,二叉树恒有 n+1 个空指针域;二叉树中有很多的空指针,可以让这些指针按照某种顺序指向下一个、前一个节点,这样在遍历时可以不用递归而可以使用循环遍历,可以提高树的遍历速度。那么问题来了,对二叉树进行线索化后,怎么才能区分一个指针是左右结点还是前驱后后继呢。其实这里的话我们可以在构造线索二叉树的时候添加一个数据项用于记录左右子树的标记,值为真表示指向后继,值为假指向子结点。
话不多说先来设计一下数据项:
typedef struct TreeNode
{
int data;
struct TreeNode *left;
struct TreeNode *right;
bool rflag;//为真时,right指向后继;否则指向右子树
}TreeNode;
下面来开始线索二叉树的各种运算操作:
创建结点
//创建结点
TreeNode *create_node(int data)
{
TreeNode *node=malloc(sizeof(TreeNode));
node->data=data;
node->left=NULL;
node->right=NULL;
node->rflag=false;
return node;
}
插入
void _insert(TreeNode **root,TreeNode *node)
{
if(NULL==*root)
{
*root=node;
return;
}
if(node->data<(*root)->data)
_insert(&(*root)->left,node);
else _insert(&(*root)->right,node);
}
//插入
void insert_tree(TreeNode **root,int data)
{
_insert(root,create_node(data));
}
中序
//中序
void midorder(TreeNode *root)
{
if(NULL==root) return;
midorder(root->left);
printf("%d ",root->data);
midorder(root->right);
}
按中序遍历创建线索(线索化)
//上一个结点
TreeNode *prev=NULL;
//创建线索 按照中序遍历
void create_clue(TreeNode *root)
{
if(NULL==root) return;
//左
create_clue(root->left);
//设置前驱
/*if(NULL==root->left->)
{
root->left=prev;
root->lflag=true;
}*/
//根
//通过中序遍历找到root的上一个结点,如果该结点不为空,且右子树为空,则右子树指向root,也就是该结点的下一个结点
if(NULL!=prev && NULL==prev->right)
{
prev->rflag=true;
prev->right=root;
}
//如果不是,那么root就变成上一个结点
prev=root;
//右
create_clue(root->right);
}
按照线索进行遍历
//按照线索进行遍历
void show_clue(TreeNode *node)
{
while(node)
{
while(node->left) node=node->left;
printf("%d ",node->data);
while(node->rflag)
{
node=node->right;
printf("%d ",node->data);
}
node=node->right;
}
printf("\n");
}
完毕,下面简单测试
int main(int argc,const char* argv[])
{
TreeNode *root=NULL;
for(int i=0;i<10;i++)
{
int data=rand()%100;
insert_tree(&root,data);
}
midorder(root);
printf("\n");
create_clue(root);
show_clue(root);
return 0;
}
over