【数据结构】【树】

除了根节外,任何一个节点都有且仅有一个前驱

树是一种递归定义的数据结构

两个节点之间的路径是有向的,只能从上往下

 

树的度:各结点的度的最大值

m叉树:每个节点最多只能有m个孩子的树

 

 

  度为m的树、m叉树第i层最多有 mi-1 个节点

高度为h的m叉树最多有mh-1/m-1

高度为h的m叉树至少有h个节点,高度为h,度为m的树至少有h+m-1个节点

具有n个结点的n叉树的最小高度为  [logm(n(m-1)+1)]

二叉树

二叉树是有序树,左右子树不能颠倒

每个节点最多只有两颗子树

满二叉树:(1)一棵高度为h,且含有2h-1个节点的二叉树;

                  (2)只有最后一层有叶子结点;

                  (3)不存在度为1的结点;按层序从1开始编号,节点i的做孩子为2i,右孩子为2i+1,节点i的股节点为i/2

                  (4)满二叉树一定是完全二叉树

完全二叉树:(1)只有最后两层可以有叶子结点;

                      (2)最多只有一个度为1的节点;

                      (3)按层序从1开始编号,节点i的左孩子为2i,右孩子为2i+1,节点i的根节点为i/2;

                      (4)i<=[n/2]为分支节点,i>[n/2]为叶子结点;

                      (5)如果某结点只有一个孩子,那一定是左孩子

                      (6)设度为 0 结点(叶子结点)个数为 A,度为 1 的结点个数为 B,度为 2 的结点个数为 C,有A=C+1, A+B+C=总结点数

 

 

 

 

 

 

二叉排序树:(1)左子树上所有节点的关键字均小于根节点的关键字;右子树上所有节点的关键字均大于根节点的关键字

                      (2)左子树和柚子树又各是一棵二叉排序树

                      (3)二叉排序树棵用于元素的排序、搜索

 

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

                      (2)一颗高度不高的树,搜索起来遍历的次数不会太多,有更高的搜索效率

 

 

 

 二叉树的顺序存储中,一定要把二叉树的节点编号与完全二叉树对应起来,方便判断节点结构

复制代码
//二叉树的顺序存储
#define MaxSize 100
struct TreeNode{
  ElemType value;//节点中的数据元素
  bool isEmpty;//节点是否为空
};
TreeNode t[MaxSize];//数组t按照从上至下,从左至右的顺序依次存储完全二叉树中的各个节点
for(int i=0;i<MazSize;i++){
 t[i].isEmpty=true;   //初始化时所有节点标记为空
}
复制代码

链式存储

n个节点的二叉链表共有n+1个空链域(空链域可用于构造线索二叉树)

复制代码
struct TreeNode{
 int value;//节点中的数据元素
};
typedef struct BiTNode{
    ElemType data;//节点中的数据元素
    struct BiTNode *lchild,*rchild;//左右孩子指针
}BiTNode,*BiTree;
//定义一颗空树
BiTree root = NULL;
//插入根节点
root = (BiTree) malloc(sizeof(BiTNode));
root->data = {1};
root->lchild = NULL;
root->rchild = NULL;
//插入新节点
BiTNode * p = (BiTNode *) malloc(sizeof(BiTNode));
root->data = {2};
root->lchild = NULL;
root->rchild = NULL;
root->lchild = p;
复制代码

三叉链表:方便寻找父亲节点,父亲节点只能从头开始遍历

//三叉链表
typedef struct BiTNode{
    ElemType data;//节点中的数据元素
    struct BiTNode *lchild,*rchild;//左右孩子指针
    struct BiTNode *parent;
}BiTNode,*BiTree;

二叉树的遍历

先序遍历:根左右

中序遍历:左根右

后序遍历:左右根

复制代码
//先序遍历
typedef struct BiTNode{
    ElemType data;//节点中的数据元素
    struct BiTNode *lchild,*rchild;//左右孩子指针
}BiTNode,*BiTree;
void PreOrder(BiTree T){//T指向第一个节点
    if(T!=NULL){
      visit(T);
      PreOrder(T->lchild);
      PreOrder(T->rchild);
    }
}
//中序遍历
typedef struct BiTNode{
    ElemType data;//节点中的数据元素
    struct BiTNode *lchild,*rchild;//左右孩子指针
}BiTNode,*BiTree;
void PreOrder(BiTree T){
    if(T!=NULL){
      PreOrder(T->lchild);
      visit(T);
      PreOrder(T->rchild);
    }
}
//后序遍历
typedef struct BiTNode{
    ElemType data;//节点中的数据元素
    struct BiTNode *lchild,*rchild;//左右孩子指针
}BiTNode,*BiTree;
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;
    }
}
复制代码

 二叉树的层序遍历:初始化一个辅助队列,根节点入队,若队列非空。则队头节点出队,访问该节点,并且将其左右孩子插入对尾,一直重复这个操作直到队空

