CH5-树和二叉树
5.1树和二叉树

5.1.1 树的定义



5.1.2基本术语

-
树的深度: 树中结点的最大层次。 -
有序树: 树中结点的各子树从左至右有次序(最左边的为第一个孩子)。 -
无序树: 树中结点的各子树无次序。


5.1.3二叉树的定义




5种基本形态

5.2案例引入
案例1∶数据压缩问题

案例2︰求解表达式的值

5.3抽象数据类型定义


5.4二叉树的性质
性质1


性质2

性质3

两种特殊形式的二叉树

5.4.1满二叉树


5.4.2完全二叉树




性质4


性质5


5.5存储结构

5.5.1顺序

//二叉树顺序存储表示#define MAXTSIZE 100
Typedef TElemType SqBiTree[MAXSTIZE]
SqBiTree bt;



实现
#include <stdio.h>
#include "stdlib.h"
#include "io.h"
#include "math.h"
#include "time.h"
#define MAXSIZE 100
#define MAX_TREE_SIZE 100
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int TElemType; /* 树结点的数据类型,目前暂定为整型 */
typedef int SqBiTree[MAX_TREE_SIZE];/* 0号单元存储根结点 */
typedef struct{
/* 结点的层,本层序号(按满二叉树计算) */
int level,order;
}Position;
//假设整数0代表为空
int Nil = 0;
//构造空的二叉树,因为T是固定数组,不会改变,故不需要&
Status InitBiTree(SqBiTree T){
int i;
for(i=0; i<MAX_TREE_SIZE; i++){
T[i] = Nil; //初始值为空
}
return 1;
}
//按层序次序输入二叉树的节点的值(字符型或整形),构造顺序存储二叉树
Status CreateBiTree(SqBiTree T){
int i =0;
printf("请按层序输入结点的值(整型),0表示空结点,输999结束。结点数≤%d:\n",MAX_TREE_SIZE);
while(i<=10){
T[i] = i+1;
if(i!=0&&T[(i+1)/2-1] == Nil&&T[i]!=Nil){
printf("出现了无双亲且非根节点%d\n",T[i]);
exit(0);
}
i++;
}
//然后将后面的值赋值为空
while(i<MAX_TREE_SIZE){
T[i] = Nil;
i++;
}
return 1;
}
//清空二叉树,在顺序存储中,两函数完全一样
#define ClearBiTree InitBiTree
/* 初始条件: 二叉树T存在 */
/* 操作结果: 若T为空二叉树,则返回TRUE,否则FALSE */
Status BiTreeEmpty(SqBiTree T){
if(T[0] == Nil){
return 1;
}
return 0;
}
/* 初始条件: 二叉树T存在。
操作结果: 返回T的深度 */
Status BiTreeDepth(SqBiTree T){
//性质2:深度为k的二叉树至多有2^k个节点
int k = 0;
while(powl(2,k)<=(10+1)){
k++;
}
return k;
}
/* 初始条件: 二叉树T存在 */
/* 操作结果: 当T不空,用e返回T的根,返回OK;否则返回ERROR,e无定义 */
Status Root(SqBiTree T){
TElemType root;
if(BiTreeEmpty(T)){
return 0;
}else{
root = T[0];
return root;
}
}
/* 初始条件: 二叉树T存在,e是T中某个结点(的位置) */
/* 操作结果: 返回处于位置e(层,本层序号)的结点的值 */
Status Value(SqBiTree T,Position e){
if(e.order <= powl(2,e.level-1)) //不超过每层的节点数
return T[(int)powl(2,e.level-1)+e.order-2];
else
return 0;
}
/* 初始条件: 二叉树T存在,e是T中某个结点(的位置) */
/* 操作结果: 给处于位置e(层,本层序号)的结点赋新值value */
Status Assign(SqBiTree T,Position e,TElemType value){
int index = (int)powl(2,e.level-1)+e.order-2;
//值不为空,且双亲节点不存在时
if(value!= Nil&&T[(index+1)/2-1]==Nil){
return 0;
}
/* 给双亲赋空值但有叶子 */
else if(value == Nil && (T[index*2+1]!=Nil || T[index*2+2]!=Nil)){
return 0;
}
T[index] = value;
return 1;
}
//求一个节点的双亲节点
TElemType Parent(SqBiTree T,Position e){
int index = 0;
index = (int)powl(2,e.level-1)+e.order-2;
//为空树或者只有根节点
if(T[0] == Nil ||(T[2*index+1]==Nil || T[2*index+2]==Nil)){
return 0;
}else{
if(index%2==0)
return T[index/2-1];
else
return T[index/2];
}
return 0;
}
//求一个节点的左孩子节点
TElemType LeftChild(SqBiTree T,Position e){
int index = 0;
index = (int)powl(2,e.level-1)+e.order-2;
if(T[0] == Nil ||(T[2*index+1]==Nil || T[2*index+2]==Nil)){
return 0;
}else{
return T[2*index+1];
}
}
//求一个节点的右孩子节点
TElemType RightChild(SqBiTree T,Position e){
int index = 0;
index = (int)powl(2,e.level-1)+e.order-2;
if(T[0] == Nil ||(T[2*index+1]==Nil || T[2*index+2]==Nil)){
return 0;
}else{
return T[2*index+2];
}
}
//求一个节点的左兄弟节点
TElemType LeftSibling(SqBiTree T,Position e){
int index = 0;
index = (int)powl(2,e.level-1)+e.order-2;
if(T[0] == Nil ||(T[2*index+1]==Nil || T[2*index+2]==Nil)){
return 0;
}else{
if(index%2==0)
return T[index-1];
else
return 0;
}
}
//求一个节点的右兄弟节点
TElemType RightSibling(SqBiTree T,Position e){
int index = 0;
index = (int)powl(2,e.level-1)+e.order-2;
if(T[0] == Nil ||(T[2*index+1]==Nil || T[2*index+2]==Nil)){
return 0;
}else{
if(index%2==0){
return 0;
}
else
return T[index+1];
}
}
//////////////////////////遍历////////////////////////////
//先序遍历的原则(递归):
void PreTraverse(SqBiTree T,int index){
printf("%d ",T[index]);
if(T[2*index+1]!=Nil){
PreTraverse(T,2*index+1);
}
if(T[2*index+2]!=Nil){
PreTraverse(T,2*index+2);
}
}
void PreOrderTraverse(SqBiTree T){
if(!BiTreeEmpty(T)){
PreTraverse(T,0);
}
printf("\n");
}
//中序遍历原则:
void InTraverse(SqBiTree T,int index){
if(T[2*index+1]!=Nil){
InTraverse(T,2*index+1);
}
printf("%d ",T[index]);
if(T[2*index+2]!=Nil){
InTraverse(T,2*index+2);
}
}
void InOrderTraverse(SqBiTree T){
if(!BiTreeEmpty(T)){
InTraverse(T,0);
}
printf("\n");
}
//后序遍历原则:
void PostTraverse(SqBiTree T,int index){
if(T[2*index+1]!=Nil){
PostTraverse(T,2*index+1);
}
if(T[2*index+2]!=Nil){
PostTraverse(T,2*index+2);
}
printf("%d ",T[index]);
}
void PostOrderTraverse(SqBiTree T){
if(!BiTreeEmpty(T)){
PostTraverse(T,0);
}
printf("\n");
}
int main(){
SqBiTree T;
InitBiTree(T);
//创建二叉树
CreateBiTree(T);
//判断是否为空
printf("二叉树是否为空:%d\n",BiTreeEmpty(T));
//清空二叉树后
//判断是否为空
printf("二叉树是否为空:%d\n",ClearBiTree(T));
//重新创建二叉树
CreateBiTree(T);
//树的深度
printf("树的深度:%d\n",BiTreeDepth(T));
//树根
printf("树的根节点:%d\n",Root(T));
//寻找某一层某个特地的元素
Position e;
e.level = 2;
e.order = 2;
printf("2层第2个是:%d\n",Value(T,e));
//修改节点元素
Assign(T,e,50);
printf("2层第2个是:%d\n",Value(T,e));
//求节点双亲
printf("2层第2个的双亲是:%d\n",Parent(T,e));
//求节点左孩子
printf("2层第2个的左孩子是:%d\n",LeftChild(T,e));
//求节点右孩子
printf("2层第2个的左孩子是:%d\n",RightChild(T,e));
//求节点左兄弟
printf("2层第2个的左兄弟是:%d\n",LeftSibling(T,e));
//求节点右兄弟
printf("2层第2个的右兄弟是:%d\n",RightSibling(T,e));
//先序遍历
printf("先序遍历\n");
PreOrderTraverse(T);
//中序遍历
printf("中序遍历\n");
InOrderTraverse(T);
//后序遍历
printf("后序遍历\n");
PostOrderTraverse(T);
return 0;
}

