数据结构-树

二叉树

基本概念

二叉树是n个节点的有限集合

每个节点之多有两个子树

左右子树不能颠倒,有序树

请添加图片描述

满二叉树:一个高度为h,含有2^h-1个节点的二叉树
请添加图片描述

平衡二叉树:任意节点的左子树和右子树的深度之差不超过1

二叉树存储结构

顺序存储

#define MAXSIZE 100
struct TreeNode{
    ElemType value;
    bool isEmpty;
};
TreeNode t[MAXSIZE];
for(int i = 0;i<MAXSIZE;i++){
    t[i].inRmpty = true;
}

请添加图片描述
请添加图片描述

  • i的左孩子 ——2i
  • i的右孩子 ——2i+1
  • i的父节点 ——i/2
  • i所在的层

二叉树的顺序存储结构只适合存储完全二叉树

链式存储

typedef struct BiTNode{
    ElemType data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
BiTree root = NULL;
root = new BiTNode;
root->data = 1;
root->lchild = NULL;
root->rchild = NULL;

二叉树的遍历

先序遍历

根左右

代码:

void PreOrder(BiTree T){
    if(T!=NULL){
        visit(T);
        PreOrder(T->lchild);
        PreOrder(T->rchild);
    }
}

中序遍历

左根右

void PreOrder(BiTree T){
    if(T!=NULL){
        PreOrder(T->lchild);
         visit(T);
        PreOrder(T->rchild);
    }
}

后序遍历

左右根

void PreOrder(BiTree T){
    if(T!=NULL){
        PreOrder(T->lchild);
        PreOrder(T->rchild);
        visit(T);
    }
}

遍历算法的举例

请添加图片描述
请添加图片描述

求树的深度

int treeDepth(Bitree T){
    if(T == NULL){
        return 0;
    }else{
        int l = treeDepth(T->lchild);
        int r = treeDepth(T->rchild);
        return l>r?l+1:r+1;
    }
}

二叉树的层序遍历

请添加图片描述

层序遍历结果为

abcdefghijkl

算法思想:

初始化一个辅助队列

根节点入队

若队列非空,则队头节点出队,访问该节点,并将其左右孩子插入队尾

重复3直到队空

void LevelOrder(Bitree T){
    LinkQueue Q;
    InitQueue(Q);
    BiTree p;
    EnQueue(Q,p);
    while(!IsEmpty(Q)){
        DeQueue(Q,p);
        visit(p);
        if(p->lchild!=NULL)
            EnQueue(Q,p->lchild);
        if(p->rchild!=NULL)
            EnQueue(Q,p->rchild);
    }
}

由遍历序列构造二叉树

若只给出一棵二叉树的前中后层遍历序列中的一种,不能唯一确定一个二叉树
请添加图片描述

线索二叉树

请添加图片描述

typedef struct ThreadNode{
    ElemType data;
    struct ThreadNode *lchild,*rchild;
    int ltag,rtag;
}ThreadOde,*ThreadTree;//tag==0指向孩子,tag==1指向线索

请添加图片描述

二叉树线索化

用土方法找到中序前驱

//中序遍历
void InOrder(BiTree T){
    if(T!=NULL){
        InOrder(T->lchild);
        visit(T);
        InOrder(T->rchild);
    }
}
//访问节点q
void visit(BiTNode *q){
    if(q==p)
        final = pre;
    else 
        pre = q;
}
BiTNode *p;
BiTNode *pre=NULL;
BiTNode *final=NULL;

中序线索化

ThreadNode *pre = NULL;
void CreatInThread(ThreadTree T){
    pre = NULL;
    if(T!=NULL){
        InThread(T);
        if(pre->rchild==NULL)
            pre->rtag = 1;
    }
}
Typedef struct ThreadNode{
    ElemType data;
    mstruct ThreadNode *lchild,*rchild;
    int ltag,rtag;
}ThreadNode,*ThreadTree;
void InThread(TreadTree T){
    if(T!=NULL){
        InThread(T->lchild);
        visit(T);
        InThread(T->rchild);
    }
} 
void visit(ThreadNode *q){
    if(q->lchild==NULL){
        q->lchild=pre;
        q->ltag=1;
    }
    if(pre!=NULL&&pre->rchild==NULL){
        pre->rchild=q;
        pre->rtag=1;
    }
    pre=q;
}

线索二叉树寻找前驱后继

中序线索

//找到以p为根的子树中,第一个被中序遍历的结点
ThreadNode *Firstnode(ThreadNode *p){
    while(p->ltag == 0)
        p=p->lchild;
    return p;
}
//在中序线索二叉树中找到结点p的后继节点
ThreadNode *NextNode(ThreadNode *p){
    if(p->rtag==0)
        return Firstnode(p->rchild);
    else return p->rchild;
}
//对中序二叉树进行中序遍历(线索二叉树实现非递归算法)
void Inorder(ThreadNode *p){
    for(ThreadNode *p = Firstnode(T);p!=NULL;p=Nextnode(p))
        visit(p);
}

寻找前驱原理相似

先序线索

先序线索二叉树第一个结点为根节点,即直接寻找后继结点

//在先序线索二叉树中找到结点p的后继节点
ThreadNode *NextNode(ThreadNode *p){
    if(p->ltag = 0)
        return p->lchild;
    else return p->rchild;
}

树:存储结构

双亲表示法

每个节点保存指向双亲的指针

#define MAX_TREE_SIZE 100
typedef struct{
    ElemType data;
    int parent;
}PTNode;
typedef struct{
    PTNode nodes[MAX_TREE_SIZE];
    int n;
}PTree;

孩子表示法

顺序存储各个节点,每个节点中保存孩子链表头指针

孩子兄弟表示法(链式存储)

typedef struct CSNode{
    ElemType data;//数据域
    struct CSNode *firstchild,*nextsibling;//第一个孩子和右兄弟指针
}CSNode,*CSTree;

请添加图片描述

森林和二叉树的相互转换

森林是m个互不相交的树的集合

请添加图片描述

各个树的根节点视为兄弟关系
请添加图片描述

请添加图片描述

树,森林的遍历

先根遍历。若树非空,先访问根节点,再依次对每棵子树进行先跟遍历

void PreOrder(TreeNode *R){
    if(R!=NULL){
        visit(R);
        while()
            PreOrder(T);
    }
}

后根遍历。若树非空,先访问子节点,再依次对每棵子树进行后跟遍历

。。。

层次遍历

哈夫曼树

带权路径长度

结点的权:有某种含义的数值

结点的带权路径长度:从树的根到该结点的路径长度与权值的乘积

树的带权路径长度:树中所有叶节点的带权路径长度之和

在含有n个带权叶结点的二叉树中,其中带权路径长度最小的二叉树称谓哈夫曼树,最优二叉树[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2QNsklAj-1683633433512)(1683632615035.png)]

哈夫曼编码

前缀编码

构造哈夫曼树的方法构造编码

并查集(2022新增考点)

{
visit®;
while()
PreOrder(T);
}
}


后根遍历。若树非空,先访问子节点,再依次对每棵子树进行后跟遍历

。。。

层次遍历

# 哈夫曼树

## 带权路径长度

结点的权:有某种含义的数值

结点的带权路径长度:从树的根到该结点的路径长度与权值的乘积

树的带权路径长度:树中所有叶节点的带权路径长度之和

在含有n个带权叶结点的二叉树中,其中带权路径长度最小的二叉树称谓哈夫曼树,最优二叉树
![请添加图片描述](https://img-blog.csdnimg.cn/c624c5a7aef146a2b5dfe5b49048b734.png)


**哈夫曼编码**

前缀编码

构造哈夫曼树的方法构造编码

# 并查集(2022新增考点)

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值