二叉树:或为空,或由根节点及左右子树构成。
每个节点最多可以有两棵子树。
左右子树是有顺序的,不可颠倒
满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
满二叉树的叶子只可以出现在最后一层
完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
性质:
二叉树度为0的结点数n0与度为2的结点数关系:n0=n2+1
推导:总结点数:n=n0+n1+n2;连接数总是等于总结点数减一(n-1),且等于n1+2*n2;
联立上面几式,可推导。
性质:具有n个结点的完全二叉树深度为[log(n)]+1
二叉树的存储:二叉链表
typedef int ElemType;
struct BiTNode
{
ElemType data;
BiTNode *lchild,*rchild;
}*BiTree;
前序遍历:若二叉树为空,则空操作返回;否则先返回空结点,然后前序遍历左子树,再前序遍历右子树。
中序遍历:若空,则空操作返回;否则从根结点开始(注意并不是先访问根结点),先中序遍历左子树,然后访问根结点,再中序遍历右子树。
后序遍历:若空,则空操作返回;否则从左到右先叶子后结点方式遍历左右子树,最后根结点。
二叉树的建立和遍历算法:
前序遍历:
前序遍历上图二叉树,输出每个结点所在层数
#include <iostream>
using namespace std;
#define MAX_SIZE 100
typedef int ElemType;
struct BiTNode
{
ElemType data;
BiTNode *lchild,*rchild;
};
typedef BiTNode *BiTree;
void CreateTree(BiTree *T)
{
char c;
scanf("%c",&c);
if(c==' ')
*T=NULL;
else
{
*T=(BiTNode *)malloc(sizeof(BiTNode));
(*T)->data=c;
CreateTree(&(*T)->lchild);
CreateTree(&(*T)->rchild);
}
}
void visit(char c,int level)
{
printf("%c在第%d层\n",c,level);
}
void PreOrderTraverse(BiTree T,int level)
{
if(T)
{
visit(T->data,level);
PreOrderTraverse(T->lchild,level+1);
PreOrderTraverse(T->rchild,level+1);
}
}
void main()
{
BiTree T;
CreateTree(&T);
int level=1;
PreOrderTraverse(T,level);
}
线索二叉树代码实现:
#include <iostream>
using namespace std;
typedef int ElemType;
//PointTag:线索存储标志位
//Link:表示指向左右孩子的指针
//Thread:表示指向前驱后继的指针
typedef enum{Link,Thread}PointTag;
struct BiThrNode
{
ElemType data;
BiThrNode *lchild,*rchild;
PointTag ltag;
PointTag rtag;
};
typedef BiThrNode *BiThrTree;
//定义全局变量,保存刚访问过的节点
BiThrTree pre;
//前序遍历输入数据。创建二叉树
void CreateBiThrTree(BiThrTree *T)
{
char c;
scanf("%c",&c);
if(c==' ')
*T=NULL;
else
{
*T=(BiThrNode *)malloc(sizeof(BiThrNode));
(*T)->data=c;
(*T)->ltag=Link;
(*T)->rtag=Link;
CreateBiThrTree(&(*T)->lchild);
CreateBiThrTree(&(*T)->rchild);
}
}
//中序遍历线索化
void InThreading(BiThrTree T)
{
if(T)
{
InThreading(T->lchild);//递归左孩子线索化
if(!T->lchild)//没有左孩子
{
T->ltag=Thread;//前驱线索
T->lchild=pre;//左孩子指针指向前驱
}
if(!pre->rchild)//若前驱没有右孩子
{
pre->rtag=Thread;//后继线索
pre->rchild=T;//前驱后继指向后继
}
pre=T;
InThreading(T->rchild);//递归右孩子线索化
}
}
//建立头结点,中序线索二叉树(建立头结点和第一个与最后一个结点及根结点关系)
void InOrderThreading(BiThrTree *p,BiThrTree T)
{
*p=(BiThrNode*)malloc(sizeof(BiThrNode));//头结点
(*p)->ltag=Link;
(*p)->rtag=Thread;
(*p)->rchild=*p;
if(!T)
{
(*p)->lchild=(*p);
}
else
{
(*p)->lchild=T;//头结点左指针指向根结点
pre=*p;
InThreading(T);//遍历到最后一个结点,赋给pre
pre->rchild=*p;//最后一个结点的rchild指向头结点
pre->rtag=Thread;
(*p)->rchild=pre;//头结点后继为最后一个结点
}
}
void visit(char c)
{
printf("%c",c);
}
//中序遍历二叉树,非递归
void InOrderTraverse(BiThrTree T)
{
BiThrTree p;
p=T->lchild;//p为根结点,T为头结点
while(p!=T)//非空
{
while(p->ltag==Link)
{
p=p->lchild;//最左边结点,即中序遍历第一个结点
}
visit(p->data);
while(p->rtag==Thread&p->rchild!=T)//访问p的后继
{
p=p->rchild;
visit(p->data);
}
p=p->rchild;//p进入右子树
}
}
void main()
{
BiThrTree p, T=NULL;
CreateBiThrTree(&T);
InOrderThreading(&p,T);
InOrderTraverse(p);
}