5.5.2链式
二叉链表

typedef struct BiNode{
TElemType data;
struct BiNode *lchild, *rchild; //左右孩纸
}BiNode,*BiTree;


三叉链表

typedef struct TriTNode{
TelemType data;
struct TriTNode *lchild,*parent,*rchild;
}TriTNode,*TriTree;
5.6遍历二叉树

5.6.1.遍历二叉树



先序遍历

中序遍历

后序遍历



5.6.2遍历序列

例题1



例题2

5.6.3算法实现
【算法1】:先序

Status PreOrderTraverse(BiTree T){
if(T==NULL) return OK; //空二叉树
else{
visit(T); //访问根结点
PreOrderTraverse(T->lchild);//递归遍历左子树
PreOrderTraverse(T->rchild);//递归遍历右子树
}
}
void Pre(BiTree *T) {
if (T!=NULL) {
printf("%d\t",T->data);
pre(T->lchild);
pre(T->rchild);
}
}

【算法2】:中序

Status InOrderTraverse(BiTree T){
if(T==NULL) return OK;//空二叉树
else{
InOrderTraverse(T->lchild);//递归遍历左子树
visit(T);//访问根结点;
InOrderTraverse(T->rchild);//递归遍历右子树}
}
}
【算法3】:后序

Status PostOrderTraverse(BiTree T){
if(T==NULL) return OK;//空二叉树
else{
PostOrderTraverse(T->lchild);//递归遍历左子树
PostOrderTraverse(T->rchild);//递归遍历右子树
visit(T);//访问根结点
}
}
算法分析



