更多二叉树相关概念请看http://blog.csdn.net/zhang_xinxiu/article/details/12904635
一、二叉树相关概念:
- 路径:对于节点n1 n2 n3….nk从n1到nk的路径长度为k-1
- 节点的层数:只有一个根节点,则层数为1,其余节点的层数为双亲节点的层数加1
- 树的深度:树中所有节点的最大层数称为树的深度,只有根节点深度为1。
- 满二叉树:所有分支节点存在左子树和右子树,并且所有的叶子节点都在同一层上。
- 完全二叉树:对于树中的节点从上至下、从左到右顺序进行编号,且与满二叉树的位置编号相同。完全二叉树特点:叶子节点只能出现在最下层和次下层,且最下层的叶子节点集中在树的左边,满二叉树肯定是完全二叉树,反之不一定。如果完全二叉树中子节点个数分别为0、1、2的节点数分别用n0 n1 n2表示,节点总数n=n0+n1=n2,且n1只能为0或者1。
二、二叉树相关性质:
- 一颗深度为k的二叉树中,最多有2的k次方-1个节点(满二叉树),最少有k个节点
- 对于一颗非空二叉树,度为0的节点总是比度为2的几点多一个,即:n0=n2+1;
- 具有n个节点的完全二叉树的深度为【logn】+1,【】为向下取整;
- 对于n个节点从1开始编号的完全二叉树,对于节点编号i的节点:
(1)如果2i<=n,则序号为i的节点的左孩子节点的序号为2i;如果2i>n,则序号为i的节点无左孩子;
(2)如果2i+1<=n,则i节点有孩子序号为2i+1,如果2i+1>n,则i无右孩子。
三、二叉树的遍历:
1、先序遍历:先序遍历是先输出根节点,再输出左子树,最后输出右子树。上图的先序遍历结果就是:ABCDEF
2、中序遍历:中序遍历是先输出左子树,再输出根节点,最后输出右子树。上图的中序遍历结果就是:CBDAEF
3、后序遍历:后序遍历是先输出左子树,再输出右子树,最后输出根节点。上图的后序遍历结果就是:CDBFEA
#include <iostream> using namespace std; struct TNode { TNode * LeftChild; TNode * RightChild; char data; }; TNode *CreateTree() { TNode *pRoot=NULL; char data=0; cin>>data; if (data=='#') { pRoot=NULL; } else { pRoot=(TNode*)malloc(sizeof(TNode)); pRoot->data=data; pRoot->LeftChild=CreateTree(); pRoot->RightChild=CreateTree(); } return pRoot; } void PreTraverse(TNode *pRoot) { if (pRoot==NULL) { return; } cout<<pRoot->data<<' '; PreTraverse(pRoot->LeftChild); PreTraverse(pRoot->RightChild); } void InTraverse(TNode *pRoot) { if (pRoot==NULL) { return; } InTraverse(pRoot->LeftChild); cout<<pRoot->data<<' '; InTraverse(pRoot->RightChild); } void LastTraverse(TNode *pRoot) { if (pRoot==NULL) { return; } LastTraverse(pRoot->LeftChild); LastTraverse(pRoot->RightChild); cout<<pRoot->data<<' '; } void main() { TNode *root=CreateTree(); cout<<"first order is: "; PreTraverse(root); cout<<endl; cout<<"middle order is: "; InTraverse(root); cout<<endl; cout<<"last order is: "; LastTraverse(root); cout<<endl; }
输出结果如下图:
四、二叉树删除操作
如右图,要删除B节点,要将D节点放入B的左孩子最右下孩子之后,也就是D’的位置。
A.left=B.left;
p=B.left;//也就是C
while(p.right!=null)
p=p.right;
p.right=B.right;
free(B);
五.建立完全二叉树
建立完全二叉树之前先给出遍历类型,例如,先序遍历:那么就用#
来代替空值,例如如下序列:ABC###DEF##G###就表示如下的树型:
六.遍历树的推导
对于一颗二叉树可以根据前序遍历和中序遍历推测出后续遍历,也可以根据中序遍历和后续遍历推测出前序遍历,但是不可以根据前序遍历和后续遍历推测出中序遍历。
我们用D来表示父节点,L表示左孩子,R来表示右孩子。
前序遍历就是DLR
中序遍历就是LDR
后续遍历就是LRD
例如一棵树的前序遍历是ABDECF 中序遍历为DBEAFC如何求后续遍历?
前序遍历第一个字母A肯定是树根,然后根据中序遍历可以划分左右子树,DBE|A|FC,接下来再看左子树DBE,根据前序遍历第一个字母是B可以推断B是左子树的树根, 再看其中续遍历DBE,可以推断出D是其左子树,E是其右子树。同理可以推测出FC。结果显而易见。
七、二叉分类树
如果一棵树是二叉分类树,那么对于任何节点,其左儿子<=父节点<右儿子,对该树进行中序遍历可以得到顺序序列。
八、扩充二叉树
将原来每个节点的空指针都指向一个特殊的节点—外节点,这样的二叉树称为扩充二叉树。
对于有n个节点的二叉树,含有2n个指针域,但是总共只有n-1条路径,所以占用n-1个指针域,剩余指针域为2n-n+1=n+1个,
所以
外节点个数=内节点个数+1.
外路径长度=内路径长度+2n
九、平衡二叉树
当且仅当每个节点的左右子树高度至多相差1时,我们称这样的树为平衡树。
如果BF的绝对值小于等于1,那么就是平衡二叉树。 平衡因子:BF=左子树高度-右子树高度
对于右面这棵树BF(A)=-2;BF(E)=-1;BF(F)=0;
所以该树不是平衡二叉树。
当用一个数字序列构造平衡二叉树的时候,如果有结点出现BF=-2,那么调节离插入节点最近的BF=-2的节点,如右图,如果A<E<F 可能使E为树根,A、F分别为左右子树.
十、哈弗曼树
详见http://blog.csdn.net/zhang_xinxiu/article/details/12704337