浅谈二叉树
二叉树
二叉树不是树的一种特殊情形,尽管其与树有许多相似之处,但树和二叉树有两个主要差别:
1. 树中结点的最大度数没有限制,而二叉树结点的最大度数为2;
2. 树的结点无左、右之分,而二叉树的结点只有左、右之分。
下图即为一个典型是二叉树!!!
接下来就来分析这个图:
在这“棵”树上
根结点 —— F
叶子结点 —— A 、B 、H 、 M
子结点 —– 除了 根结点F 的其他结点
父亲结点 —– 除了 叶子结点 的其他结点
兄弟结点 —– 【C 、E】【A 、D】【H 、G】
堂兄结点 —– 【B 、M】【A 、H】【D 、G】
深度 —– 这棵树的深度为4
………………
像这样的专业术语还有很多,这里就列举了几个常用的。
接着就来看一下二叉树的几种形态:
A —— 一颗空二叉树。(记住:没有东西,也可以是一颗二叉树,只不过是一颗空树)
B —— 有一个结点的二叉树。(这一个结点既是根结点,也是叶子结点)
C —— 只有左子树。
D —— 只有右子树。
E —— 完全二叉树。(这里完全二叉树只一种特殊的二叉树)
所以这样可以定义二叉树:
struct Binary_tree //构建二叉树 { int Date ; //结点数值 struct Binary_tree *lchild ; //左子树 struct Binary_tree *rchild ; //右子树 (这里左右子树也可以看成二叉树) } *Bitree ;
二叉树的性质:
(1) 在非空二叉树中,第i层的结点总数不超过2^(i-1)i>=1;
(2) 深度为h的二叉树最多有2^h-1个结点(h>=1),最少有h个结点;
(3) 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
(4) 具有n个结点的完全二叉树的深度为[log_2 n](注:[ ]表示向下取整)
(5)有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
若I为结点编号则
如果I>1,则其父结点的编号为I/2;
如果2*I<=N,则其左孩子(即左子树的根结点)的编号为2*I;若2*I>N,则无左孩子;
如果2*I+1<=N,则其右孩子的结点编号为2*I+1;若2*I+1>N,则无右孩子。
(6)给定N个节点,能构成h(N)种不同的二叉树。
h(N)为卡特兰数的第N项。h(n)=C(2*n,n)/(n+1)。
(7)设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和J=I+2i。
介绍一下特殊的二叉树:
1、完全二叉树:
定义:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
2、满二叉树:
定义:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树。
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。(这里是国内的说法,国外的说法不同)
3、平衡二叉树:
定义:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
以上三种为特殊的二叉树,都十分的特别,都具有一些性质。(这里就不详细的讲解了)
最后来讲一下二叉树的遍历:
遍历是对树的一种最基本的运算,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。
由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个结点转换成为一个线性序列来表示。
一、 NLR:前序遍历
(Preorder Traversal 亦称(先序遍历))
——访问根结点的操作发生在遍历其左右子树之前。
void NLR_PreTraversal ( Binary_tree *tree ) //先序遍历 { if ( tree->Data == NULL ) { return; } cout << tree->Data ; NLR_PreTraversal ( tree->lchild ) ; NLR_PreTraversal ( tree->rchild ) ; }
二、 LNR:中序遍历
(Inorder Traversal)
——访问根结点的操作发生在遍历其左右子树之中(间)。
void LRN_InoTraversal ( Binary_tree *tree ) //中序遍历 { if ( tree->Data == NULL ) { return; } LRN_InoTraversal ( tree->lchild ) ; cout << tree->Data ; LRN_InoTraversal ( tree->rchild ) ; }
三、 LRN:后序遍历
(Postorder Traversal)
——访问根结点的操作发生在遍历其左右子树之后。
void LRN_PosTraversal ( Binary_tree *tree ) //后序遍历 { if ( tree->Data == NULL ) { return; } LRN_PosTraversal ( tree->lchild ) ; LRN_PosTraversal ( tree->rchild ) ; cout << tree->Data ; }
注:还有层序遍历,其实就只BFS(宽度优先搜索),这里就不单独提出来了。
以上即为我总结的二叉树基础内容。