二叉树
二叉树的性质
性质1:在二叉树的第i层上至多有 2 i − 1 2^{i-1} 2i−1
性质2:深度为k的二叉树至多有 2 k − 1 2^k-1 2k−1个结点
性质3:对任何一颗二叉树T,如果其叶子数为 n 0 n_0 n0,度为2的结点数为 n 2 n_2 n2,则 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1
性质4:具有n个结点的完全二叉树的深度为 [ l o g 2 n ] + 1 [log_2n]+1 [log2n]+1
性质5:略
顺序存储
按满二叉树的结点层次编号,依次存放二叉树中的数据元素
特点:
1.结点间关系蕴含在其存储位置中
2.浪费空间,适用于存满二叉树和完全二叉树
遍历二叉树
DLR——先序遍历
LDR——中序遍历
LRD——后序遍历
递归算法:
时间效率:O(n)
空间效率:O(n)
非递归算法(栈)
层次遍历(队列)
复制二叉树
1.如果是空树,递归结束;
2.否则,申请新结点空间,复制根结点
1)递归复制左子树
2)递归复制右子树
int Copy(BiTree T, BiTree &NewT){
if(T == NULL){
NewT = NULL;
return 0;
}
else{
NewT = new BiTNode;
NewT->data = T->data;
Copy(T->lChild, NewT->lChild);
Copy(T->rChild, NewT->rChild);
}
}
计算二叉树的深度
1.如果是空树,则深度为0;
2.否则,递归计算左子树的深度记为m,递归计算右子树的深度记为n,二叉树的深度则为m与n的较大者加1.
int Depth( BiTree T){
if(T == NULL) return 0;
else{
m = Depth(T->lChild);
n = Depth(T->rChild);
if( m > n) return (m + 1);
else return (n + 1);
}
}
计算二叉树结点总数
1.如果是空树,则结点个数为0;
2.否则,结点个数为左子树的结点个数+右子树的结点个数+1.
int NodeCount(BiTree T){
if(T == NULL){
return 0;
else
return NodeCount(T->lChild) + NodeCount(T->rChild) + 1;
}
计算二叉树叶子结点数
1.如果是空树,则叶子数结点个数为0;
2.否则,为左子树的叶子结点个数+右子树的叶子结点个数
int LeadCount(BiTree T){
if(T == 0)
return 0;
if(T->lChild == NULL && T->rChild == NULL)
return 1;
else
return LeadCount(T->lChild) + LeadCount(T->rChild);
}
线索二叉树
提出问题:如何寻找特定遍历序列中二叉树结点的前驱和后继?
解决方法:
1.通过遍历寻找——费时间
2.再增设前驱、后继指针域——增加了储存负担。
3.利用二叉链表中的空指针域。
利用二叉链表中的空指针域:如果某个结点的左孩子为空,则将空的左孩子指针域改为指向其前驱;如果某结点的右孩子为空,则将空的右孩子指针域改为指向其后继。
这种该表指向的指针称为“线索”,加上了线索的二叉树称为线索二叉树(Threaded Binary Tree)
为区分lchild和rchild指针到底是指向孩子的指针,还是指向前驱或者后继的指针,对二叉链表中每个结点增设两个标志域ltag和rtag,并约定:
ltag = 0 lchild指向该结点的左孩子
ltag = 1 lchild指向该结点的前驱
rtag = 0 rchild指向该结点的右孩子
rtag = 1 rchild指向该结点的后继
结点的结构为:
typedef struct BiThrNode{
int data;
int ltag, rtag;
struct BiThrNode *lchild, rchild;
}BiThrNode, *BiThrTree;