tips:本文只涉及二叉树的顺序存储和链式存储!!!
二叉树
1. 二叉树的相关概念
1.1 二叉树的定义
- 二叉树是另一种树形结构,其特点是每个结点至多只有两颗子树(即二叉树中不存在大于2的结点),并且二叉树的子树有左右之分,其次序不能任意颠倒。
- 与树相似,二叉树也以递归的形式定义。二叉树是n(n >= 0) 个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两颗互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
- 二叉树具有以下五种基本形态:
空二叉树、只有一个根结点、根结点只有左子树、根结点只有右子树、根结点即有左子树又有右子树。
1.2 二叉树和树的区别
- 度为2 的树至少有3个结点,而二叉树可以为空。
- 度为2的有序树的孩子的左右次序是相对于另一个孩子而言的,若某个结点只有一个孩子,则这个孩子就无须区分其左右次序,而二叉树无论其孩子数是否为2,均需确定其左右次序,即二叉树的结点次序不是相对于另一个结点而言的,而是确定的。
3.$
1.3 特殊的二叉树
1.3.1 满二叉树
- 一颗高度为h,且含有2h-1个结点的二叉树称为满二叉树,即树中每层都含有最多的结。满二叉树的叶子结点都集中在二叉树的最下一层,并且除叶子结点之外的每个结点度数均为2。
- 可以对满二叉树按层编号:约定编号从根结点起,自下而上,自左向右。每个结点对应一个编号,对于编号为 i 的结点,若有双亲,则其双亲为
⌊
i
/
2
⌋
\lfloor i / 2 \rfloor
⌊i/2⌋
(
⌊
x
⌋
表示不大于
x
的最大整数)
(\lfloor x \rfloor 表示不大于x的最大整数)
(⌊x⌋表示不大于x的最大整数) ,若有左孩子则左孩子为 2i;若有右孩子,则有孩子为 2i+1 .

1.3.2 完全二叉树
高度为 h、有n个结点的二叉树,当且仅当其每个结点都与高度为h的满二叉树中编号i ~ n的结点意义对应时,称为完全二叉树。

