说明:本笔记依照《王道论坛-数据结构》视频内容整理。
一、基本概念
二叉树是 n (n≥0)个结点的有限集合。
(1)或者为空二叉树,即 n = 0。
(2)或者由一个根结点和两个互不相交的被称为根的左子树和右子树组成。左子树和右子树又分别是一颗二叉树。
特点:
(1)每个结点至多只有两颗子树
(2)左右子树不能颠倒(二叉树是有序树)
二叉树是递归定义的数据结构。
二、二叉树的五种状态
三、特殊的二叉树
四、二叉树性质
五、二叉树的存储结构
1、顺序存储
结点编号反应结点的逻辑关系。
二叉树的顺序存储结构,只适合存储完全二叉树。
typedef int ElemType; // 根据实际情况定义
typedef struct treeNode{
ElemType data; // 用数组存放数据元素(ElemType - 实际数据类型)
int isEmpty; // 结点是否为空
}TreeT; // Tree(列表)T(数据类型)Q(指针类型)
2、链式存储
typedef struct ElemtypeTree{
int value;
}ElemtypeTree;
typedef struct BiTNode{
struct ElemtypeTree data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
六、二叉树先中后序遍历
遍历:按照某种次序把所有结点访问一边。
层次遍历:基于树的层次特性确定的次序规则。
先/中/后序遍历:基于树的递归特性确定的次序规则。
- 先序遍历:根左右(NLR)
- 中序遍历:左根右(LNR)
- 后序遍历:左右根(LRN)
计算方法:分支结点逐层展开法。
/****************************************
* 打印结点值
* t - 结点首地址
****************************************/
void visit(BiTree t)
{
printf("%d",t->data.value);
}
/****************************************
* 先序遍历(根左右)
* t - 结点首地址
****************************************/
void preOrder(BiTree t)
{
if(t != NULL){
visit(t); // 访问结点
preOrder(t->lchild); // 递归遍历左子树
preOrder(t->rchild); // 递归遍历右子树
}
}
/****************************************
* 中序遍历(左根右)
* t - 结点首地址
****************************************/
void inOrder(BiTree t)
{
if(t != NULL){
preOrder(t->lchild); // 递归遍历左子树
visit(t); // 访问结点
preOrder(t->rchild); // 递归遍历右子树
}
}
/****************************************
* 后序遍历(左右根)
* t - 结点首地址
****************************************/
void postOrder(BiTree t)
{
if(t != NULL){
preOrder(t->lchild); // 递归遍历左子树
preOrder(t->rchild); // 递归遍历右子树
visit(t); // 访问结点
}
}
七、二叉树层序遍历
算法思想:
(1)初始化一个辅助队列
(2)根结点入队
(3)若队列非空,则对头结点出队,访问该结点,并将其左、右孩子插入队尾(如果有的话)
(4)重复(3)直至队列为空
typedef struct ElemtypeTree{
int value;
}ElemtypeTree;
typedef struct BiTNode{
struct ElemtypeTree data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
typedef BiTree ElemType; // 根据实际情况定义
typedef struct lNode{ // 定义链式队列结点类型
ElemType data; // 每个结点存放一个数据元素
struct lNode *next; // 指针指向下一个元素
}lNode; // lNode 强调是一个结点
typedef struct{ // 链式队列
lNode *front, *rear; // 队列的队头和队尾
}LinkQueueT;
/****************************************
* 层次遍历
* t - 结点首地址
****************************************/
void levelOrder(BiTree t)
{
LinkQueueT q;
initQueue(&q); // 初始化辅助队列
BiTree p;
enQueue(&q,t); // 将结点地址入队
while(isEmpty(q)){ // 循环队列不为空
deQueue(&q,&p); // 对头结点出队
visit(p); // 访问出队结点
if(p->lchild!=NULL){
enQueue(&q,p->lchild); // 左孩子入队
}
if(p->rchild!=NULL){
enQueue(&q,p->rchild); // 右孩子入队
}
}
}
八、构造二叉树
若只给出一棵二叉树的 前/中/后/层 序遍历序列中的一种,不能唯一确定一棵二叉树。
二叉树构造方法:
- 前序 + 中序遍历序列
- 后序 + 中序遍历序列
- 层次 + 中序遍历序列
九、线索二叉树