1. 二叉树的概念
1.1 二叉树的定义(递归定义)
二叉树是有限的节点集合。
- 这个集合或者是空。
- 或者由一个根节点和两棵互不相交的称为左子树和右子树的二叉树组成。
二叉树的5种基本形态:
二叉树的4种表示方法:
- 树型表示法
- 文氏图表示法
- 凹入表示法
- 括号表示法
两种特殊的二叉树:
①满二叉树
在一棵二叉树中:
- 如果所有分支节点都有双分节点;
- 并且叶节点都集中在二叉树的最下一层。
- 高度为h的二叉树恰好有2^ h -1 个节点。
则称之为满二叉树。
②完全二叉树
在一棵二叉树中:
- 最多只有下面两层的节点的度数小于2
- 并且最下面一层的叶节点都依次排列在该层最左边的位置上。
- 完全二叉树实际上是对应的满二叉树删除叶节点层最右边 若干个节点得到的。
示例:
1.2 二叉树的性质
【性质1】 非空二叉树上叶节点数等于双分支节点数加1。即: n0 =n2+1。
【性质2】 非空二叉树上第 i 层上至多有2^( i-1)个节点(i≥1)。
【性质3】高度为h的二叉树至多有2 ^h -1个节点(h≥1)。
【性质4】n 个结点的完全二叉树深度为 。
【性质5】n 个结点的完全二叉树,结点按层次编号,则有:
1.3 二叉树与树、森林之间的转换
①树与二叉树的转换
特点:由树转化成的二叉树,根结点没有右孩子。
例如:
②森林与二叉树的转换
森林中第 1 棵树的根作为对应的二叉树的根;其他的树看作第 1 棵树的兄弟;森林中 的树转换成对应的二叉树。则森林转换成对应的二叉树。
例如:
2. 二叉树的存储结构
2.1 顺序存储结构
用数组、编号 i 的结点存放在[i-1]处。适合于存储完全二叉树。
存储表示:
#define MAX_TREE_SIZE 100 //二叉树的最大结点数
typedef TElemType SqBiTree[ MAX_TREE_SIZE ]; //0号单元存储根结点
SqBiTree bt;
二叉树顺序存储结构的特点:
- 对于完全二叉树来说,其顺序存储是十分合适的。
- 对于一般的二叉树,特别是对于那些单分支节点较多的二叉树来说 是很不合适的,因为可能只有少数存储单元被利用,特别是对退化 的二叉树(即每个分支节点都是单分支的),空间浪费更是惊人。
- 在顺序存储结构中,找一个节点的双亲和孩子都很容易。
2.2 链式存储结构
借鉴树的孩子链存储结构 → 二叉树的链式存储结构。
二叉链表:
typedef struct BTNode {
DataType data;
struct BTNode *lchild, *rchild;
} BTNode, *BinTree;
二叉链存储结构的特点:
- 除了指针外,二叉链比较节省存储空间。占用的存储空间与树形 没有关系,只与树中节点个数有关。
- 在二叉链中,找一个节点的孩子很容易,但找其双亲不方便。
三叉链表:
typedef struct BTNode {
DataType data;
struct BTNode *lchild, *rchild, *parent;
} BTNode, *BinTree;
示例:
3、二叉树的基本操作及实现
3.1 基本操作
①创建二叉树
函数原型:Status CreatBiTree(BiTree &T);
操作结果:构造二叉链表表示二叉树。
②先序遍历
函数原型:Status PreOrderTraverse(BiTree T);
操作结果:先序遍历二叉树T。
③中序遍历
函数原型:Status InOrderTraverse(BiTree T);
操作结果:中序遍历二叉树T。
④先序遍历
函数原型:Status PostOrderTraverse(BiTree T);
操作结果:后序遍历二叉树T。
⑤层序遍历
函数原型:Status LeveOrderTraverse(BiTree T);
操作结果:层序遍历二叉树T。
⑥统计叶子结点数
函数原型:int CountLeaf(BiTree T);
操作结果:统计二叉树T的叶子结点数。
⑦测深度
函数原型:int BiTreeDepth(BiTree T);
操作结果:测二叉树T的深度。
⑧销毁二叉树
函数原型:Status DestroyBiTree(BiTree &T);
操作结果:销毁二叉树T。
3.2 代码实现
//----*----*----*---
//程序名称:二叉树
//编译环境:VC++ 6.0
//作者:Bee_darker
//修改日期:2018-11-26
//----*----*----*---
#include<stdio.h>
#include<stdlib.h>
//#include "LinkQueue.h"
#define OK 1
#define OVERFLOW -1
#define ERROR 0
typedef int Status;
typedef char TElemType;
typedef struct BiTNode{
TElemType data;
struct BiTNode *lchild,*rchild;
}BiTNode, *BiTree;
//创建
Status CreatBiTree(BiTree &T)
{
char ch;
scanf("%c",&ch);
if(ch == '#') //空树
T = NULL;
else{
T = (BiTNode*)malloc(sizeof(BiTNode));
if(!T) exit(OVERFLOW);
T->data = ch; //生成根结点
CreatBiTree(T->lchild); //构造左子树
CreatBiTree(T->rchild); //构造右子树
}
return OK;
}
//先序遍历
Status PreOrderTraverse(BiTree T)
{
if(T){
printf("%c\t",T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
return OK;
}
//中序遍历
Status InOrderTraverse(BiTree T)
{
if(T){
InOrderTraverse(T->lchild );
printf("%c\t",T->data);
InOrderTraverse(T->rchild);
}
return OK;
}
//后序遍历
Status PostOrderTraverse(BiTree T)
{
if(T){
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c\t",T->data);
}
return OK;
}
//统计叶子结点数
int CountLeaf(BiTree T)
{
static int count = 0;
if(T){
if(!T->lchild && !T->rchild )
count++;
CountLeaf(T->lchild );
CountLeaf(T->rchild );
}
return count;
}
//测深度
int BiTreeDepth(BiTree T)
{
int ldepth,rdepth,max_depth;
if(T){
ldepth = BiTreeDepth(T->lchild );
rdepth = BiTreeDepth(T->rchild );
max_depth = (ldepth > rdepth) ? ldepth : rdepth;
return max_depth + 1;
}
else return 0;
}
/*层序遍历1
void LevelOrderTraverse(BiTree BT)
{
TElemType e;
LinkQueue Q;
BiTree T;
if( !BT ) return ;
InitQueue(Q);
EnQueue(Q,BT->data );
while( !QueueEmpty(Q))
{
T->data = DeQueue(Q,e);
printf("%d\n",T->data);
if( T -> lchild)
EnQueue(Q,T ->lchild->data);
if( T -> rchild)
EnQueue(Q,T ->rchild->data);
}
}
*/
//层序遍历2
void LevelOrderTraverse(BiTree T)
{
const int MAXSIZE = 1024;
BiTree p;
BiTree q[MAXSIZE];
int front, rear;
front = rear = 0; // 队列初始化为空
q[rear] = T;
rear = ( rear+1 ) % MAXSIZE; // 根入队列
while ( front != rear ) { // 队列不空则循环
p = q[front];
front = ( front+1 ) % MAXSIZE;
if ( p ) {
printf("%c\t", p->data );
q[rear] = p->lchild;
rear = ( rear+1 ) % MAXSIZE;
q[rear] = p->rchild;
rear = ( rear+1 ) % MAXSIZE; // 左、右子树入队列
}//if
}//while
}
//销毁
Status DestroyBiTree(BiTree &T)
{
if(T){
DestroyBiTree(T->lchild );
DestroyBiTree(T->rchild );
free(T);
}
return OK;
}
//打印
void PrintMenu(){
printf("**********二叉树的应用*************\n");
printf("* *\n");
printf("* 1.创建二叉树 *\n");
printf("* 2.先序遍历二叉树 *\n");
printf("* 3.中序遍历二叉树 *\n");
printf("* 4.后序遍历二叉树 *\n");
printf("* 5.层序遍历二叉树 *\n");
printf("* 6.统计叶子结点数 *\n");
printf("* 7.测量二叉树深度 *\n");
printf("* 8.销毁二叉树 *\n");
printf("* 0.退出 *\n");
printf("***********************************\n");
}
int main()
{
int action;
BiTree T;
while(1){
PrintMenu();
fflush(stdin);
printf("请输入指令:");
scanf("%d",&action);
fflush(stdin);
switch(action)
{
case 1:system("cls");
printf("请按先序遍历方式输入:");
CreatBiTree(T);
printf("二叉树创建成功!\n\n");
break;
case 2:system("cls");
printf("先序遍历二叉树:");
PreOrderTraverse(T);
printf("\n\n");
break;
case 3:system("cls");
printf("中序遍历二叉树:");
InOrderTraverse(T);
printf("\n\n");
break;
case 4:system("cls");
printf("后序遍历二叉树:");
PostOrderTraverse(T);
printf("\n\n");
break;
case 5:
system("cls");
printf("层序遍历二叉树:");
LevelOrderTraverse(T);
printf("\n\n");
break;
case 6:system("cls");
printf("叶子结点数为:%d\n",CountLeaf(T));
break;
case 7:system("cls");
printf("二叉树深度为:%d\n",BiTreeDepth(T));
break;
case 8:system("cls");
if(DestroyBiTree(T))
printf("二叉树销毁成功!!!\n");
break;
case 0:
exit(1);break;
default:
system("cls");
printf("输入命令错误!请重新输入:\n");
break;
}
}
return 0;
}