一、树(Tree)
1.树:是n(n>=0)个结点的有限集。
n=0时称为空树。
在任意一颗非空树中:
(1)有且仅有一个特定的称为根(ROOT)的结点;
(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2...Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree).
2. 结点分类
度(Degree):结点拥有的子树数
叶结点(Leaf)/(非终端结点):度为0的结点
分支结点(终端节点):度不为0的结点,除根结点之外,分支结点也称为内部结点
树的度:树内各节点的度的最大值
孩子结点:结点的直接后继
双亲结点:孩子结点的直接前驱
子孙结点:孩子结点的孩子结点
祖先节点:双亲结点的双亲结点
兄弟结点:同一个结点的孩子结点互称兄弟结点
堂兄弟结点:双亲在同一层的结点互为堂兄弟
3. 层次
树中结点的最大层次称为树的深度(Depth)或高度。
有序树: 如果将树中结点的各子树看成从左至右是有次序的,不能互换,称为有序树,否则称为无序树。
森林(Forest)是m(m>=0)棵互不相交的树的集合。对树中的每个结点而言,其子树的集合即为森林。
4.线性表和树结构的区别:
在一定情况下,线性表可以看成特殊的树结构
5.树的操作
创建树、销毁树、清空树、插入结点、删除结点、获取结点、获取根结点、获取树的结点数、获取树的高度、获取树的度
6.树的存储结构表示方法:
双亲表示法,孩子表示法,孩子兄弟表示法;
(a)双亲表示法
#define MAX_TREE_SIZE 100
typedef struct PTNode
{
int data; //结点数据
int parent; // 双亲位置
}PTNode;
typedef struct{ //树结构
PTNode nodes[MAX_TREE_SIZE];
int r,n; //根的位置和结点数
}PTree;
(b)孩子表示法
每个结点有多个指针域,其中每个指针指向一个子树的根结点的方法叫做多重链表表示法。
/*树的孩子表示法结点结构定义 */
#define MAXSIZE 100
typedef int ElemType; //树结点的数据类型,暂定为整形
typedef struct CTNode //孩子结点
{
int child;
struct CTNode *next;
}*ChildPtr;
typedef struct //表头结构
{
int data;
ChildPtr firstchild;
}CTBox;
typedef struct //树结构
{
CTBox nodes[MAXSIZE]; //结点数组
int r,n; //根结点的位置和结点数
}CTree;
(c)孩子兄弟表示法:
任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。
/*树的孩子兄弟表示法结构定义 */
typedef struct CSNode
{
int data;
struct CSNode *firstchild, *rightsib;
}CSNode, *CSTree;
二、二叉树
1.二叉树:是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的,
分别称为根结点的左子树和右子树的二叉树组成。
特点:
①每个结点最多有两棵子树,所以二叉树中不存在度大于2的结点。
②左子树和右子树是有顺序的,次序不能任意颠倒。
③即使树中结点只有一颗子树,也要区分它是左子树和右子树。
2.二叉树具有五种基本形态:
①空二叉树;
②只有一个根结点
③根结点只有左子树
④根结点只有右结点
⑤根结点既有左子树又有右子树
3.特殊二叉树
(a)斜树:所有的结点都只有左子树的二叉树叫做左斜树;只有右子树的二叉树叫右斜树;统统称为斜树;
(b)满二叉树:在一颗二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树;
特点:
1) 叶子只能出现在最小一层。
2) 非叶子结点的度一定是2
3) 在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。
(c)完全二叉树
对一棵具有n个结点的二叉树按层次编号,如果编号为i的结点与同样深度的满二叉树中编号 为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。
特点:
1)叶子结点只能出现在最小两层;
2)最下层的叶子一定集中在左部连续位置;
3)倒数二层,若有叶子结点,一定都在右部连续位置;
4) 如果结点度为1, 则该结点只有左孩子,即不存在只有右子树的情况;
5)同样结点树的二叉树,完全二叉树的深度最小。
4.二叉树的存储结构:
①二叉树的顺序存储:用一组连续的存储单元存放二叉树中的结点。 必须把二叉树的所有点安排成为一个恰当的序列,缺点是有可能对存储空间造成极大的浪费。依据二叉树的性质,完全二叉树采用顺序存储比较合适。
#define Maxsize 100 //假设一维数组最多存放100个元素
typedef char Datatype; //假设二叉树元素的数据类型为字符
typedef struct
{
Datatype bt[Maxsize];
int btnum;
}Btseq;
②二叉链表二叉树每个结点最多的有两个孩子,所以它设计一个数据域和两个指针域,这样的链表叫做二叉链表:
data域存放某结点的数据信息;
lchild与rchild分别存放指向左孩子和右孩子的指针,当左孩子或右孩子不存在时,相应指针域值为空(用符号∧或NULL表示)。利用这样的结点结构表示的二叉树的链式存储结构被称为二叉链表。
typedef struct BiTNode{
int data;
struct BiTNode *lchild, *rchild;
}BiTNode,*BiTree;
5.遍历二叉树
①前序遍历:规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前向遍历右子树。
前序遍历算法
void PreOrderTraverse(BiTree T)
{
if(T == NULL)
return ;
printf("%c", T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
②中序遍历:中序遍历左子树,访问根结点中的数据,中序遍历右子树
中序遍历算法
void InOrderTraverse(BitTree T)
{
if(T == NULL)
return;
InOrderTraverse(T->lchild);
printf("%c",T->data);
InOrderTraverse(T->rchild);
}
③后序遍历:后序遍历左子树,后序遍历右子树,访问根结点中的数据
后序遍历算法
void PostOrderTraverse(BiTree T)
{
if(T == NULL)
return;
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c",T->data);
}
④层序遍历:按层依次遍历
6. 二叉树的建立
void CreateBiTree(BiTree *T)
{
int ch;
scanf("%c", &ch);
if(ch == '#')
*T = NULL;
else
{
*T = (BiTree)malloc(sizeof(BiTNode));
if(!*T)
exit(OVERFLOW);
(*T)->data = ch;
CreateBiTree(&(*T)->lchild);
CreateBiTree(&(*T)->rchild);
}
}
6. 线索二叉树
线索二叉树原理:这种指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,
对应的二叉树就称为线索二叉树。
对二叉树以某种次序遍历使其变为线索二叉树的过程就是线索化。
线索二叉树结构实现
typedef enum{Link, Thread} PointerTag; // Link==0,表示指向左右孩子指针;Thread == 1 表示指向前驱或后继的线索
typedef struct BiThrNode{ // 二叉线索存储结点结构
int data;
struct BiThrNode *lchild,*rchild;
PointerTag LTag;
PointerTag RTag; //左右标志
} BiThrNode, *BiThrTree;