复制代码
//二叉树的层序遍历
void LevelOrder(BiTree T){
  LinkQueue Q;
  InitQueue(Q);
  BiTree P;
  EnQueue(Q,T); //让元素入队的时候入的是指针
  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 BiNode{
   ElemType data;
   struct BiNode *lchild,*rchile;
   int ltag,rtag;   //左右线索标志 tag==0表示指针指向孩子,tag==1表示指针是线索
}ThreadNode,*ThreadTree;

 树的存储:

双亲表示法(顺序存储)设置数据域和“指针”域,“指针”域的数是双亲的序号。

二叉树的顺序存储中,一定要把二叉树的节点编号与完全二叉树对应起来,节点编号不仅反映了存储位置,也隐含了节点之间的逻辑关系(i的左孩子2i,右孩子2i+1,父节点i/2)

孩子表示法(顺序+链式)

复制代码
//孩子表示法
struct CTNode{
  int child;//孩子节点在数组中的位置
  struct CTNode *node;//下一个孩子
};
typedef struct {
  ElemType data;
  struct CTNode *firstChild;//第一个孩子
}CTBox;
typedef struct {
 CTBox nodes[MAX_TREE_SIZE];
  int n,r;
}CTree;
复制代码

孩子兄弟表示法(链式)实现了树和二叉树的转换

//孩子兄弟表示法
typedef struct CSNode{
    ElemType data;
    struct CSNode *firstChild ,*nextsibling;//第一个孩子和右兄弟指针
}CSNode,*CTree;

 

 

 

 

树的先根遍历:若树非空,先访问根节点,在依次对每颗子树进行先根遍历。

树的先根遍历序列与这颗树相应的二叉树的先序序列相同。

//树的先根遍历
void PreOrder(TreeNode *R){
  if(R!=NULL)
      visit(R);//访问根节点
      while(R还有下一课子树T)
          PreOrder(T);//先遍历下一课子树
}

后根遍历

树的先根遍历序列与这颗树相应的二叉树的中序序列相同。

//后根遍历
void PreOrder(TreeNode *R){
  if(R!=NULL)
      while(R还有下一课子树T)
          PreOrder(T);//先遍历下一课子树
       visit(R);//访问根节点

}

树的层次遍历(用队列实现)(广度优先遍历)

 

 森林的先序遍历:效果等同于对一次对各个树进行先根遍历,也可以转成二叉树

 森林的中序遍历:效果等同于对一次对各个树进行后根遍历,也可以转成二叉树

 二叉排序(查找)树(BST)

左子树基点至<根节点值<柚子树节点值,进行中序遍历得到一个递增的有序序列

复制代码
//在二叉排序树中找值为KEY的节点
typedef struct BSTNode{
    int key;
   struct BSTNode *lchild,*rchile;
}BSTNode,*BSTree;

BSTNode *BST_Search(BSTree T,int key){//BSTree T是根节点的指针
    while(T!==NULL&&key!=T->key){
      if(ley<T->key)T=T->lchild;
      else T=T->rchild;
    }
    return T;
}

//在二叉排序树中找值为KEY的节点(递归实现)
BSTNode *BST_Search(BSTree T,int key){
    if(T==NULL)
        return NULL;
    if(key==T->key)
        return T
    else if(key < T->key)
        return BST_Search(T->lchild,key);
    else
        return BST_Search(T->rchild,key);
}
复制代码

二叉排序树插入

复制代码
//在二叉排序树中插入值为K的节点(递归实现)
int BST_Insert(BTree &T,int k){
    if(T==NULL){  //原树为空,新插入的节点为根节点
        T=(BSTree)malloc(sizeof(BSTNode));
        T->key=k;
        T->lchild=T->rchild=NULL;
        reurn 1;    
    }
    else if(k==T->key) //树中存在相同关键字的节点,插入失败
        return 0;
    else if(k<T->key)
        return BST_Insert(T->lchild,k);
    else (k==T->key)
        return BST_Insert(T->rchild,k);

}
复制代码

二叉排序树的构造

不同的关键字序列(Str[])可能得到同款二叉排序树,也可能不同款。

复制代码
//二叉排序树的构造
void Creat_BST(BSTree &T,int str[],int n){
    T=NULL;  //初始是T为空树
    int  i=0;
    while(i<n){
       BST_Insert(T,str[i]);
       i++;
    }
}
复制代码

 

 平衡二叉树

 

哈夫曼树

节点的权:有某种现实意义的数值

节点带权路径长度:从树的根到该节点的路径长度(经过的边数)与该节点上权值的乘积

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

哈夫曼树:在含有N个带权叶子节点的二叉树中,其中带全路径长度最小(WPL)的二叉树称为哈夫曼树。

 

构造哈夫曼树:

每次选择两个最小的节点让它们成为兄弟,把它们的权值之和作为根节点的权值,把这个根节点的全值和另一个全值最小的结点他们成为兄弟,以此类推。

特点:(1)每个初始节点最终都成为叶子节点,且权值越小的节点到根节点的路径长度越大。

 (2)哈夫曼树的节点总数为2n-1

(3)哈夫曼树不存在度为1的节点

(4)哈夫曼树不唯一,但wpl必然相同且为最优

哈夫曼编码

 

 哈夫曼编码可以用于数据的压缩

 

 根据数列中数据的个数 n,所得到的排列顺序的数目为:C22n/n+1

 

 


posted @   七月猫合  阅读(433)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
点击右上角即可分享
微信分享提示