主要操作是以下:
- 创建二叉树
- 克隆二叉树
- 求二叉树的高度
- 求二叉树中结点的个数
- 求二叉树的叶子结点个数
- 求二叉树中第k层结点的个数
- 判断一个节点是否在一棵二叉树中
- 求结点的左孩子
- 求结点的右孩子
- 求结点的父结点
- 求二叉树的镜像(递归与非递归)
- 判断一棵树是否是完全二叉树
- 根据先序和中序序列,求出这棵树
创建二叉树
树的定义是递归创建的,所以创建树也可以递归地创建一棵树,首先需要一个序列,按什么顺序来创建,我采用了前序的遍历方式来实现,所以给一个前序的序列,为空的子树给#。
TreeNode* TreeCreate(TreeNodeType array[],size_t size ,size_t* index, TreeNodeType null_node)
{
if(array==NULL||index==NULL)
{
return NULL;
}
if(*index>size)
{
return NULL;
}
TreeNode* root=NULL;
if(array[*index]!=null_node)
{
root=CreatNode(array[*index]);
++(*index);
root->lchild=TreeCreate(array,index,null_node);
++(*index);
root->rchild=TreeCreate(array,index,null_node);
}
return root;
}
克隆二叉树
克隆的思路比较简单,首先创建一个根节点,然后将src的所有结点值依次复制,然后递归的克隆左右子树。
TreeNode* TreeClone(TreeNode* root)
{
if(root==NULL)
{
return NULL;
}
TreeNode* dst=CreatNode(root->data);
dst->data=root->data;
dst->lchild=TreeClone(root->lchild);
dst->rchild=TreeClone(root->rchild);
return dst;
}
求二叉树的高度
求二叉树的高度这个问题用递归来解决,其实非常容易。
要求一个树的高度,可以转换为求它左右子树中高的那棵树的高度+1。以次类推。
size_t TreeHeight(TreeNode* root)
{
if(root==NULL)
{
return 0;
}
if(TreeHeight(root->lchild)>TreeHeight(root->rchild))
{
return TreeHeight(root->lchild)+1;
}
if(TreeHeight(root->lchild)<=TreeHeight(root->rchild))
{
return TreeHeight(root->rchild)+1;
}
return 0;
}
求二叉树中结点的个数
求结点个数,其实就是求左右子树的结点个数+1。
递归下去就可以解决。
size_t TreeSize(TreeNode* root)
{
if(root==NULL)
{
return 0;
}
return TreeSize(root->lchild)+TreeSize(root->rchild)+1;
}
求二叉树的叶子结点个数
叶子结点:左右子树为空的结点就是叶子结点,同样也是采取递归的思路。
size_t TreeLeafSize(TreeNode* root)
{
if(root==NULL)
{
return 0;
}
if(root->lchild==NULL&&root->rchild==NULL)
{
return 1;
}
return TreeLeafSize(root->lchild)+TreeLeafSize(root->rchild);
}
求二叉树第k层结点的个数
求二叉树第k层结点的个数,可以转换为求左右子树的第k-1层结点的个数。
size_t TreeKLevelSize(TreeNode* root, int K)
{
if(root==NULL||K<1)
{
return 0;
}
if(K==1)
{
return 1;
}
return TreeKLevelSize(root->lchild,K-1)+TreeKLevelSize(root->rchild,K-1);
}
判断一个结点是否在二叉树中
采用先序遍历的思路。
先访问该节点,再遍历左子树,再遍历右子树。
此时的访问操作:就是比较。
TreeNode* TreeFind(TreeNode* root, TreeNodeType to_find)
{
if(root==NULL)
{
return NULL;
}
if(to_find==root->data)
{
return root;
}
TreeNode* ret1 = TreeFind(root->lchild,to_find);
TreeNode* ret2 = TreeFind(root->rchild,to_find);
return ret1 != NULL ? ret1 : ret2;
}
求二叉树的父结点,左孩子,右孩子
TreeNode* LChild(TreeNode* node)
{
if(node==NULL)
{
return NULL;
}
return node->lchild;
}
TreeNode* RChild(TreeNode* node)
{
if(node==NULL)
{
return NULL;
}
return node->rchild;
}
TreeNode* Parent(TreeNode* root, TreeNode* node)
{
if(root==NULL)
{
return NULL;
}
if(root->lchild==node||root->rchild==node)
{
return root;
}
TreeNode* lresult=Parent(root->lchild,node);
TreeNode* rresult=Parent(root->rchild,node);
return lresult!=NULL?lresult:rresult;
}
求二叉树的镜像
思路与二叉树的遍历相同,只是此时的访问动作变成了交换左右子树。
非递归的求法只需要采用层序遍历的方式即可。也可以采用非递归遍历的任何一种方法都可以。
void TreeMirror(TreeNode* root)
{
if(root==NULL)
{
return;
}
Swap(&root->lchild,&root->rchild);
TreeMirror(root->lchild);
TreeMirror(root->rchild);
}
void TreeMirrorByLoop(TreeNode* root)
{
if(root==NULL)
{
return;
}
SeqQueue q;
SeqQueueInit(&q);
SeqQueuePush(&q,root);
while(1)
{
SeqQueType front;
int ret=SeqQueueTop(&q,&front);
if(ret==0)
{
return;
}
Swap(&root->lchild,&root->rchild);
SeqQueuePop(&q);
if(root->lchild!=NULL)
{
TreeMirrorByLoop(root->lchild);
}
if(root->rchild!=NULL)
{
TreeMirrorByLoop(root->rchild);
}
}
}
判断一个树是否是完全二叉树
首先要清楚,完全二叉树的描述思路:
遍历结束,满足以上条件的就是完全二叉树。
int IsCompleteTree(TreeNode* root)
{
if(root==NULL)
{
return 0;
}
SeqQueue q;
SeqQueueInit(&q);
SeqQueuePush(&q,root);
TreeNode* front=NULL;
int if_start_step2_flag=0;
//层序遍历
while(SeqQueueTop(&q,&front))
{
SeqQueuePop(&q);
//阶段一:任何一个节点同时具备左右子树,一旦发现某个结点不具备该条件,进行以下判断:
if(if_start_step2_flag==0)
{
if(front->lchild!=NULL&&front->rchild!=NULL)
{
SeqQueuePush(&q,front->lchild);
SeqQueuePush(&q,front->rchild);
}
// a)当前结点只有右子树,一定不是完全二叉树
else if(front->rchild!=NULL&&front->lchild==NULL)
{
return 0;
}
// b)如果当前结点只有左子树,进入阶段二
else if(front->lchild!=NULL&&front->rchild==NULL)
{
if_start_step2_flag=1;
SeqQueuePush(&q,front->lchild);
}
// c)如果当前结点没有子树,进入阶段二
else
{
if_start_step2_flag=1;
}
}
else
{
//阶段二:
//任何一个节点都必须没有子树
if(front->lchild==NULL&&front->rchild==NULL)
{
;
}
else
{
return 0;
}
}
}
return 1;
}
给出先序和中序序列,求出这棵树
思路:首先通过遍历先序序列,可以在中序序列中找到该子树的左右子树区间,然后递归地去创建左子树和右子树。
int Find(TreeNodeType in_order[],size_t in_order_left,size_t in_order_right,TreeNodeType value)
{
size_t i=0;
for(i=in_order_left;i<in_order_right;i++)
{
if(in_order[i]==value)
{
return i;
}
}
return -1;
}
TreeNode* _TreeRebuild(TreeNodeType pre_order[],size_t size,size_t* pre_order_index,
TreeNodeType in_order[],size_t in_order_left,size_t in_order_right)
{
if(in_order_left>=in_order_right)
{
return NULL;
}
if(pre_order==NULL||in_order==NULL||size==0)
{
return NULL;
}
if(pre_order_index==NULL)
{
return NULL;
}
//根据先序序列遍历结果创建结点
TreeNode* new_node=CreatNode(pre_order[*pre_order_index]);
(*pre_order_index)++;
//查找当前结点在中序序列中的位置
size_t cur_root_in_order_index=Find(in_order,in_order_left,in_order_right,new_node->data);
assert(cur_root_in_order_index!=(size_t)-1);
//递归地创建左子树
new_node->lchild=_TreeRebuild(pre_order,size,pre_order_index,in_order,in_order_left,cur_root_in_order_index);
//递归地创建右子树
new_node->rchild=_TreeRebuild(pre_order,size,pre_order_index,in_order,cur_root_in_order_index+1,in_order_right);
return new_node;
}
TreeNode* TreeRebuild(TreeNodeType pre_order[],TreeNodeType in_order[],size_t size)
{
if(pre_order==NULL||in_order==NULL)
{
return NULL;
}
size_t pre_order_index=0;
size_t in_order_left=0;
size_t in_order_right=size;
return _TreeRebuild(pre_order,size,&pre_order_index,in_order,in_order_left,in_order_right);
}