其特点如下:
- 若 i ≤ ⌊ n / 2 ⌋ i \leq \lfloor n /2 \rfloor i≤⌊n/2⌋,则结点i 为分支结点,否则为叶子结点。
- 叶子结点只可能在层次最大的两层上出现。对于最大层次中的叶子结点,都依次排序在该层的最左边的位置上。
- 若有度为1的结点,则只可能出现一个,且该结点只有左孩子而无右孩子。
- 按层序编号后,一旦出现某结点(n=i)为叶子结点或只有左孩子,则编号大于i的结点均为叶子结点。
- 若n为奇数,则每个分支结点都有左孩子和右孩子;若n为偶数,则编号最大的分支结点(编号为n/2)只有左孩子,没有右孩子,其余分支结点都有左孩子和右孩子。
1.4 二叉树的性质
- 非空二叉树上的叶子结点数等于度为2的结点数加1,即 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1.
- 非空二叉树上第k层上至多有2k-1个结点( k ≥ 1 k\geq1 k≥1).
- 高度为h的二叉树至多有2h-1个结点( h ≥ 1 h\geq1 h≥1).
- 对于完全二叉树按从上到下,从左到右的顺序依次编号1、2、…、n,则有以下关系:
1)当 i > 1 i>1 i>1时,结点i的双亲的编号为 ⌊ i / 2 ⌋ \lfloor i/2 \rfloor ⌊i/2⌋,即当i为偶数时,其双亲的编号为 i / 2 i/2 i/2 ,它是双亲的左孩子;当i为奇数时,其双亲的编号为 ( i − 1 ) / 2 (i-1)/2 (i−1)/2,它是双亲的右孩子。
2)当 2 i ≤ n 2i \leq n 2i≤n时,结点 i i i 的左孩子编号为 2 i 2i 2i ,否则无左孩子。
3)当 2 i + 1 ≤ n 2i+1 \leq n 2i+1≤n时,结点 i i i 的右孩子编号为 2 i + 1 2i+1 2i+1,否则没有右孩子。
4)结点 i i i所在层次(深度)为 ⌊ l o g 2 i ⌋ + 1 \lfloor log_{2}i\rfloor+1 ⌊log2i⌋+1 - 具有n个(n>0)结点的完全二叉树的高度为 ⌊ l o g 2 n ⌋ + 1 \lfloor log_{2}n\rfloor+1 ⌊log2n⌋+1 或 ⌈ l o g 2 n + 1 ⌉ \lceil log_{2}n+1\rceil ⌈log2n+1⌉ ( ⌈ x ⌉ 表示不小于 x 的最小整数 \lceil x\rceil 表示不小于x的最小整数 ⌈x⌉表示不小于x的最小整数)
3. 二叉树的存储结构
3.1 顺序存储结构
3.1.1 定义
二叉树的顺序存储结构是指用一组地址连续的存储单元依次自上而下、自左向右存储完全二叉树上的结点元素,即将完全二叉树上编号为
i
i
i的结点元素存储在一维数组下标为
i
−
1
i-1
i−1的分量中。
依据二叉树的性质,完全二叉树和满二叉树采用顺序存储比较合适,树中结点的序号可以唯一的反映结点之间的逻辑关系,这样既能最大可能的节省存储空间,又能利用数组元素的下标值确定结点在二叉树中的位置,以及结点之间的关系。
但对于一般的二叉树,为了让数组下标能反映二叉树中结点之间的逻辑关系,只能添加并不存在的空结点,让其每个结点与完全二叉树上的结点对照,在存储到一维数组的相应分量中。然而,在最坏情况下,一个高度h且只有h个结点的单支树却需要占据近2h-1个存储单元。
注意:建议从数组下标1开始存储树中的结点。
3.1.2 基本操作
//初始化(构造空二叉树)
//判空
//求树的深度
//按层序创建二叉树
//层序遍历二叉树
//求根结点的值
//返回位置e的值
//给位置e赋新值
//求结点的双亲
//求结点的左孩子
//求结点的右孩子
//求结点的左兄弟
//求结点的右兄弟
//前序遍历
//中序遍历
//后序遍历
//按层输出
3.1.3 代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#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 99 //二叉树的最大结点数
typedef int TElemType;
typedef int Status;
typedef TElemType SqBiTree[MAX_TREE_SIZE]; //1号单元存储根结点
typedef struct
{
int level; //结点的层
int order; //本层序号(按满二叉树计算)
}Position;
TElemType Nil = 0; //设整型以0为空
1.初始化(构造空二叉树)
//构造空二叉树T。
Status InitBiTree(SqBiTree T)
{
int i;
for (i = 1; i < MAX_TREE_SIZE; i++)
{
T[i] = Nil; //初始值为空 将数组中的所有元素置为0
}
return 0;
}
2.判空
//判空
Status BiTreeEmpty(SqBiTree T)
{
if (T[1] == Nil) //根结点为空,则树为空
{
return TRUE; //空
}
else
{
return FALSE; //不为空
}
}
3.求树的深度
//求二叉树的深度
int BiTreeDepth(SqBiTree T)
{
int i = 0;
int j = 0;
for (i = MAX_TREE_SIZE - 1; i >= 1; i--)
{
if (T[i] != Nil)
{
break;
}
}
i++;
do
{
j++;
} while (i >= powl(2, j)); //计算2的j次幂
return j;
}
4.按层序创建二叉树
//按层序构造顺序存储的二叉树T
Status CreateBiTree(SqBiTree T)
{
int i = 1;
printf("结点数≤%d:\n", MAX_TREE_SIZE-1); //最多只能有98个结点
while (i <= 10) //结点数为10
{
T[i] = i;
if (i != 1 && T[i / 2] == Nil && T[i] != Nil) /* 此结点(不空)无双亲且不是根 */
{
printf("出现无双亲的非根结点%d\n", T[i]);
exit(ERROR);
}
i++;
}
while (i < MAX_TREE_SIZE)
{
T[i] = Nil; /* 将空赋值给T的后面的结点 */
i++;
}
return OK;
}
5.层序遍历二叉树
/* 层序遍历二叉树 */
Status visit(TElemType c)
{
printf("%d ", c);
return OK;
}
void LevelOrderTraverse(SqBiTree T)
{
int i = MAX_TREE_SIZE - 1, j;
while (T[i] == Nil)
{
i--; /* 找到最后一个非空结点的序号 */
}
for (j = 1; j <= i; j++) /* 从根结点起,按层序遍历二叉树 */
{
if (T[j] != Nil)
{
visit(T[j]); /* 只遍历非空的结点 */
}
}
printf("\n");
}

6.求根结点的值
//求根结点的值
Status Root(SqBiTree T, TElemType* e)
{
if (BiTreeEmpty(T)) //空
{
return ERROR;
}
else
{
*e = T[1]; //用e返回根结点的值
return OK;
}
}