【算法4】:中序非递归

Status InOrderTraverse (BiTree T) {
BiTree p; InitStack(S); p=T;
while(p || !StackEmpty(S)) {
if(p) {
Push(S,p);
p = p->lchild;
}
else {
Pop(S,q);
printf(“%c”,q->data);
p= q->rchild;
}
}
return OK;
}
【算法5】:层次遍历


typedef struct{
BTNode data[MaxSize]; //存放队中元素
int front,rear; //队头和队尾指针
} SqQueue; //顺序循环队列类型
void LevelOrder(BTNode *b) {
BTNode *p; SqQueue *qu;
InitQueue(qu); //初始化队列
enQueue(qu,b); //根结点指针进入队列
while (!QueueEmpty(qu) ) { //队不为空,则循环
deQueue(qu,p); //出队结点p
printf("%c ", p->data); //访问结点p
if (p->lchild!=NULL) enQueue(qu,p->lchild); //有左孩子时将其进队
if (p->rchild!=NULL) enQueue(qu,p->rchild); //有右孩子时将其进队
}
}
5.6.4算法的应用
【算法6】:二叉树的建立


Status CreateBiTree(BiTree &T) {
scanf(&ch); //cin> >ch;
if (ch== “#”) T = NULL;
else {
if (!(T =(BiTNode *)malloc(sizeof(BiTNode))))
exit(OVERFLOW); //T=new BiTNode;
T->data = ch; //生成根结点
CreateBiTree(T->lchild);//构造左子树
CreateBiTree(T->rchild);//构造右子树
}
return OK;
}// CreateBiTree
【算法7】:复制二叉树

int Copy(BiTree T,BiTree &NewT){
if(T==NULL){//如果是空树返回0
NewT=NULL;return 0;
}
else {
NewT=new BiTNode;
NewT->data=T->data;
Copy(T->lChild,NewT->lchild);
Copy(T->rChild,NewT->rchild);
}
}
【算法8】:计算二叉树深度![20220113185653]()
int Depth( BiTree T){
if(T==NULL) return O;//如果是空树返回0
else {
m=Depth(T->lChild);
n =Depth(T->rChild);
if(m>n) return (m+1);
else return(n+1);
}
}
【算法9】:计算二叉树结点总数

int NodeCount(BiTree T){
if(T == NULL)
return O;
else
return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
}
【算法10】:计算二叉树叶子结点总数

int LeadCount(BiTree T){
if(T==NULL) //如果是空树返回0
return O;
if (T->lchild == NULL && T->rchild == NULL)
return 1; //如果是叶子结点返回1
else
return LeafCount(T- >lchild) +LeafCount(T->rchild);
}
5.7线索二叉树




typedef struct BiThrNode{
int data;
int Itag, rtag;
struct BiThrNode *Ichild,rchild;
}BiThrNode,*BiThrTree ;





5.8树和森林

5.8.1双亲表示法


typedef struct PTNode {
TElemType data;
int parent; //双亲位置域
}PTNode;
#define MAX_TREE_SIZE 100
typedef struct {
PTNode nodes[MAX_TREE_SIZE];
int r, n; //根结点的位置和结点个数
}PTree;
5.8.2孩子链表


typedef struct CTNode {
int child;
struct CTNode *next;
}*ChildPtr;
typedef struct {
TElemType data;
ChildPtr firstchild;//孩子链表头指针
}CTBox;
typedef struct {
CTBox nodes[MAX_TREE_SIZE];
int n, r;//结点数和根结点的位置
}CTree;
5.8.3孩子兄弟表示法

typedef struct CSNode{
ElemType data;
struct CSNode *firstchild, *nextsibling;
}CSNode,*CSTree;

5.8.4树与二叉树的转换






5.8.5森林与二叉树的转化




5.8.6树与森林的遍历


先序

中序


5.9哈夫曼树及其应用
5.9.1基本概念









5.9.2构造算法





5.9.3算法实现



typedef struct {
int weight;
int parent, lch, rch;
}HTNode,*HuffmanTree;
void CreatHuffmanTree (HuffmanTree HT, int n){//构造哈夫曼树——哈夫曼算法
if(n<=1) return;
m=2*n-1; //数组共2n-1个元素
HT=new HTNode[m+1]; //0号单元未用,HT[m]表示根结点
for(i=1;i<=m;++i){ //将2n-1个元素的lch、rch、parent置为0
HT[i].Ich=O; HT[i].rch=O; HT[i].parent=O;
}
for(i=1;i<=n;++i) cin>>HT[i].weight;//输入前n个元素的weight值
//初始化结束,下面开始建立哈夫曼树
for( i=n+1;i<=m; i++){ //合并产生n-1个结点-构造Huffman树
Select(HT, i-1,s1, s2); //在HT[k](1≤k≤i-1)中选择两个其双亲域为0,
//且权值最小的结点,并返回它们在HT中的序号s1和s2
HT[s1].parent=i; HT[s2].parent=i; //表示从F中删除s1,s2
HT[i].lch=s1; HT[i].rch=s2 ;
//s1,s2分别作为i的左右孩子
HT[i].weight=HT[s1].weight + HT[s2].weight;//i的权值为左右孩子权值之和
}
}

5.9.4哈夫曼编码








void CreatHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n){
//从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
HC=new char *[n+1]; //分配n个字符编码的头指针矢量
cd=new char [n]; //分配临时存放编码的动态数组空间
cd[n-1]= ‘1O’; //编码结束符
for(i=1; i<=n; ++i){ //逐个字符求哈夫曼编码
start=n-1; c=i; f=HT[i].parent;
while(f!=O){ //从叶子结点开始向上回溯,直到根结点
--start; //回溯一次start向前指一个位置
if (HT[f].Ilchild= =c) cd[start]= '0’ ; //结点c是f的左孩子,则生成代码0
else cd[start]= ‘1’ ; //结点c是f的右孩子,则生成代码1
c=f; f=HT[f].parent; //继续向上回溯
} //求出第i个字符的编码
HC[i]= new char [n-start]; //为第i个字符串编码分配空间
strcpy(HC[i],&cd[start]); //将求得的编码从临时空间cd复制到HC的当前行中
}
delete cd; //释放临时空间
}// CreatHuffanCode
5.9.5文件的编码和解码






浙公网安备 33010602011771号