概念
- 树是n个结点的有限集合
- 有且仅有一个特定的称为根的结点。
- 当n>1时,其余结点可分为m(m>0)个互不相交的有限集合,其中每一个集合本身又是一棵树,称为根结点的子树。
☆n个结点的树中有n-1条边。
- 基本术语:
- 祖先结点和子孙结点
- 双亲结点和孩子结点
- 兄弟结点
- 度:树中一个结点的子结点
- 结点的层次
- 结点的高度
- 结点的深度
- 树的高度:树种结点的最大层数
二叉树
存储结构
typedef struct BitNode {
int data;
struct BitNode *lchild, *rchild;
}BitNode, *BitNode;
- 遍历
先序遍历:
若二叉树非空:
(1)访问根结点
(2)先序遍历左子树
(3)先序遍历右子树
线索二叉树
线索化
若无左子树,则将左指针指向其前驱结点
若无右子树,则将右指针指向其后继结点
结构
ltag | lchild | data | rchild | rtag |
- tag=0 左(右)孩子
- tag=1 前(后)继
中序线索二叉树
void InThread(ThreadTree &p,ThreadTree &pre)
{
if(p!=NULL){
InThread(p->lchild,pre);
if(p->lchild==NULL){
p->lchild=pre;
p->ltag=1;
}
if(pre!=NULL&&pre-<rchild==NULL)
{
pre->rchild=p
pre->rtag=1;
}
pre=p;
InThread(p->rchild,pre);
}
}
void CreateInThread(ThreadTree T)
{
ThreadTree pre=NULL;
if(T!=NULL){
InThread(T,pre);
pre->rchild=NULL;
pre->tag=1;
}
}
- 中序线索二叉树遍历
ThreadNode *Firstnode(ThreadNode *p){
while(p->tag==0)
p=p->lchild;
return p;
}
ThreadNode *Nextnode(ThreadNode *p){
if(p->rtag==o)
return Firstnode(p->rchild);
else return p->rchild;
}
void Inoder(ThreadNode *T){
for(ThreadNode *p=Firstnode(T);p!=NULL;p=Nextnode(p))
visit(p);
}
树的存储结构
- 双亲表示法
采用一组连续的存储空间来存储每个结点,同时在每个节点中增设一个伪指针,指示双亲结点在数组中的位置。根结点的下标为0,其伪指针域为-1。
#define MAX_TREE_SIZE 100
typedef struct{
ElemType data;
int parent;
}PTNode;
typedef struct{
PTNode nodes[MAX_TREE_SIZE];
int n;
}PTree;
- 孩子表示法
将每个结点的孩子结点都用单链表连接起来形成一个线性结构,n个结点具有n个孩子链表
#define MAX_TREE_SIZE 100
typedef struct{
int child;
struct CNode *next;
}CNode;
typedef struct{
ElemType data;
struct CNode *child;
}PNode;
typedef struct{
PNode nodes{MAX_TREE_SIZE};
int n;
}CTree;
- 孩子兄弟表示法
以二叉链表作为树的存储结构,又称二叉树表示法
二叉排序树BST
也称二叉查找树。
- 左子树结点值<根结点值<右子树结点值
- 查找:
若小于根结点时查找左子树,大于根结点时,查找右子树
BSTNode *BST_Search(BITREE T,ELEMTYPE key,BSTNode *&p){
p=NULL;
while(T!=NULL&key!=T->data){
p=T;
if(key<T->data)T=T->lchild;
else T=T->rchild;
}
return T;
}
- 插入:
小于根结点插入左子树,大于根结点插入右子树,等于根结点时不插入
int BST_Insert(BITree &T,KeyType k){
if(T==NULL){
T=(BITree)malloc(sizeof(BSTNode));
T->key=k;
T->lchild=T->rchild=NULL;
return 1;
}
else if(k==T->key)return 0;
else if(k<T->key)return BST_Insert(T->lchild,k);
else return BST_Insert(T->rchild,k);
}
- 构造:
同插入
void Create_BST(BITree &T,KeyType str[],int n){
T=NULL;
int i=0;
while(i<n){
BST_Insert(T,str[i]);
i++;
}
}
- 删除:
- 若被删除结点z是叶结点,则直接删除。
- 若被删除结点z只有一棵子树,则让z的子树成为z父节点的子树,代替z结点。
- 若被删除的结点z有两棵子树,则让z的中序序列直接后继代替z,并删去直接后继结点。
平衡二叉树
- 任意结点的平衡因子的绝对值不超过一
平衡因子:左子树高度-右子树高度 - 高度为h的最小平衡二叉树的结点数Nh
平衡二叉树的判断
- 利用递归的后序遍历过程:
- 判断左子树是一棵平衡二叉树
- 判断右子树是一棵平衡二叉树
- 判断以该结点为根的二叉树为平衡二叉树
void Judge_AVL(BiTree bt,int &balance,int &h)
{
int bl=0,br=0,hl=0,hr=0;
if(bt=NULL)
{
h=0;
balance=1;
}
else if(bt->lchild==NULL&&bt->rchild=NULL)
{
h=1;
balance=1;
}
else{
Judge_AVL(bt->lchild,bl,hl);
Judge_AVL(bt->rchild,br,hr);
if(hl>hr)h=hl+1;
else h=hr+1;
if(abs(hl-hr)<2&&bl==1&&br==1)
balance=1;
else balance=0;
}
}
- 平衡二叉树的插入
( 先插入,再调整 )
哈弗曼树
带权路径长度
- 路径长度:路径上所经历边的个数
- 结点的权:结点被赋予的数值
树的带权路径长度 - 树中所有叶节点的带权路径长度之和,记为,
WPL=∑WiLi
哈弗曼树:带权路径长度最小的树