7.返回位置e的值
//返回处于位置e(第level层的第order个结点)的值
TElemType Value(SqBiTree T, Position e)
{
return T[(int)powl(2, e.level - 1) + e.order - 1];
//第i层有至多有2^{k-1}个结点,+e.order-1之后可以得到本层第order个结点的值
}

8.给位置e赋新值
//给处于位置e(第level层第order个结点)赋新值value
Status Assign(SqBiTree T, Position e, TElemType value)
{
int i = (int)powl(2, e.level - 1) + e.order - 1;
if (value != Nil && T[i/2] == Nil)
{ /* 给叶子赋非空值但双亲为空 */
return ERROR;
}
else if (value == Nil && (T[i * 2] != Nil || T[i * 2 + 1] != Nil))
{ /* 给双亲赋空值但有叶子(不空) */
return ERROR;
}
T[i] = value;
return OK;
}

9.求结点的双亲
//求结点的双亲
TElemType Parent(SqBiTree T, TElemType e)
{
int i;
if (T[1] == Nil) //空树
{
return Nil;
}
for (i = 2; i <= MAX_TREE_SIZE - 1; i++) //根结点T[1]无双亲,从2开始
{
if (T[i] == e) //找到e
{
return T[i / 2]; //双亲结点在数组中的位置
}
}
return Nil; //没找到e
}

10.求结点的左孩子
//求结点的左孩子
TElemType LeftChild(SqBiTree T, TElemType e)
{
int i = 0;
if (T[1] == Nil)
{
return ERROR; //空树
}
for (i = 1; i <= MAX_TREE_SIZE - 1; i++)
{
if (T[i] == e)
{
return T[i * 2];
}
}
return Nil; //没找到
}

11.求结点的右孩子
//求结点的右孩子
TElemType RightChild(SqBiTree T, TElemType e)
{
int i = 0;
if (T[1] == Nil)
{
return ERROR; //空树
}
for (i = 0; i <= MAX_TREE_SIZE - 1; i++)
{
if (T[i] == e)
{
return T[i * 2 + 1];
}
}
return Nil;
}

12.求结点的左兄弟
//求结点的左兄弟
TElemType LeftSibling(SqBiTree T, TElemType e)
{
int i = 0;
if (T[1] == Nil)
{
return ERROR;
}
for (i = 2; i <= MAX_TREE_SIZE - 1; i++) //根结点T[1]没有左兄弟,i从2开始
{
if (T[i] == e && i % 2 == 1)
{
return T[i - 1];
}
}
return Nil; //没找到e结点
}

13.求结点的右兄弟
//求结点的右兄弟
TElemType RightSibling(SqBiTree T, TElemType e)
{
int i = 0;
if (T[1] == Nil)
{
return ERROR; //空树
}
for (i = 2; i <= MAX_TREE_SIZE - 1; i++)
{
if (T[i] == e && i % 2 == 0)
{
return T[i + 1];
}
}
return Nil;
}

14.前序遍历
//前序遍历二叉树
void PreTraverse(SqBiTree T, int e)
{
visit(T[e]); //打印输出结点的值
if (T[2 * e] != Nil) /* 左子树不空 */
{
PreTraverse(T, 2 * e);
}
if (T[2 * e + 1] != Nil) /* 右子树不空 */
{
PreTraverse(T, 2 * e + 1);
}
}
Status PreOrderTraverse(SqBiTree T)
{
if (!BiTreeEmpty(T)) /* 树不空 */
{
PreTraverse(T, 1);
}
printf("\n");
return OK;
}

15.中序遍历
//中序遍历二叉树
void InTraverse(SqBiTree T, int e)
{
if (T[2 * e] != Nil) //左子树不为空
{
InTraverse(T, 2 * e);
}
visit(T[e]); //打印
if (T[2 * e + 1] != Nil) //右子树不为空
{
InTraverse(T, 2 * e + 1);
}
}
Status InOrderTraverse(SqBiTree T)
{
if (!BiTreeEmpty(T))
{
InTraverse(T, 1);
}
printf("\n");
return OK;
}

16.后序遍历
//后序遍历二叉树
void PostTraverse(SqBiTree T, int e)
{
if (T[2 * e] != Nil)
{
PostTraverse(T, 2 * e);
}
if (T[2 * e + 1] != Nil)
{
PostTraverse(T, 2 * e + 1);
}
visit(T[e]);
}
Status PostOrderTraverse(SqBiTree T)
{
if (!BiTreeEmpty(T))
{
PostTraverse(T, 1);
}
printf("\n");
return OK;
}

17.按层输出
//逐层、按本层序号输出二叉树
void Print(SqBiTree T)
{
int j = 0;
int k = 0;
Position p;
TElemType e = 0;
for (j = 1; j <= BiTreeDepth(T); j++)
{
printf("第%d层:", j);
for (k = 1; k <= powl(2, j - 1); k++)
{
p.level = j;
p.order = k;
e = Value(T, p);
if (e != Nil)
{
printf("第%d个:%d ", k, e);
}
}
printf("\n");
}
}

18.清空
#define ClearBiTree InitBiTree /* 在顺序存储结构中,两函数完全一样 */

3.1.4 完整代码
#define _CRT_SECURE_NO_WARNINGS 1
#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 99 //二叉树的最大结点数
typedef int TElemType;
typedef int Status;
typedef TElemType SqBiTree[MAX_TREE_SIZE]; //1号单元存储根结点
typedef struct
{
int level; //结点的层
int order; //本层序号(按满二叉树计算)
}Position;
TElemType Nil = 0; //设整型以0为空
//构造空二叉树T。
Status InitBiTree(SqBiTree T)
{
int i;
for (i = 1; i < MAX_TREE_SIZE; i++)
{
T[i] = Nil; //初始值为空 将数组中的所有元素置为0
}
return 0;
}
//判空
Status BiTreeEmpty(SqBiTree T)
{
if (T[1] == Nil) //根结点为空,则树为空
{
return TRUE; //空
}
else
{
return FALSE; //不为空
}
}
//求二叉树的深度
int BiTreeDepth(SqBiTree T)
{
int i = 0;
int j = 0;
for (i = MAX_TREE_SIZE - 1; i >= 1; i--)
{
if (T[i] != Nil)
{
break;
}
}
i++;
do
{
j++;
} while (i >= powl(2, j)); //计算2的j次幂
return j;
}
//按层序构造顺序存储的二叉树T
Status CreateBiTree(SqBiTree T)
{
int i = 1;
printf("结点数≤%d:\n", MAX_TREE_SIZE-1); //最多只能有98个结点
while (i <= 10) //结点数为10
{
T[i] = i;
if (i != 1 && T[i / 2] == Nil && T[i] != Nil) /* 此结点(不空)无双亲且不是根 */
{
printf("出现无双亲的非根结点%d\n", T[i]);
exit(ERROR);
}
i++;
}
while (i < MAX_TREE_SIZE)
{
T[i] = Nil; /* 将空赋值给T的后面的结点 */
i++;
}
return OK;
}
/* 层序遍历二叉树 */
Status visit(TElemType c)
{
printf("%d ", c);
return OK;
}
void LevelOrderTraverse(SqBiTree T)
{
int i = MAX_TREE_SIZE - 1, j;
while (T[i] == Nil)
{
i--; /* 找到最后一个非空结点的序号 */
}
for (j = 1; j <= i; j++) /* 从根结点起,按层序遍历二叉树 */
{
if (T[j] != Nil)
{
visit(T[j]); /* 只遍历非空的结点 */
}
}
printf("\n");
}
//求根结点的值
Status Root(SqBiTree T, TElemType* e)
{
if (BiTreeEmpty(T)) //空
{
return ERROR;
}
else
{
*e = T[1]; //用e返回根结点的值
return OK;
}
}
//返回处于位置e(第level层的第order个结点)的值
TElemType Value(SqBiTree T, Position e)
{
return T[(int)powl(2, e.level - 1) + e.order - 1];
//第i层有至多有2^{k-1}个结点,+e.order-1之后可以得到本层第order个结点的值
}
//给处于位置e(第level层第order个结点)赋新值value
Status Assign(SqBiTree T, Position e, TElemType value)
{
int i = (int)powl(2, e.level - 1) + e.order - 1;
if (value != Nil && T[i/2] == Nil)
{ /* 给叶子赋非空值但双亲为空 */
return ERROR;
}
else if (value == Nil && (T[i * 2] != Nil || T[i * 2 + 1] != Nil))
{ /* 给双亲赋空值但有叶子(不空) */
return ERROR;
}
T[i] = value;
return OK;
}
//求结点的双亲
TElemType Parent(SqBiTree T, TElemType e)
{
int i;
if (T[1] == Nil) //空树
{
return Nil;
}
for (i = 2; i <= MAX_TREE_SIZE - 1; i++) //根结点T[1]无双亲,从2开始
{
if (T[i] == e) //找到e
{
return T[i / 2]; //双亲结点在数组中的位置
}
}
return Nil; //没找到e
}
//求结点的左孩子
TElemType LeftChild(SqBiTree T, TElemType e)
{
int i = 0;
if (T[1] == Nil)
{
return ERROR; //空树
}
for (i = 1; i <= MAX_TREE_SIZE - 1; i++)
{
if (T[i] == e)
{
return T[i * 2];
}
}
return Nil; //没找到
}
//求结点的右孩子
TElemType RightChild(SqBiTree T, TElemType e)
{
int i = 0;
if (T[1] == Nil)
{
return ERROR; //空树
}
for (i = 0; i <= MAX_TREE_SIZE - 1; i++)
{
if (T[i] == e)
{
return T[i * 2 + 1];
}
}
return Nil;
}
//求结点的左兄弟
TElemType LeftSibling(SqBiTree T, TElemType e)
{
int i = 0;
if (T[1] == Nil)
{
return ERROR;
}
for (i = 2; i <= MAX_TREE_SIZE - 1; i++) //根结点T[1]没有左兄弟,i从2开始
{
if (T[i] == e && i % 2 == 1)
{
return T[i - 1];
}
}
return Nil; //没找到e结点
}
//求结点的右兄弟
TElemType RightSibling(SqBiTree T, TElemType e)
{
int i = 0;
if (T[1] == Nil)
{
return ERROR; //空树
}
for (i = 2; i <= MAX_TREE_SIZE - 1; i++)
{
if (T[i] == e && i % 2 == 0)
{
return T[i + 1];
}
}
return Nil;
}
//前序遍历二叉树
void PreTraverse(SqBiTree T, int e)
{
visit(T[e]); //打印输出结点的值
if (T[2 * e] != Nil) /* 左子树不空 */
{
PreTraverse(T, 2 * e);
}
if (T[2 * e + 1] != Nil) /* 右子树不空 */
{
PreTraverse(T, 2 * e + 1);
}
}
Status PreOrderTraverse(SqBiTree T)
{
if (!BiTreeEmpty(T)) /* 树不空 */
{
PreTraverse(T, 1);
}
printf("\n");
return OK;
}
//中序遍历二叉树
void InTraverse(SqBiTree T, int e)
{
if (T[2 * e] != Nil) //左子树不为空
{
InTraverse(T, 2 * e);
}
visit(T[e]); //打印
if (T[2 * e + 1] != Nil) //右子树不为空
{
InTraverse(T, 2 * e + 1);
}
}
Status InOrderTraverse(SqBiTree T)
{
if (!BiTreeEmpty(T))
{
InTraverse(T, 1);
}
printf("\n");
return OK;
}
//后序遍历二叉树
void PostTraverse(SqBiTree T, int e)
{
if (T[2 * e] != Nil)
{
PostTraverse(T, 2 * e);
}
if (T[2 * e + 1] != Nil)
{
PostTraverse(T, 2 * e + 1);
}
visit(T[e]);
}
Status PostOrderTraverse(SqBiTree T)
{
if (!BiTreeEmpty(T))
{
PostTraverse(T, 1);
}
printf("\n");
return OK;
}
//逐层、按本层序号输出二叉树
void Print(SqBiTree T)
{
int j = 0;
int k = 0;
Position p;
TElemType e = 0;
for (j = 1; j <= BiTreeDepth(T); j++)
{
printf("第%d层:", j);
for (k = 1; k <= powl(2, j - 1); k++)
{
p.level = j;
p.order = k;
e = Value(T, p);
if (e != Nil)
{
printf("第%d个:%d ", k, e);
}
}
printf("\n");
}
}
#define ClearBiTree InitBiTree /* 在顺序存储结构中,两函数完全一样 */
void test01()
{
//1.初始化二叉树
SqBiTree T;
InitBiTree(T);
//2.创建结点数为10的二叉树
CreateBiTree(T);//请按层序输入结点的值(整型),0表示空结点,输999结束。结点数≤98:
//3.层序遍历二叉树
LevelOrderTraverse(T); //1 2 3 4 5 6 7 8 9 10
//4.判空
Status i_empty = BiTreeEmpty(T);
printf("该二叉树是否为空(1为是/0为否):%d\n", i_empty); //该二叉树是否为空(1为是/0为否):0
//5.求二叉树的深度
int i_depth = BiTreeDepth(T);
printf("该二叉树的深度为:%d\n", i_depth); //该二叉树的深度为:4
printf("---------------------------------------\n");
//6.求二叉树的根结点
TElemType e_root = Root(T, &e_root);
printf("二叉树的根结点为:%d\n", e_root); //二叉树的根结点为:1
printf("---------------------------------------\n");
//7.求第level层的第order个结点的值
Position p = {4,3};
TElemType e_value = Value(T, p);
printf("在满二叉树第%d层的第%d个结点的值为:%d\n", p.level, p.order, e_value);
//在满二叉树第4层的第3个结点的值为:10
printf("---------------------------------------\n");
//8.给位置e的结点重新赋值
Position p1 = { 2,2 }; //第二层的第二个结点
TElemType e = 20;
Assign(T, p1, e);
//层序遍历二叉树
LevelOrderTraverse(T); //1 2 20 4 5 6 7 8 9 10
printf("---------------------------------------\n");
//9.求结点的双亲
e = 20;
TElemType i_parent = Parent(T, e);
printf("结点%d的双亲是%d\n", e, i_parent); //结点20的双亲是1
//10.求结点的左孩子
e = 20;
TElemType i_leftchild = LeftChild(T, e);
printf("结点%d的左孩子是%d\n", e, i_leftchild); //结点20的左孩子是6
//11.求结点的右孩子
e = 20;
TElemType i_rightchild = RightChild(T, e);
printf("结点%d的右孩子是%d\n", e, i_rightchild); //结点20的右孩子是7
//12.求结点的左兄弟
e = 20;
TElemType i_leftsibling = LeftSibling(T, e);
printf("结点%d的左兄弟是%d\n", e, i_leftsibling); //结点20的左兄弟是2
//13.求结点的右兄弟
e = 6;
TElemType i_rightsibling = RightSibling(T, e);
printf("结点%d的右兄弟是%d\n", e, i_rightsibling); //结点6的右兄弟是7
printf("---------------------------------------\n");
//14.层序遍历二叉树
LevelOrderTraverse(T); //1 2 20 4 5 6 7 8 9 10
//15.前序遍历二叉树
PreOrderTraverse(T); //1 2 4 8 9 5 10 20 6 7
//16.中序遍历二叉树
InOrderTraverse(T); //8 4 9 2 10 5 1 6 20 7
//17.后序遍历二叉树
PostOrderTraverse(T); //8 9 4 10 5 2 6 7 20 1
//18.逐层、按本层序号输出二叉树
Print(T);
//第1层:第1个:1
//第2层:第1个 : 2 第2个 : 20
//第3层:第1个 : 4 第2个 : 5 第3个 : 6 第4个 : 7
//第4层:第1个 : 8 第2个 : 9 第3个 : 10
printf("---------------------------------------\n");
//19.清空
ClearBiTree(T);
//层序遍历二叉树
LevelOrderTraverse(T); //
//判空
i_empty = BiTreeEmpty(T);
printf("该二叉树是否为空(1为是/0为否):%d\n", i_empty); //该二叉树是否为空(1为是/0为否):1
//求二叉树的深度
i_depth = BiTreeDepth(T);
printf("该二叉树的深度为:%d\n", i_depth); //该二叉树的深度为:1
}
int main()
{
test01();
return 0;
}
3.2 链式存储结构
3.2.1 定义
由于顺序存储空间利用效率较低,因此二叉树一般采用链式存储结构存储,用链表结点来存储二叉树中的每个结点。
在二叉树中,结点结构通常包含若干数据域和若干指针域,二叉链表中至少包含3个域:数据域data、左指针域lchild、右指针域rchild.
3.2.2 基本操作
//初始化树
//创建树
//判空
//求树的深度
//求根结点
//前序遍历
//中序遍历
//后序遍历
//清空
//销毁
3.2.3 代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 //存储空间初始分配量
typedef int Status;
//用于构造二叉树的准备————————————————————————
int treeIndex = 1;
typedef char String[24]; //0号单元存放串的长度
String str;
Status StrAssign(String T, char* chars)
{
int i = 0;
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 TElemType;
TElemType Nil = ' '; //字符型以空格符为空
typedef struct BiTNode //结点结构
{
TElemType data;
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode,*BiTree;
1.初始化树
//构造空二叉树
Status InitBiTree(BiTree* T)
{
*T = NULL;//头指针指向空
return OK;
}

2.创建树
//按前序输入二叉树中结点的值(一个字符)
void CreateBiTree(BiTree* T)
{
TElemType ch;
//scanf("%c",&ch);
ch = str[treeIndex++];
if (ch == '#')
{
*T = NULL; //#表示空树
}
else
{
*T = (BiTree)malloc(sizeof(BiTNode));
if (!*T)
{
exit(OVERFLOW);
}
(*T)->data = ch;
CreateBiTree(&(*T)->lchild); //构造左子树
CreateBiTree(&(*T)->rchild); //构造右子树
}
}
3.判空
//判空
Status BiTreeEmpty(BiTree T)
{
if (T)
{
return FALSE; //不为空
}
else
{
return TRUE; //为空
}
}
4.求树的深度
//求二叉树的深度
int BiTreeDepth(BiTree T)
{
int i;
int 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;
}

5.求根结点
//返回树的根结点
TElemType Root(BiTree T)
{
if (BiTreeEmpty(T))
{
return Nil;
}
else
{
return T->data; //返回头指针指向的结点的值
}
}

6.前序遍历
/* 初始条件: 二叉树T存在 */
/* 操作结果: 前序递归遍历T */
void PreOrderTraverse(BiTree T)
{
if (T == NULL)
{
return;
}
printf("%c", T->data);/* 显示结点数据,可以更改为其它对结点操作 */
PreOrderTraverse(T->lchild); /* 再先序遍历左子树 */
PreOrderTraverse(T->rchild); /* 最后先序遍历右子树 */
}

7.中序遍历
/* 初始条件: 二叉树T存在 */
/* 操作结果: 中序递归遍历T */
void InOrderTraverse(BiTree T)
{
if (T == NULL)
{
return;
}
InOrderTraverse(T->lchild); /* 中序遍历左子树 */
printf("%c", T->data);/* 显示结点数据,可以更改为其它对结点操作 */
InOrderTraverse(T->rchild); /* 最后中序遍历右子树 */
}

8.后序遍历
/* 初始条件: 二叉树T存在 */
/* 操作结果: 后序递归遍历T */
void PostOrderTraverse(BiTree T)
{
if (T == NULL)
{
return;
}
PostOrderTraverse(T->lchild); /* 先后序遍历左子树 */
PostOrderTraverse(T->rchild); /* 再后序遍历右子树 */
printf("%c", T->data);/* 显示结点数据,可以更改为其它对结点操作 */
}

9.清空
#define ClearBiTree DestroyBiTree

10.销毁
/* 初始条件: 二叉树T存在。操作结果: 销毁二叉树T */
void DestroyBiTree(BiTree* T)
{
if (*T)
{
if ((*T)->lchild) /* 有左孩子 */
{
DestroyBiTree(&(*T)->lchild); /* 销毁左孩子子树 */
}
if ((*T)->rchild) /* 有右孩子 */
{
DestroyBiTree(&(*T)->rchild); /* 销毁右孩子子树 */
}
free(*T); /* 释放根结点 */
*T = NULL; /* 空指针赋0 */
}
}
3.2.4 完整代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 //存储空间初始分配量
typedef int Status;
//用于构造二叉树的准备————————————————————————
int treeIndex = 1;
typedef char String[24]; //0号单元存放串的长度
String str;
Status StrAssign(String T, char* chars)
{
int i = 0;
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 TElemType;
TElemType Nil = ' '; //字符型以空格符为空
typedef struct BiTNode //结点结构
{
TElemType data;
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode,*BiTree;
//构造空二叉树
Status InitBiTree(BiTree* T)
{
*T = NULL;//头指针指向空
return OK;
}
//按前序输入二叉树中结点的值(一个字符)
void CreateBiTree(BiTree* T)
{
TElemType ch;
//scanf("%c",&ch);
ch = str[treeIndex++];
if (ch == '#')
{
*T = NULL; //#表示空树
}
else
{
*T = (BiTree)malloc(sizeof(BiTNode));
if (!*T)
{
exit(OVERFLOW);
}
(*T)->data = ch;
CreateBiTree(&(*T)->lchild); //构造左子树
CreateBiTree(&(*T)->rchild); //构造右子树
}
}
//判空
Status BiTreeEmpty(BiTree T)
{
if (T)
{
return FALSE; //不为空
}
else
{
return TRUE; //为空
}
}
//求二叉树的深度
int BiTreeDepth(BiTree T)
{
int i;
int 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;
}
//返回树的根结点
TElemType Root(BiTree T)
{
if (BiTreeEmpty(T))
{
return Nil;
}
else
{
return T->data; //返回头指针指向的结点的值
}
}
/* 初始条件: 二叉树T存在,p指向T中某个结点 */
/* 操作结果: 返回p所指结点的值 */
TElemType Value(BiTree p)
{
return p->data;
}
/* 给p所指结点赋值为value */
void Assign(BiTree p, TElemType value)
{
p->data = value;
}
/* 初始条件: 二叉树T存在 */
/* 操作结果: 前序递归遍历T */
void PreOrderTraverse(BiTree T)
{
if (T == NULL)
{
return;
}
printf("%c", T->data);/* 显示结点数据,可以更改为其它对结点操作 */
PreOrderTraverse(T->lchild); /* 再先序遍历左子树 */
PreOrderTraverse(T->rchild); /* 最后先序遍历右子树 */
}
/* 初始条件: 二叉树T存在 */
/* 操作结果: 中序递归遍历T */
void InOrderTraverse(BiTree T)
{
if (T == NULL)
{
return;
}
InOrderTraverse(T->lchild); /* 中序遍历左子树 */
printf("%c", T->data);/* 显示结点数据,可以更改为其它对结点操作 */
InOrderTraverse(T->rchild); /* 最后中序遍历右子树 */
}
/* 初始条件: 二叉树T存在 */
/* 操作结果: 后序递归遍历T */
void PostOrderTraverse(BiTree T)
{
if (T == NULL)
{
return;
}
PostOrderTraverse(T->lchild); /* 先后序遍历左子树 */
PostOrderTraverse(T->rchild); /* 再后序遍历右子树 */
printf("%c", T->data);/* 显示结点数据,可以更改为其它对结点操作 */
}
#define ClearBiTree DestroyBiTree
/* 初始条件: 二叉树T存在。操作结果: 销毁二叉树T */
void DestroyBiTree(BiTree* T)
{
if (*T)
{
if ((*T)->lchild) /* 有左孩子 */
{
DestroyBiTree(&(*T)->lchild); /* 销毁左孩子子树 */
}
if ((*T)->rchild) /* 有右孩子 */
{
DestroyBiTree(&(*T)->rchild); /* 销毁右孩子子树 */
}
free(*T); /* 释放根结点 */
*T = NULL; /* 空指针赋0 */
}
}
void test01()
{
//初始化
BiTree T;
InitBiTree(&T);
StrAssign(str, "ABDH#K###E##CFI###G#J##");
//判空
Status i_empty = BiTreeEmpty(T);
printf("二叉树是否为空(1为是/0为否):%d\n", i_empty); //二叉树是否为空(1为是/0为否):1
//求二叉树的深度
int i_length = BiTreeDepth(T);
printf("二叉树的深度为:%d\n", i_length); //二叉树的深度为:0
printf("--------------------------\n");
//创建链树
CreateBiTree(&T);
//判空
i_empty = BiTreeEmpty(T);
printf("二叉树是否为空(1为是/0为否):%d\n", i_empty); //二叉树是否为空(1为是/0为否):0
i_length = BiTreeDepth(T);
printf("二叉树的深度为:%d\n", i_length); //二叉树的深度为:5
printf("--------------------------\n");
//求根结点
TElemType e_root = Root(T);
printf("二叉树的根结点为:%c\n",e_root); //二叉树的根结点为:A
//前序遍历
PreOrderTraverse(T); //ABDHKECFIGJ
printf("\n____________\n");
//中序遍历
InOrderTraverse(T); //HKDBEAIFCGJ
printf("\n____________\n");
//后序遍历
PostOrderTraverse(T); //KHDEBIFJGCA
printf("\n____________\n");
//清空
ClearBiTree(&T);
//判空
i_empty = BiTreeEmpty(T);
printf("二叉树是否为空(1为是/0为否):%d\n", i_empty); //二叉树是否为空(1为是/0为否):1
i_length = BiTreeDepth(T);
printf("二叉树的深度为:%d\n", i_length); //二叉树的深度为:0
}
int main()
{
test01();
return 0;
}
本文详细介绍了二叉树的概念,包括二叉树的定义、特殊类型如满二叉树和完全二叉树的特性,以及二叉树的顺序存储结构和链式存储结构。在顺序存储结构中,给出了初始化、判断空树、求深度、创建、遍历等操作的代码实现。而在链式存储结构中,文章描述了结点结构和相应的操作,如创建、遍历和销毁二叉树。
1万+

被折叠的 条评论
为什么被折叠?



