二叉树
- 1.基本概念
可以定义为结点的有限集合,这个集合可以为空集,或者由一个称为根的节点, - 2.基本形态
1、空树
2、只有一个根结点
3、有根结点和非空左子树
4、有根结点和非空右子树
5、有根结点且左右子树非空 - 3.相关概念
父结点:若x是y的前驱,y是x的后继,则称x为y的父结点
叶子结点:左右子树均为空二叉树的结点称为叶子结点
层次:规定根的层数为0,其他结点的层数等于父结点的层数加1
深度:二叉树结点的最大层数称为二叉树的高度 - 4.特殊的二叉树
1、满二叉树:若一个二叉树的任何结点都是树叶或者都有两个非空子树,则称这种二叉树为满二叉树
2、完全二叉树:若一个二叉树中,只有最下面两层的结点的子树个数小于2,其余各层结点都等于2,并且最下面一层的结点都是集中在该层的最左边。若设二叉树的深度为h,除第h层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。 - 5.二叉树的周游
1、先根次序周游:若二叉树非空,则先访问根,然后按先根次序访问左子树,最后再右子树
//递归算法:
void pre_order(pNode root, void(*func)(pNode node))
{
if (root == NULL)
{
return ;
}
func(root);
pre_order(root->left,func);
pre_order(root->right,func);
}
//非递归算法:先将根结点压入栈中,然后取栈头元素进行访问,先压入栈头元素的右子树,再压入栈头元素的左子树
void npre_order(pNode root)
{
STACK *s = create_stack();
if(root == NULL) return ;
pNode c = root;
push(s,c);
while( isEmptyStack(s) != 0)
{
c = top(s);
pop(s);
if(c != NULL)
{
printf("%d-",c->data);
push(s,c->right);
push(s,c->left);
}
}
destroy_stack(&s);
printf("\n");
}
2、中根次序周游:若二叉树非空,则周游左子树,再访问根,最后再访问右子树
//递归算法:
void mid_order(pNode root, void(*func)(pNode node))
{
if (root == NULL)
{
return ;
}
mid_order(root->left, func);
func(root);
mid_order(root->right,func);
}
//非递归算法
void nmid_order(pNode root)
{
STACK *s = create_stack();
pNode c = root;
if(c == NULL) return;
do
{
while(c != NULL)
{
push(s,c);
c = c->left;
}
c = top(s);
pop(s);
printf("%d-",c->data);
c = c->right;
}while(c != NULL || isEmptyStack(s) != 0);
destroy_stack(&s);
printf("\n");
}
3、后根次序周游:若二叉树非空,则先周游左子树,再周游右子树,最后访问根
//递归算法:
void back_order(pNode root, void(*func)(pNode node))
{
if (root == NULL)
{
return ;
}
back_order(root->left,func);
back_order(root->right,func);
func(root);
}
//非递归算法:
void nback_order(pNode root)
{
STACK *s = create_stack();
pNode c = root;
pNode cc;
while(c != NULL || isEmptyStack(s) != 0)
{
while(c != NULL)
{
push(s,c);
cc = c->right;
c = c->left;
if(c == NULL) c = cc;
}
c = top(s);
pop(s);
printf("%d-",c->data);
if(isEmptyStack(s) != 0 && top(s)->left == c)
{
c = top(s)->right;
}
else c = NULL;
}
destroy_stack(&s);
printf("\n");
}
4、层次周游(广度周游):逐层从左到右周游
通过队列,先加入根结点;然后访问队头元素;若队头有子树,则先加入左子树至队尾,再加入右子树;队头元素出队,循环至队列为空;
void level_order(pNode root)
{
QUEUE *q = create_queue();
if(root == NULL) return;
pNode c = root;
pNode cc;
add_queue(q,c);
while( isEmptyQueue(q) != 0 )
{
c = frontQueue(q);
printf("%d-",c->data);
del_queue(q);
cc = c->left;
if(cc != NULL) add_queue(q,cc);
cc = c->right;
if(cc != NULL) add_queue(q,cc);
}
destroy_queue(&q);
printf("\n");
}
- 6.二叉树的打印
void print_tree(pNode root,int ident,int depth[])
{
if(ident > 0)
{
for(int i = 0; i < ident - 1; ++i)
{
printf(depth[i] ? "│ " : " ");
}
printf(depth[ident-1] ? "├── " : "└── ");
}
if(! root)
{
printf("(null)\n");
return;
}
printf("%d\n", root->data);
if(!root->left && !root->right)
{
return;
}
depth[ident] = 1;
print_tree(root->left, ident + 1,depth);
depth[ident] = 0;
print_tree(root->right, ident + 1,depth);
}