树
结点:是数据结构中的基础,是构成复杂数据结构的基本组成单位
树(Tree): 是 n(n >= 0) 个结点的有限集,n = 0 时称为空树,在任意一颗非空树种中:
- 有且仅有一个特定的结点称为根(Root)结点
- 当 n > 1 时,其余结点可以分为 m(m > 0)个互不相交的有限集 T1、T2、...、Tn,其中每一个集合本身又是一棵树,并且称为根的子树。
- n > 0 时,根结点是唯一的,不可能存在多个根结点,数据结构中的数只能有一个根结点。
- m > 0 时,子树的个数没有限制,但它们一定是互不相交的。
一般树
结点关系
- 结点子树的根结点为根结点的孩子结点,孩子结点的根结点为孩子结点的双亲结点
- 同一个双亲结点的孩子结点之间互称兄弟结点

二叉树
二叉树是 n(n >= 0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两颗互不相交的、分别称为根结点的左子树和右子树组成。

二叉树的五种形态

斜树

满二叉树
在一颗二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树
满二叉树特点:
- 叶子只能出现在最下一层,出现在其他层就不可能达成平衡。
- 非叶子结点的度一定是2
- 在同样深度的二叉树中,满二叉树的结点个数最多,叶子最多

完全二叉树
对一颗具有 n 个结点的二叉树按层编号,如果编号为 i(1 <= i <=n)的结点与同样深度的满二叉树中编号为 i 的结点在二叉树中位置完全相同,则这颗二叉树称为完全二叉树

特点
- 叶子结点只能出现在最下层和次下次
- 最下层的叶子结点集中在树的左部
- 倒数第二层若存在叶子结点,一定在右部连续位置。
- 如果结点度为 1,则该结点只有左孩子,没有右孩子
- 同样结点数目的二叉树,完全二叉树深度最小
注意:满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树
二叉树的特性
- 每个节点最多有两颗子树,所以二叉树中不存在度大于 2 的结点
- 左子树和右子树是由顺序的,次序不能任意颠倒
- 即使数中某结点只有一颗子树,也不要区分它是左子树还是右子树。
- 叶子结点:度为 0 的结点
二叉树性质
- 在二叉树的第 i 层最多有 2^(i-1) 个结点。(i >= 1)
- 二叉树中如果深度为 k ,那么最多有 2^k 个结点。(k >= 1)
- 在完全二叉树中,具有 n 个结点的完全二叉树深度为 [log2n] + 1,其中 [log2n] 是向下取整。
- 若对含 n 个结点的完全二叉树从上到下且从左到右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点有如下特性:
- 如果 i>1,那么序号为 i 的结点的双亲结点序号为 i/2;
- 如果 i=1,那么序号为 i 的结点为根节点,无双亲结点;
- 如果 2i <= n, 那么序号为 i 的结点的左孩子序号为 2i;
- 如果 2i > n, 那么序号为 i 的结点无左孩子;
- 如果 2i + 1 <= n,那么序号为 i 的结点右孩子需要为 2i+1;
- 如果 2i + 1 > n,那么序号为 i 的结点无右孩子。
二叉树顺序存储
二叉树的顺序存储结构就是使用一维数组存储二叉树中的结点,并且结点的存储位置,就是数组的下标索引
完全二叉树的顺序存储方式

上图便是一颗完全二叉树的顺序存储方式示意图
非完全二叉树的顺序存储方式

图中 '^' 符号表示此位置为空,没有存储结点。通过图就可以观察出,通过顺序存储会造成一定空间的浪费,因此顺序存储一般适用于完全二叉树
二叉树的顺序存储的代码实现
- 基本功能
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */
#define MAX_TREE_SIZE 100 /* 二叉树的最大结点数 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Element;
typedef Element sqBiTree[MAX_TREE_SIZE];
Element Nil = 0;//设整型以0为空
typedef struct {
int level;//结点层
int order;//本层的序号(按照满二叉树给定序号规则)
}Position;
//1.visit
Status visit(Element e) {
printf("%d ",e);
return OK;
}
//2.构造空二叉树T,因为T是固定数组,不会改变.
Status initSqBiTree(sqBiTree T) {
for (int i = 0; i < MAX_TREE_SIZE; i++) {
T[i] = Nil;
}
return OK;
}
//按层序次序输入二叉树中的结点值(字符型或整型),构造顺序存储的二叉树T
Status createSqBiTree(sqBiTree T) {
int i = 0, value;
printf("按层序输入结点的值(整型),0表示空结点, 输入999结束.结点数<=%d\n",MAX_TREE_SIZE);
while (1) {
scanf("%d",&value);
//如果输入的值为 999 ,或者第一个数输入0时,跳出循环,上面以设定,为 0 代表结点为空
if (value == 999 || (i == 0 && value == 0)) {
break;
}
T[i] = value;
//结点不为空,并且无双亲结点, i/2 便是双亲结点的位置
if (i != 0 && T[(i+1)/2-1] == Nil && T[i] == Nil) {
printf("出现双亲结点的b非根节点:%d\n",T[i]);
return ERROR;
}
i ++;
}
//将 0 赋给 T 后面的结点
for (; i < MAX_TREE_SIZE; i++) {
T[i] = Nil;
}
return OK;
}
//4 判断⼆叉树是否为空
int isEmpty(sqBiTree T) {
if (T[0] != Nil) {
return FALSE;
}
return TRUE;
}
//5 获取二叉树的深度
int getDeepOfSqBiTree(sqBiTree T) {
int i;
int j = -1;
//找到二叉树中最后一个结点
for (i = MAX_TREE_SIZE-1; i >= 0; i--) {
//从后往前找,第一个不为 Nil 的元素,变为最后一个结点
if (T[0] != Nil) {
break;
}
}
do {
j++;
} while (powl(2, j) <= i);//计算2的次幂
return j;
}
//6 返回处于位置e(层,本层序号)的结点值
Element value(sqBiTree T, Position p) {
//因为根结点的位置从 0 开始的
int level = (int)pow(2, p.level-1);
//order 是从0开始的不是1 所以要减1 ,然后 2 次幂算出来已经在第 level 层的第一个,所以要再减 1,加起来就是减 2
int order = p.order-2;
return T[level + order];
}
//7 获取二叉树跟结点的值
Element rootValue(sqBiTree T) {
if (isEmpty(T)) {
return ERROR;
}
return T[0];
}
//8 给处于位置e的结点赋值
//初始条件: 二叉树存在,e是T中某个结点的位置
//操作结果: 给处于位置e的结点赋值Value;
Status Assign(sqBiTree T,Position e,Element value) {
int level = pow(2, e.level-1);
int order = e.order - 2;
int i = level + order;
//叶子结点的双亲为空
if (value != Nil && T[(i + 1)/2-1] == Nil) {
return ERROR;
}
// 给双亲赋空值但是有叶子结点
if (value == Nil && T[i*2+1] != Nil) {
return ERROR;
}
T[i] = value;
return TRUE;
}
//9 获取e的双亲
Element Parent(sqBiTree T, Element e) {
if (isEmpty(T)) {
return Nil;
}
int i ;
for (i = 0; i < MAX_TREE_SIZE; i++) {
if (T[i] == e) {
return T[(i+1)/2-1];
}
}
return Nil;
}
//10 获取某个结点的左孩⼦
Element leftChild(sqBiTree T, Element e) {
if (isEmpty(T)) {
return Nil;
}
int i ;
for (i = 0; i < MAX_TREE_SIZE; i++) {
if (T[i] == e) {
return T[(i * 2)+1];
}
}
return Nil;
}
//11 获取某个结点的右孩⼦;
Element rightChild(sqBiTree T, Element e) {
if (isEmpty(T)) {
return Nil;
}
int i ;
for (i = 0; i < MAX_TREE_SIZE; i++) {
if (T[i] == e) {
return T[(i * 2)+2];
}
}
return Nil;
}
//12 获取结点的左兄弟
Element leftBrother(sqBiTree T, Element e) {
if (isEmpty(T)) {
return Nil;
}
int i;
for (i = 0; i < MAX_TREE_SIZE; i++) {
if (T[i] == e && i%2 == 0) {
return T[i-1];
}
}
return Nil;
}
//13 获取结点的右兄弟
Element rightBrother(sqBiTree T, Element e) {
if (isEmpty(T)) {
return Nil;
}
int i;
for (i = 0; i < MAX_TREE_SIZE; i++) {
if (T[i] == e && i%2 == 1) {
return T[i+1];
}
}
return Nil;
}
#pragma mark -- 二叉树的遍历
/*
6.14 层序遍历二叉树
*/
void levelOrderTraverse(sqBiTree T) {
int i = MAX_TREE_SIZE-1;
while (T[i] != Nil) {
i++;
}
for (int j = 0; j <= i; j++) {
if (T[j] != Nil) {
visit(T[j]);
}
}
printf("\n");
}
/*
6.15 前序遍历二叉树
*/
void preTraverse(sqBiTree T,int e) {
visit(T[e]);
//遍历左子树,地址为奇数
if (T[(e * 2) + 1] != Nil) {
preTraverse(T, (e * 2) + 1);
}
//遍历右子树,地址为偶数
if (T[(e * 2) + 2] != Nil) {
preTraverse(T, (e * 2) + 2);
}
}
Status preOrderTraverse(sqBiTree T){
//树不为空
if (!isEmpty(T)) {
preTraverse(T, 0);
}
printf("\n");
return OK;
}
/*
6.16 中序遍历
*/
void inTraverse(sqBiTree T, int e) {
/* 左子树不空 */
if (T[2*e+1] != Nil)
inTraverse(T, 2*e+1);
visit(T[e]);
/* 右子树不空 */
if (T[2*e+2] != Nil)
inTraverse(T, 2*e+2);
}
Status inOrderTraverse(sqBiTree T){
/* 树不空 */
if (!isEmpty(T)) {
inTraverse(T, 0);
}
printf("\n");
return OK;
}
/*
6.17 后序遍历
*/
void postTraverse(sqBiTree T,int e) {
if (T[e * 2 + 1] != Nil) {
postTraverse(T, e);
}
if (T[e * 2 + 2] != Nil) {
postTraverse(T, e);
}
visit(T[e]);
}
Status postOrderTraverse(sqBiTree T)
{
if(!isEmpty(T)) /* 树不空 */
postTraverse(T,0);
printf("\n");
return OK;
}
int main(int argc, const char * argv[]) {
// insert code here...
printf("二叉树顺序存储结构实现!\n");
Status iStatus;
Position p;
Element e;
sqBiTree T;
initSqBiTree(T);
createSqBiTree(T);
printf("建立二叉树后,树空否?%d(1:是 0:否) \n",isEmpty(T));
printf("树的深度=%d\n",getDeepOfSqBiTree(T));
p.level=3;
p.order=2;
e=value(T,p);
printf("第%d层第%d个结点的值: %d\n",p.level,p.order,e);
iStatus = rootValue(T);
if (iStatus) {
printf("二叉树的根为:%d\n",e);
}else
{
printf("树为空,无根!\n");
}
//向树中3层第2个结点位置上结点赋值99
e = 99;
Assign(T, p, e);
//获取树中3层第2个结点位置结点的值是多少:
e=value(T,p);
printf("第%d层第%d个结点的值: %d\n",p.level,p.order,e);
//找到e这个结点的双亲;
printf("结点%d的双亲为%d_",e,Parent(T, e));
//找到e这个结点的左右孩子;
printf("左右孩子分别为:%d,%d\n",leftChild(T, e),rightChild(T, e));
//找到e这个结点的左右兄弟;
printf("结点%d的左右兄弟:%d,%d\n",e,leftBrother(T, e),rightBrother(T, e));
Assign(T, p, 5);
printf("二叉树T层序遍历:");
levelOrderTraverse(T);
printf("二叉树T先序遍历:");
preOrderTraverse(T);
printf("二叉树T中序遍历:");
inOrderTraverse(T);
printf("二叉树T后序遍历:");
return 0;
}
打印结果:

- 二叉树的遍历
是指的从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点访问一次且仅被访问一次。
- 层数遍历

/*
6.14 层序遍历二叉树
*/
void levelOrderTraverse(sqBiTree T) {
int i = MAX_TREE_SIZE-1;
while (T[i] != Nil) {
i++;
}
for (int j = 0; j <= i; j++) {
if (T[j] != Nil) {
visit(T[j]);
}
}
printf("\n");
}
打印结果:

- 前序遍历
从二叉树的根结点出发,当第一次到达结点是就输出结点数据,按照先向左再向右的方向访问

/*
6.15 前序遍历二叉树
*/
void preTraverse(sqBiTree T,int e) {
visit(T[e]);
//遍历左子树,地址为奇数
if (T[(e * 2) + 1] != Nil) {
preTraverse(T, (e * 2) + 1);
}
//遍历右子树,地址为偶数
if (T[(e * 2) + 2] != Nil) {
preTraverse(T, (e * 2) + 2);
}
}
Status preOrderTraverse(sqBiTree T){
//树不为空
if (!isEmpty(T)) {
preTraverse(T, 0);
}
printf("\n");
return OK;
}
打印结果:

- 中序遍历
从根结点开始(注意并不不是先访问根结点), 中序遍历根结点的左⼦子树,然后是访问根结点,最后中序遍历右⼦子树

/*
6.16 中序遍历
*/
void inTraverse(sqBiTree T, int e) {
/* 左子树不空 */
if (T[2*e+1] != Nil)
inTraverse(T, 2*e+1);
visit(T[e]);
/* 右子树不空 */
if (T[2*e+2] != Nil)
inTraverse(T, 2*e+2);
}
Status inOrderTraverse(sqBiTree T){
/* 树不空 */
if (!isEmpty(T)) {
inTraverse(T, 0);
}
printf("\n");
return OK;
}
打印结果:

- 后序遍历
从左到右先叶子后结点的方式遍历左右子树,最后访问根结点

/*
6.17 后序遍历
*/
void postTraverse(sqBiTree T,int e) {
/* 左子树不空 */
if(T[2*e+1]!=Nil)
postTraverse(T,2*e+1);
/* 右子树不空 */
if(T[2*e+2]!=Nil)
postTraverse(T,2*e+2);
visit(T[e]);
}
Status postOrderTraverse(sqBiTree T)
{
if(!isEmpty(T)) /* 树不空 */
postTraverse(T,0);
printf("\n");
return OK;
}
打印结果:

二叉树链式存储
二叉数赋值
Status StrAssign(String T,char *chars)
{
int i;
if(strlen(chars)>MAXSIZE)
return ERROR;
else
{
T[0]=strlen(chars);
for(i=1;i<=T[0];i++)
T[i]=*(chars+i-1);
return OK;
}
}
定义结构

typedef char CElemType;
CElemType Nil=' '; /* 字符型以空格符为空 */
typedef struct BiTNode /* 结点结构 */
{
CElemType data; /* 结点数据 */
struct BiTNode *lchild,*rchild; /* 左右孩子指针 */
}BiTNode,*BiTree;
链式二叉树示意图

基本操作
/**2、打印数据*/
ret visit(Element e) {
printf("%c", e);
return OK;
}
/**3、构造空二叉树*/
ret initBiTree(biTree *T) {
*T = NULL;
return OK;
}
/**4、 创建二叉树
按前序输入二叉树中的结点值(字符),#表示空树;
*/
ret creatBiTree(biTree *T) {
//获取字符
Element e = str[indexs++];
if (e == '#') {
*T = NULL;
} else {
*T = (biTree)malloc(sizeof(biTree));
//是否创建成功
if (!*T) {
return ERROR;
}
/* 生成根结点 */
(*T)->data = e;
/* 构造左子树 */
creatBiTree(&(*T)->lChild);
/* 构造右子树 */
creatBiTree(&(*T)->rChild);
}
return OK;
}
/**5、销毁二叉树*/
ret destroyBiTree(biTree *T) {
if ( *T == NULL) {
return ERROR;
}
/* 销毁左孩子子树 */
if ((*T)->lChild) {
destroyBiTree(&(*T)->lChild);
}
/* 销毁右孩子子树 */
if ((*T)->rChild) {
destroyBiTree(&(*T)->rChild);
}
/**释放结点*/
free(*T);
*T = NULL;
return OK;
}
/**6、二叉树T是否为空*/
ret biTreeEmpty(biTree T) {
if (T) {
return ERROR;
} else {
return OK;
}
}
/**7 二叉树T的深度*/
int BiTreeDepth(biTree T) {
int i, j;
if (!T) {
return 0;
}
if (T->lChild) {
i = BiTreeDepth(T->lChild);
} else {
i = 0;
}
if (T->rChild) {
j = BiTreeDepth(T->rChild);
} else {
j = 0;
}
return i > j ? i + 1:j + 1;
}
/**8 二叉树T的根*/
Element root(biTree T) {
if (biTreeEmpty(T)) {
return Nil;
}
return T->data;
}
/**9 返回p所指向的结点值*/
Element value(biTree p){
return p->data;
}
/**10 给p所指结点赋值为value;
初始条件: 二叉树T存在,p指向T中某个结点
操作结果: 给p所指结点赋值为value
*/
void Assign(biTree p,Element value)
{
p->data=value;
}
int main(int argc, const char * argv[]) {
// insert code here...
printf("二叉树链式存储实现!\n");
int i;
biTree T;
Element e1;
initBiTree(&T);
strAssign(str,"ABDH#K###E##CFI###G#J##");
creatBiTree(&T);
printf("二叉树是否为空%d(1:是 0:否),树的深度=%d\n",biTreeEmpty(T),BiTreeDepth(T));
e1=root(T);
printf("二叉树的根为: %c\n",e1);
printf("\n前序遍历二叉树:");
preOrderTraverse(T);
printf("\n中序遍历二叉树:");
inOrderTraverse(T);
printf("\n后序遍历二叉树:");
postOrderTraverse(T);
printf("\n");
return 0;
}
打印结果:

前序遍历
/*
11 前序递归遍历T
初始条件:二叉树T存在;
操作结果: 前序递归遍历T
*/
void preOrderTraverse(biTree T) {
if (T == NULL) {
return;
}
visit(T->data);/* 显示结点数据*/
preOrderTraverse(T->lChild);/* 再先序遍历左子树 */
preOrderTraverse(T->rChild); /* 最后先序遍历右子树 */
}
打印结果:

中序遍历
/*
12 中序递归遍历T
初始条件:二叉树T存在;
操作结果: 中序递归遍历T
*/
void inOrderTraverse(biTree T)
{
if(T==NULL)
return ;
inOrderTraverse(T->lChild); /* 中序遍历左子树 */
visit(T->data);/* 显示结点数据*/
inOrderTraverse(T->rChild); /* 最后中序遍历右子树 */
}
打印结果:

###后续遍历
/*
7.10 后序递归遍历T
初始条件:二叉树T存在;
操作结果: 中序递归遍历T
*/
void postOrderTraverse(biTree T)
{
if(T==NULL)
return;
postOrderTraverse(T->lChild); /* 先后序遍历左子树 */
postOrderTraverse(T->rChild); /* 再后序遍历右子树 */
visit(T->data);/* 显示结点数据*/
}
打印结果:
