1.树的遍历
遍历: 按一定规律走遍树的各个顶点,且使每一顶点仅被访问一次,即找一个完整而有规律的走法,以得到树中所有结点的一个线性排列
常用方法
先根(序)遍历:先访问树的根结点,然后依次先根遍历根的每棵子树
后根(序)遍历:先依次后根遍历每棵子树,然后访问根结点
按层次遍历:先访问第一层上的结点,然后依次遍历第二层,……第n层的结点
2.二叉树的遍历
方法
先序遍历:先访问根结点,然后分别先序遍历左子树、右子树
中序遍历:先中序遍历左子树,然后访问根结点,最后中序遍历右子树
后序遍历:先后序遍历左、右子树,然后访问根结点
按层次遍历:从上到下、从左到右访问各结点
2.1 递归算法
先序遍历算法:
void preorder(JD *bt)
{ if(bt!=NULL)
{ printf("%d\t",bt->data);
preorder(bt->lchild);
preorder(bt->rchild);
}
}
中序遍历算法:
void inorder(JD *bt)
{ if(bt!=NULL)
{ inorder(bt->lchild);
printf("%d\t",bt->data);
inorder(bt->rchild);
}
}
后序遍历算法:
void postorder(JD *bt)
{ if(bt!=NULL)
{ postorder(bt->lchild);
postorder(bt->rchild);
printf("%d\t",bt->data);
}
}
2.2 非递归算法
void inorder(JD *bt)
{ int i=0;
JD *p,*s[M];
p=bt;
do
{ while(p!=NULL)
{ s[i++]=p;
p=p->lchild;
}
if(i>0)
{ p=s[--i];
printf("%d\t",p->data);
p=p->rchild;
}
}while(i>0||p!=NULL);
}
3. 遍历算法的应用
- 按先序遍历序列建立二叉树的二叉链表
JD *crt_bt_pre(JD *bt)
{ char ch;
printf("ch=");
scanf("%c",&ch);
if(ch==' ') bt=NULL;
else
{ bt=(JD *)malloc(sizeof(JD));
bt->data=ch;
bt->lchild=crt_bt_pre(bt->lchild);
bt->rchild=crt_bt_pre(bt->rchild);
}
return(bt);
}
- 统计二叉树中叶子结点个数算法
#include <alloc.h>
#include <stdio.h>
typedef struct node
{ char data;
struct node *lchild,*rchild;
}JD;
void countleaf(JD *bt,int *count)
{ if(bt!=NULL)
{ if((bt->lchild==NULL)&&(bt->rchild==NULL))
{ (*count)++;
return;
}
countleaf(bt->lchild,count);
countleaf(bt->rchild,count);
}
}
JD *crt_bt_pre(JD *bt)
{ char ch;
printf("ch=");
scanf("%c",&ch);
if(ch==' ') bt=NULL;
else
{ bt=(JD *)malloc(sizeof(JD));
bt->data=ch;
bt->lchild=crt_bt_pre(bt->lchild);
bt->rchild=crt_bt_pre(bt->rchild);
}
return(bt);
}
void main()
{ /* ABC00DE0G00F000 */
JD *head=NULL;
int count=0;
head=crt_bt_pre(head);
countleaf(head,&count);
printf("count of leaf node is %d\n",count);
}
- 求二叉树的深度算法
#include <alloc.h>
#include <stdio.h>
typedef struct node
{ char data;
struct node *lchild,*rchild;
}JD;
JD *crt_bt_pre(JD *bt)
{ char ch;
printf("ch=");
scanf("%c",&ch);
getchar();
if(ch==' ') bt=NULL;
else
{ bt=(JD *)malloc(sizeof(JD));
bt->data=ch;
bt->lchild=crt_bt_pre(bt->lchild);
bt->rchild=crt_bt_pre(bt->rchild);
}
return(bt);
}
void treedepth(JD *bt,int *l,int *h)
{
int l1=0,l2=0,h1=0,h2=0;
if(bt!=NULL)
{ (*l)++;
if (*l>*h) *h=*l;
treedepth(bt->lchild,&l1,&h1);
treedepth(bt->rchild,&l2,&h2);
if (h1>h2) *h=*h+h1;
else *h=*h+h2;
}
}
void main()
{ /* ABC00DE0G00F000 */
JD *head=NULL;
int level=0,high=0;
head=crt_bt_pre(head);
treedepth(head,&level,&high);
printf("depth of tree is %d\n",high);
}
4.线索二叉树
4.1 线索二叉树定义
定义:
前驱与后继:在二叉树的先序、中序或后序遍历序列中两个相邻的结点互称为~
线索:指向前驱或后继结点的指针称为~
线索二叉树:加上线索的二叉链表表示的二叉树叫~
线索化:对二叉树按某种遍历次序使其变为线索二叉树的过程叫~
实现
在有n个结点的二叉链表中必定有n+1个空链域
在线索二叉树的结点中增加两个标志域
lt :若 lt =0, lc 域指向左孩子;若 lt=1, lc域指向其前驱
rt :若 rt =0, rc 域指向右孩子;若 rt=1, rc域指向其后继
结点定义
typedef struct node
{ int data;
int lt, rt;
struct node *lc, *rc;
}JD;
4.2 算法
按中序线索化二叉树
JD *zxxsh(JD *bt)
{ JD *p,*pr,*s[M],*t;
int i=0;
t=(JD *)malloc(sizeof(JD));
t->lt=0;
t->rt=1;
t->rc=t;
if(bt==NULL)
t->lc=t;
else
{ t->lc=bt;
pr=t;
p=bt;
do
{ while(p!=NULL)
{ s[i++]=p;
p=p->lc;
}
if(i>0)
{ p=s[--i];
printf("%c ",p->data);
if(p->lc==NULL)
{ p->lt=1;
p->lc=pr;
}
if(pr->rc==NULL)
{ pr->rt=1;
pr->rc=p;
}
pr=p;
p=p->rc;
}
}while(i>0||p!=NULL);
pr->rc=t;
pr->rt=1;
t->rc=pr;
}
return(t);
}
遍历中序线索二叉树
void zxblxss(JD *t)
{ JD *p;
p=t->lc;
do
{ while(p->lt==0)
p=p->lc;
printf("%c ",p->data);
while((p->rt==1)&&(p->rc!=t))
{ p=p->rc;
printf("%c ",p->data);
}
p=p->rc;
}while(p!=t);
}
在中序线索二叉树中找结点后继的方法:
(1)若rt=1, 则rc域直接指向其后继
(2)若rt=0, 则结点的后继应是其右子树的左链尾(lt=1)的结点
在中序线索二叉树中找结点前驱的方法:
(1)若lt=1, 则lc域直接指向其前驱
(2)若lt=0, 则结点的前驱应是其左子树的右链尾(rt=1)的结点