一、树的定义
树的递归定义:
1.有且只有一个结点叫根。
2.除根结点外其余结点可划分为m个互不相交的子集T1,T2...Tm(m>=0),并且这m个子集每个子集本身又构成一棵树,称为T的子树。
树的表示方法有很多,如图形表示,广义表表示,嵌套集合表示,凹入表表示等等。
树的基本概念和术语
1.结点
又称作节点,表示数据元素,链式储存结构要加上相关指针。
2.结点的度Degree
结点的子树个数或者分枝数,称为结点的度。
3.树的度
树内各结点的度的最大值。
4.叶子结点
度为0的结点称为叶子结点,或者终端结点。
5.分支结点
指的是度不为0的结点,或者有子树的结点。
6.结点的层次
此处规定根结点的层次为1,其他结点的层次数等于父亲结点+1。结点的层次也叫结点的深度。
7.树的高度(Depth)
树中各结点的最大层次数,称为树的高度。
8.孩子结点
当前结点所有子树的根结点,称为孩子结点。
9.后裔结点
当前结点为跟结点,其子树上的所有结点,都是当前结点的后裔结点。
10.双亲结点
即父亲结点。
11.祖先结点
从根结点由路径到达当前结点,路径经过的所有结点,均为当前结点的祖先结点。
12.兄弟结点(Silbling)
双亲结点相同的所有结点互称为兄弟结点。
13.堂兄弟结点
双亲结点在同一层次(深度相同)的结点,互为堂兄弟。
14.有序树和无序树
同一结点的所有子树,从左至右规定次序叫有序树,若结点的子树不分先后次序即无序树。
15.森林
m棵不相交树的集合,叫做森林。
与线性表以及其他结构相比,树结构有明显的差异,每个结点至多有一个直接前驱,但却可以有多个后继。
二、二叉树
2.1递归定义
二叉树是n个结点的有限集合,其中n>=0,n=0 称为空树否则:
1.有且只有一个结点为根结点。
2.其余结点划分为两个互不相交的子集TL,TR,并且TL,TR分别构成一棵二叉树,称为T的左子树和右子树。
2.2特点
特点一、二叉树中的每个结点最多只有两棵子树。即二叉树中仅仅存在三种度数的结点:0度,1度,2度。
特点二、二叉树是一棵有序树,其子树区分左右。
例如:3个结点构成的树 只有2种形态,而3个结点构成的二叉树形态 有 5 种
2.3二叉树的性质
定义:
满二叉树:每层都有最大数目结点的二叉树
完全二叉树:在满二叉树最下层自右向左连续删除若干结点形成的树
性质一:二叉树上第i层上的结点树
性质二:深度为k的二叉树的结点树
性质三:对于任意非空二叉树,如果其叶子树为N0,度为2的结点树为N2,则有下列等式:
证明略。
性质四:有n个结点的完全二叉树的深度为 (向下取整)
性质五:在编号的完全二叉树中,当前结点的编号为i,则有:
1.如果i的左孩子存在,其编号为2i
2.如果i的右孩子存在,其编号为2i+1
3.如果i的父亲结点存在,其编号为i/2 向下取整
例题:已知完全二叉树有100个结点,则该二叉树有多少个叶子结点?
(至少三种方法)
方法一:最大编号为100,其父结点为50,从51~100均为叶子结点。ANS = 100 - 51 + 1 = 50.
2.4二叉树的存储结构
2.4.1顺序存储结构
(1)完全二叉树的顺序存储
用数组存储元素(结点的值),用数组下标编号表示树中对应结点的编号值。
(2)一般二叉树的顺序存储
将其补全为完全二叉树后按照完全二叉树进行存储。
2.4.2链表存储结构
二叉链表
typedef struct BNode{
char data;
struct BNode *lChild, *rChild;
}BiNode;
二叉链表是最基本的链式存储结构,一棵n个结点的二叉树,采用二叉链表存储的时候,共有2n个指针域,其中有n-1个指针非空(除了根结点,其他结点都有指针指向,剩下2n-(n-1) = n+1个指针域为空。
三叉链表
每个结点有三个指针域(左右孩子,父结点),称这种结构的链表叫做三叉链表。
typedef struct TriNode{
char data;
struct Trinode *lChird, *rChild, *parent;
}TNode;
2.5 二叉树的遍历
遍历即对二叉树中的每个结点经过一次且仅一次的访问。
二叉树访问次序组合
从左到右 从右到左
先序 DLR DRL
中序 LDR RDL
后序 LRD RLD
在此使用从左到右的遍历序。
1.先序遍历 DLR
if(T){
首先访问根结点;
先序遍历T的左子树;
先序遍历T的右子树;
}
2.中序遍历 LDR
if(T) {
中序遍历T的左子树;
访问T的根结点;
中序遍历T的右子树;
}
3.后序遍历 LRD
if(T) {
后序遍历T的左子树;
后序遍历T的右子树;
访问T的根结点;
}
此处需要练习,请自行练习。
例:某序列遍历如下:
中序:CBEDAGHFJI
后序:CEDBHGJIFA
试构造其二叉树结构。
先序遍历的递归算法
void preOrder(BNode *T) {
if(T) {
cout << T->data << endl;
preOrder(T->lChild);
preOrder(T->rChild);
}
}
先序遍历的非递归算法
void preOrderNR(BiNode *T) {
BiNode *p;
stack<BiNode*> s;
p = T;
while(p || s.empty()) {
if(p) {
cout << p->data << " ";
s.push(p);
p = p->lChild;
}
else {
s.pop();
p = p->rChild;
}
}
}
2.6二叉树的创建和销毁
void createSubTree(BiNode *q, int k) { // 子树创建
//q为当前跟结点
//k = 1为左子树,k = 2为右子树
BiNode *u;
int x;
cin >> x;
if(x != '/') {
u = new BiNode;
u->data = x;
u->lChild = NULL;
u->rChild = NULL;
if(k == 1)
q ->lChild = u;
else if(k == 2)
q ->rChild = u;
createSubTree(u,1);
createSubTree(u,2);
}
}
void createBiTree(BiNode *&T) {
BiNode *p;
char x;
cout << "请按照先序序列输入二叉树,'/'表示无子树" << endl;
cin >> x;
if(x = '/')
return;
T = new BiNode;
T->data = x;
T->lChild = NULL;
T->rChild = NULL;
p = T;
createSubTree(p, 1);
createSubTree(p, 2);
}
创建如图