非线性表-BiTree(特殊二叉树-需记忆!!!!难啊难)

1:哈夫曼树-wpl最小-最优二叉树

复制代码
1.没有度为1的结点

2.n个叶子节点的哈夫曼树共有2n-1个结点

树的特点:度为2结点和叶结点的关系n2=n0-1
所以:当叶结点为n时,度为二的结点数为n-1
因为哈夫曼没有度为一的结点,所以一共在树中有2n-1个结点
3.哈夫曼树任意非叶结点的左右子树交换后还是哈夫曼树

4.对同一组权值{w1,w2,...,wn},是会存在不同结构的哈夫曼树
BADCADFEED
法一:直接传递字符的ASCII码,每个字符占八位,一共传递80位
法二:我们发现数据只是从A-F,一共6个字符,我们完全可以使用3位二进制来表示这些数据(网络对方需要知道我们的编码才能解码)
A    B   C   D   E   F
000 001 010 011 100 101
001000011010000011101100100011(30)
法三:我们发现一段文字中各个数字出现的频率是不一样的,各个字母频率相加100%,可以使用哈夫曼编码,对数据再次进行压缩
假设各个字母频率为
A 27,B 8,C 15,D 15,E 30,F 5
1.先构造哈夫曼树
2.获取前缀码
(1)左右分支分别用0,1表示(避免了二义性)
(2)字符只在叶子节点
1001010010101001000111100(25)
复制代码

2:平衡二叉树

看这个(重点看构造平衡二叉树时左右子树旋转方法)https://www.cnblogs.com/ssyfj/p/9504996.html

复制代码
//返回二叉树的深度,前提T存在
int depth(bitTree T)
{
    if(!T)
        return 0;
    else
        return max(depth(T->lchild),depth(T->rchild))+1;
        //这有个缺点,空树会返回深度1
}
//判断平衡二叉树
int balance(bitTree t)
{
    int left,right;
    int cha;
    if(t!=NULL)
    {
        left=depth(t.lchild);
        right=depth(t.rchild);
        cha=left-right;
        if(cha>1||cha<-1)
        {
            return false;
        }
        return  balance(t.lchild)&&balance((t.rchild));
    }

}
复制代码

3:二叉搜索树

看这个(重点看插入删除时树的变化)https://www.cnblogs.com/ssyfj/p/9503740.html

这里“查找”文章里也有叙述:https://www.cnblogs.com/Y-flower/p/15528200.html

4:线索二叉树

在这里:https://www.cnblogs.com/ssyfj/p/9465532.html

复制代码
//线索二叉树
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef char TElemType;
typedef int Status;

typedef enum {Link,Thread} PointerTag;
//二叉树的二叉链表结点结构定义
typedef struct BiTNode    //结点结构
{
    TElemType data;    //结点数据
    struct BiTNode *lchild, *rchild;    //左右孩子指针
    PointerTag ltag;
    PointerTag rtag;
}BiThrNode, *BThriTree;
复制代码
复制代码
//按照前序输入二叉树中结点的值(一个字符)#表示空树,构造二叉树表示二叉树T
void CreateBiThrTree(BThriTree *T)
{
    TElemType ch;
    scanf("%c", &ch);
    if (ch == '#')
        *T = NULL;
    else
    {
        *T = (BThriTree)malloc(sizeof(BiThrNode));
        if (!*T)
            exit(ERROR);
        (*T)->data = ch;    //生成根节点数据
        (*T)->ltag = Link;
        (*T)->rtag = Link;

        CreateBiThrTree(&(*T)->lchild);    //构造左子树
        CreateBiThrTree(&(*T)->rchild);    //构造右子树
    }
}
复制代码

线索化

复制代码
//在线索化前设置头结点
InOrderThreading(BThriTree* p,BThriTree T)
{
    *p = (BThriTree)malloc(sizeof(BiThrNode));
    (*p)->ltag = Link;
    (*p)->rtag = Thread;
    //按树的结构设置头结点
    //使他指向自己,下面判断是不是空树,再进行指向
    (*p)->rchild = *p;
    if (!T)    //T是空树的情况
    {
        (*p)->lchild = *p;
    }
    else
    {
        //使得头结点指向根节点
        (*p)->lchild = T;
        pre = *p;

        //对所有的含有空指针域的结点进行线索化,从根节点开始,不包含头结点
        InThreading(T);

        //线索化后将中序遍历最后的结点指向头结点
        pre->rchild = *p;
        pre->rtag = Thread;
        (*p)->rchild = pre;
    }
}
BThriTree pre;    //始终指向前驱结点
//进行线索化
//中序遍历线索化
void InThreading(BThriTree T)
{
    if (T)
    {
        InThreading(T->lchild);    //递归左子树线索化

        //进行线索化操作
        if (!T->lchild)    //若是没有左孩子,进行线索化
        {
            T->ltag = Thread;    //前驱线索
            T->lchild = pre;    //左孩子指针指向前驱
        }
        //我们这里是想要对该T结点进行线索化
        /*
        if (!T->rchild)
        {
            T->rtag = Thread;
            T->rchild = 下一个后继结点
        }
        */
        //但是我们无法知道下一个后继结点位置
        //我们可以反向思考,我们根据当前节点去推断前驱结点是不是可以向右线索化,来配置
        if (!pre->rchild)    //前驱没有右孩子
        {
            pre->rtag = Thread;    //后继线索
            pre->rchild = T;    //前驱有孩子指向后继(当前节点p)
        }

        pre = T;    //将前驱推移,始终保持pre执行p的前驱

        InThreading(T->rchild);    //递归右子树线索化
    }
}
复制代码

线索树遍历

复制代码
//我们是使用中序方法来线索化二叉树,所以使用中序来遍历是最方便的
void InOrderTraverse(BThriTree T)    //我们传入的是线索化带有头结点的树
{
    BThriTree p;
    p = T->lchild;    //这是根节点

    while (p != T)    //可以直接按照双向链表来处理二叉树了
    {
        while (p->ltag == Link)    //当我们找到了Thread时就是找到了最左边的结点,是双向链表的开始结点
        {
            p = p->lchild;
        }
        printf("%c", p->data);

        p = p->rchild;
        printf("%c", p->data);

        p = p->rchild;
    }
}
复制代码

 

posted on   Y-flower  阅读(330)  评论(0编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示