目录
遍历二叉树
遍历二叉树是指按某条搜索路径巡防树中的每个节点,使得每个节点均被访问一次,而且仅被访问一次。
由二叉树的递归定义可知,二叉树由三个基本单元构成:根节点、左子树和右子树。如果用L、D、R分别表示遍历左子树、访问根节点和遍历右子树再限定先左后右,则有以下3种情况:先序遍历(DLR)、中序遍历(LDR)、后序遍历(LRD)。其操作定义如下:
1.先序遍历二叉树:
若二叉树为空,则操作为空,否则:
1>访问根节点;
2>先序遍历左子树;
3>先序遍历右子树;
2.中序遍历而二叉树:
若二叉树为空,则操作为空,否则:
1>中序遍历左子树;
2>访问根节点;
3>中序遍历右子树;
3.后序遍历二叉树:
若二叉树为空,则操作为空,否则:
1>后序遍历左子树;
2>后序遍历右子树;
3>访问根节点;
遍历的算法及应用
三种遍历的算法
下面是关于先序遍历的算法:
#include<stdio.h>
#include<malloc.h>
#define OK 1
#define OVERFLOW -2
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
//创建二叉链表
int CreateBiTree(BiTree &T)
{
char ch;
scanf("%c",&ch);
if(ch=='#') //递归结束建空树
{ //递归创建二叉树
T=NULL;
}
else
{
T=new BiTNode; //生成根节点
T->data=ch; //根节点数据域置为ch
CreateBiTree(T->lchild); //递归创建左子树
CreateBiTree(T->rchild); //递归创建右子树
}
return OK;
}
//定义二叉树的先序遍历
void PreOrderTraverse(BiTree T)
{
if(T)
{
printf("%c",T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
int main()
{
BiTree T;
CreateBiTree(T);
printf("\n 先序遍历的结果是:");
PreOrderTraverse(T);
printf("\n");
}
中序遍历算法
//定义二叉树的中序遍历
void InOrderTraverse(BiTree T)
{
if(T)
{
InOrderTraverse(T->lchild);
printf("%c",T->data);
InOrderTraverse(T->rchild);
}
}
后序遍历算法
//定义二叉树的后序遍历
void PostOrderTraverse(BiTree T)
{
if(T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c",T->data);
}
}
复制二叉树
复制二叉树是利用已有的一棵二叉树复制得到另外一棵与其完全相同的二叉树。
复制特点如下:若二叉树不为空,则首先复制根节点,相当于二叉树先序遍历算法中访问根节点的语句,然后分别复制二叉树根节点的左子树和右子树,这相当于先序遍历二叉树中递归遍历左子树和右子树的语句。
算法思路:
1>申请一个新节点空间,复制根节点;
2>递归复制左子树;
3>递归复制右子树。
void Copy(BiTree T,BiTree &NewT)
{
if(T=NULL) //如果是空树,递归结束
{
NewT=NULL;
return;
}
else
{
NewT=new BiTNode;
NewT->data=T->data; //复制根节点
Copy(T->lchild,NewT->lchild); //递归复制左子树
Copy(T->rchild,NewT->rchild); //递归复制右子树
}
}
计算二叉树的深度
二叉树的深度就是树中节点的最大层次,二叉树的深度就是左右子树深度的较大者加一。
算法思路:
如果是空树,递归结束,深度为0,否则:
1>递归计算左子树的深度记为m;
2>递归计算右子树的深度记为n;
3>如果m>n,二叉树的深度为m+1,否则为n+1。
//计算二叉树的深度
int Depth(BiTree T)
{
if(T=NULL) //如果是空树,深度为0,递归结束
return 0;
else
{
m=Depth(T->lchild); //递归计算左子树的深度记为m
n=Depth(T->rchild); //递归计算右子树的深度记为n
if(m>n)
return (m+1); //二叉树的深度为母语你的较大者加1
else
return (n+1);
}
}
统计二叉树中节点的个数
如果二叉树是空树,则节点个数为0,递归结束,否则,节点个数为左子树的节点个数加上右子树的节点个数再加上1。
//统计二叉树T中节点的个数
int NodeCount(BiTree T)
{
if(T=NULL)
return 0; //如果是空树,则节点个数为0,递归结束
else
return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
//否则节点个数为左子树的节点个数加右子树的节点个数加1
}
树与森林
树的存储结构
下面有三种常用形式的存储结构来表示树:
1.双亲表示法
在这种表示方法中,以一组连续的存储单元存储树的节点,每个节点除了数据域data外,还附设一个parent域用以指示其双亲节点的位置。这种存储结构虽然利用了每个节点(除根节点之外)只有一个双亲的性质,求节点的双亲以及树的根都很方便,但是求节点的孩子要遍历整个结构。
2.孩子表示法
由于树中每个节点可能有多棵子树,则可用多重链表,即每个节点有多个指针域,其中每个指针指向一棵子树的根节点,此时链表中的节点有以下两种方式:
1>孩子链表
每个节点有data域还有其孩子域。
2>带双亲的孩子链表
每个节点有data域还有其双亲域以及孩子域。
3.孩子兄弟表示法
孩子兄弟表示法又称二叉树表示法,或二叉链表表示法,即以二叉链表作为树的存储结构。链表中节点的两个链域分别指向该节点的第一不该 子节点所下一个兄弟节点, 分别命名为istchid域和nextsibling域。
//树的二叉链表(孩子-兄弟)存储表示
typedef struct CSNode
{
ElemType data;
struct CSNode *firstchild, *nextsibling;
}CSNode, *CSTree;
森林与二叉树的转换
树转变二叉树:将兄弟相连再将双亲与非长子的线去掉。(兄弟相连留长子)
二叉树转变树:将左孩子右连连双亲,去掉原来连右孩子的线。(左孩右右连双亲,去掉原来右孩线)
二叉树转变森林:将每个树都通过孩子兄弟表示法转变为二叉树,再使这些二叉树的根节点相连。(去掉全部右孩线,孤立二叉再还原)
森林转变二叉树:的形式是将森林的根节点及其右节点分隔开,再将分隔后的得到的二叉链表转化为树。(根去右孩,二叉变树)