文章目录
一.树与二叉树
1.1树的基本概念
1.1.1树的定义
树是由n个节点的有限集:
- 有且仅有一个特定的称为根的结点
- 当n>1时,其余的结点可以分为m(m>0)个互不相交的有限集,其中每个集合又是一棵树,称为根的子树
树是一种递归的数据结构,它既作为一种逻辑结构,也是一种分层结构,具有如下特点:
- 树的根结点没有前驱,除根结点外的所有结点有且只有一个前驱
- 树中的所有结点可以有零个或多个后继
n个结点的树中有n-1条边
1.1.2基本术语
- 祖先,子孙,双亲,孩子,兄弟,堂兄弟
- 树中一个结点的孩子个数称为度,树中节点的最大度数称为树的度
- 度大于0的结点称为分支结点(非终端结点),度为0的结点为叶子结点
- 深度(自上而下:1,2,…),高度(自底向上累加),层次(自顶向下累加)
- 有序树:树中结点的各子树从左到右是有次序的,不能够交换。反之,则为无序树
- 路径和路径长度。树中的两个节点之间的路径是由这两个结点之间所经过的结点序列构成的,路径长度为路径上所经过的边的个数
- 森林:m(m>=0)棵互不相交的树的集合
1.1.3树的性质
- 树中的节点数=所有结点的度数之和+1
- 度为m的树中第i层上至多有 m i − 1 m^{i-1} mi−1 个结点(i ≥ \geq ≥ 1)
- 高度为h的m叉树至多有 ( m h − 1 m^h -1 mh−1)/(m-1)个结点
- 具有n个结点的m叉树的最小高度为 ⌈ log m ( n ( m − 1 ) + 1 ) ⌉ \lceil \log_m(n(m-1)+1) \rceil ⌈logm(n(m−1)+1)⌉
注: n i n_i ni 表示度为i的结点个数
- 总结点数= n 0 n_0 n0 + n 1 n_1 n1 + n 2 n_2 n2 +…+ n m n_m nm
- 总分支数=1 n 1 n_1 n1 +2 n 2 n_2 n2 +…+m n m n_m nm
- 总结点数=总分支数+1
1.2二叉树的概念
1.2.1二叉树的定义及其主要特性
1)二叉树定义:二叉树是n个结点的有限集合
- 或为空二叉树,即n=0
- 或为一个根结点和两个互不相交的左右子树组成,左右子树也分别为一棵二叉树
2)几个特殊的二叉树
- 满二叉树:高度为h,且含有 2 h − 1 2^h-1 2h−1个结点的二叉树。按层序编号,对于编号为i的结点,若有双亲,则其双亲为 ⌊ i / 2 ⌋ \lfloor i/2\rfloor ⌊i/2⌋,若有左孩子,则左孩子为2i;若有右孩子,则为2i+1
- 完全二叉树:
①若i ≤ \leq ≤ ⌊ n / 2 ⌋ \lfloor n/2\rfloor ⌊n/2⌋,则结点i为分支结点,否则为叶子结点
②叶子结点只可能在层次最大的两层出现,并排列在改成最左边的位置上
③若有度为1的结点,则只可能有1个,且该节点只有左孩子没有右孩子
④按层序编号后,出现某节点(i)为叶子结点或只有左孩子,则编号大于i的结点都为叶子结点
⑤n为奇数,每个分支结点都有左右孩子;n为偶数,编号最大的分支结点只有左孩子,没有右孩子,其余分支结点左右孩子都有 - 二叉排序树:左子树上所有结点的关键字都小于根结点的关键字;右子树上所有结点的关键都大于根结点的关键字
- 平衡二叉树:树上任一结点的左右子树的深度之差不超过1
3) 二叉树的性质
- 非空二叉树上的叶子结点数=度为2的结点数+1,即 n 0 n_0 n0= n 2 n_2 n2+1
- 非空二叉树上第k层上至多有 2 k − 1 2^{k-1} 2k−1个结点
- 高度为h的二叉树至多有 2 h - 1 2^{h}-1 2h-1个结点
- 完全二叉树关于双亲结点和孩子结点的判断
- 具有n个结点的完全二叉树的高度为 ⌈ log 2 ( n + 1 ) ⌉ \lceil\log_2(n+1)\rceil ⌈log2(n+1)⌉或者 ⌊ log 2 n ⌋ \lfloor\log_2n\rfloor ⌊log2n⌋+1
1.2.2二叉树的存储结构
- 顺序存储结构
- 链式存储结构
typedef struct BiTNode{
ElemType data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
注: 在含有n个结点的二叉链表中,含有n+1个空链域
完全二叉树补充:
- 完全二叉树最多只有一个度为1的结点,即 n 1 n_1 n1=0或1
- 若完全二叉树有2k个结点则必有 n 0 n_0 n0=1, n 1 n_1 n1=k, n 2 n_2 n2=k-1
- 若完全二叉树有2k-1个结点则必有 n 0 n_0 n0=0, n 1 n_1 n1=k, n 2 n_2 n2=k-1
1.3二叉树的遍历和线索二叉树
1.3.1二叉树的遍历
//二叉树创建
BiTree createBiTree()
{
int x;
BiTree T;
cin>>x;
if(x==0)T=NULL;
else {
T=(BiTree)malloc(sizeof(BiTNode));
T->data=x;
T->lchild=createBiTree();
T->rchild=createBiTree();
}
return T;
}
- 先序遍历(根左右)
//递归实现
void PreOrder(BiTree root)
{
if(root){
visit(root);
PreOrder(root->lchild);
PreOrder(root->rchild);
}
}
//非递归
void PreOrder(BiTree T)
{
stack<BiTNode*>st;
BiTree p=T;
while(p||st.size()){
if(p){
st.push(p);
visit(p);
p=p->lchild;
}
else{
p=st.top();
st.pop();
p=p->rchild;
}
}
}
- 中序遍历(左根右)
//递归实现
void InOrder(BiTree root)
{
if(root){
InOrder(root->lchild);
visit(root);
InOrder(root->rchild);
}
}
- 后序遍历(左右根)
//递归实现
void PostOrder(BiTree root)
{
if(root){
PostOrder(root->lchild);
PostOrder(root->rchild);
visit(root);
}
}
//非递归实现
void PostOrder(BiTree T)
{
stack<BiTree>st;
BiTree p=T,r=NULL;//r指向最近访问的结点,判断是否已被访问
while(p||st.size()){
if(p){
st.push(p);
p=p->lchild;
}
else{
p=st.top();
if(p->rchild&&p->rchild!=r)p=p->rchild;
else{
st.pop();
visit(p);
r=p;
p=nullptr;
}
}
}
}
- 层序遍历
void levelOrder(BiTree T)
{
queue<BiTree>q;
q.push(T);
while(q.size())
{
BiTree p=q.front();q.pop();visit(p);
if(p->lchild)q.push(p->lchild);
if(p->rchild)q.push(p->rchild);
}
}
- 由遍历序列构造二叉树
1)先序+中序
2)后序+中序
3)层序+中序
注:先序+后序
线索二叉树
- 基本概念
- 线索二叉树的构造
- 线索二叉树的遍历