本文打出了大部分树的操作 和部分知识点 还有自己编写的哈夫曼树中的select函数(看书上是直接调用便自己打出了自己理解的select函数,有错请在评论区指出)
后续会补充栈,队列,线性表操作总结。
//二叉树树的存储结构
typedef struct BeTnode{
char data;
struct BeTnode*left,*right;
}BeTnode,*BeTree;
// 建立先序二叉树 要正好返回
BeTree jianlierchashu (BeTree t)
{
char ch;
scanf("%c",&ch);
if(ch=='#')
{
return ;
}
if(ch!='#')
{
t=(BeTree) malloc (sizeof(BeTnode));
t->data=ch;
t->left=NULL;
t->right=NULL;
jianlierchashu(t->left);
jianlierchashu(t->right);
return t;
}
}
// 求二叉树叶子节点的个数
int yezijiediangeshu(BeTree t)
{
if(t==NULL)
{
return 0;
}
if(t->left==NULL&&t->right==NULL)
{
return 1;
}
int n=0,m=0;
n=yezijiediangeshu(t->left);
m=yezijiediangeshu(t->right);
return m+n ;
}
// 求二叉树节点个数
int jiediangeshu(BeTree t)
{
if(t==NULL)
{
return 0;
}
int n=0,m=0;
n=jiediangeshu(t->left);//0 1
m=jiediangeshu(t->right);//0
return 1+n+m;//1
}
//二叉树树的深度
int shendu(BeTree t)
{
if(t==NULL)
return 0;
int n=0,m=0;
n=shendu(t->left);
m=shendu(t->right);
return n>m?n+1:m+1;
}
// 中序线索二叉树
/*
主要是添加两个标识域
ltage= 1-则左指针域前驱 0-则左指针域左孩子
rtage= 1-则右指针域后驱 0-则右指针域右孩子
物理存储结构
*/
typedef struct TNode{
char data;
struct TNode *left;
struct TNode *right;
int ltage;
int rtage;
}TNode,*BTNode;
void xiansuoerchashu(BTNode t)
{
BTNode pro=NULL;
if(t)
{
xiansuoerchashu(t->left); //因为为中序所以 要从左开始 递归调用到最左 返回
if(t->left==NULL)
{
t->ltage=1;//设置标记
t->left=pro; //pro为前驱 全局变量 初始值为NULL
}
else
t->ltage=0;
if(pro->right==NULL) //这里为什么是pro那?因为现在操作的是t 只有t和pro的地址 所以要填充pro的右指针域
{
pro->rtage=1;
pro->right=t;
}
else
pro->rtage=0;
pro=p; //因为当前节点的操作完成了 所以将其赋值 递归右子树
xiansuoerchashu(t->right);
}
}
//树的存储 -1 双亲表示法
typedef struct PTNode{
char data;
int parent;// 双亲位置域
}PTNode; //节点
//树结构
# define MAXSIZE 100
typedef struct {
PTNode node[MAXSIZE];//创建数组 可以存放MAXSIZE个节点
int r,n; //根节点位置个数
}PTree;
//树的存储 -2 孩子表示法
//孩子节点结构的定义
typedef struct CTNode{
int child; // int 类型 为该孩子在数组中的下标
struct CTNode* nexthaizi; // 双亲节点的下一个孩子
}*childptr;
//双亲节点结构
typedef struct
{
char data;
childptr firstchild; //孩子链表的头指针
}CTBox;
//树结构
typedef struct {
CTBox node[MAXSIZE];
int r,n; //根节点的位置和节点数
}CTree;
//方便找孩子 不方便找双亲 则添加一个双亲节点
typedef struct
{
char data;
int pro;
childptr firstchild; //孩子链表的头指针
}CTBox;
//带双亲的孩子链表
//树的存储 -3 二叉链表表示法
/*
左指针域 ---第一个孩子结点
右指针域 ---向右一个 兄弟结点
找双亲比较困难
*/
typedef struct CTNode{
char data;
struct CTNode * lefthaizi;
struct CTNode *rightxdi;
}CTNode;
//哈夫曼树
// 结点结构
typedef struct Hafuman //顺序存储 --- 1维结构数组
{
//权值
//双亲 左孩子右孩子下标
int weight;
int parent,left,right;
}Hafuman,*THafuman; //---是动态数组存储一个哈夫曼树
//建立哈夫曼树(最优二叉树)
/*
权值越大越靠近根
所以找权值要从小到大 从下到上进行构造哈夫曼树
每个权值都是根 权值实际也是叶子节点
而且不唯一,因为没有限定左右子树,并且有权值重复时,可能树的高度都不唯一,唯一的只是带权路径长度之和最小。
王卓老师的口诀
构造森林全是根 选用二小造新树
删除二小添新人 重复2,3剩单根
*/
void creatHfm(THafuman t,int n) // t是哈夫曼树 n是 有权值的个数(叶子节点) 需要合并n-1次
{
if(n<=1)
return ;
/*
1. 建数组 for循环初始化 3个域均为0
2. 选出无双亲 中权值最小的两个 组成新的二叉树
3. 组成后 权值最小的两个 消失(有双亲)
*/
int m=2*n-1;
t=(THafuman) malloc(sizeof(Hafuman)*(1+m)); //从1开始使用
for(int i=1;i<m+1;i++)
{
t[i].left=0;
t[i].parent=0;
t[i].right=0;
}
for(int i=1;i<n+1;i++)
{
scanf("%d",&t[i].weight);
}
//-----------------------------------------------------------
//因为要 选出无双亲 中权值最小的两个 组成新的二叉树 所以要自定义函数胡
int s1,s2;
for(i=n+1;i<m+1;i++)
{
select(t,&s1,&s2,i);
t[i].weight=s1+s2;
t[i].right=s1;
t[i].left=s2;
}
}
int cmp(int *x, int *y) {
return *x - *y;
}
void select(THafuman *t,int &s1,int &s2,int n) //s1,s2是需要返回的值
{
int m=sizeof(t)/sizeof(Hafuman);
THafuman a[m];//指针数组
int j=0;
for(int i=1;i<m;i++)
{
if(t[i].parent==0)
{
a[j]=t[i];
j++;
}
} int i=0;
qsort(a,j,sizeof(Hafuman),cmp);
for(i=0;i<m;i++)
{ int p=0;
if(a[0]==t[i]||a[1]==t[i])
{
p++;
t[i].parent=n;
if(p==1)
*s1=i;
else
*s2=i;
}
}
}
//哈夫曼编码
//算概率大 则权大 则要靠近根
//左分支标记为0,右分支标记为1进行编码
/*
从根到叶子进行编码
*/
本篇文章主要是树的操作
本文转载自: https://blog.csdn.net/m0_61469860/article/details/124377897
版权归原作者 &volume 所有, 如有侵权,请联系我们删除。
版权归原作者 &volume 所有, 如有侵权,请联系我们删除。