数据结构——树(三)

338 阅读3分钟

这是我参与更文挑战的第18天,活动详情查看:更文挑战

树,森林

树的存储结构

  • 双亲表示法

#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

树,森林,二叉树的转换

树和森林的遍历

树的遍历

  • 先根遍历:若树非空,则先访问根结点,再按从左到右的顺序遍历根结点的每棵子树
  • 后根遍历:若树非空,则先按从左到右的顺序遍历根结点的每棵子树,再访问根结点

森林的遍历

  • 先序遍历森林
    • 访问森林中第一棵树的根节点
    • 先序遍历第一棵树中根节点的子树树林
    • 先序遍历除去第一棵树以后剩余的树构成的森林
  • 中序遍历森林
    • 中序遍历森林中第一棵树的根结点的子树森林
    • 访问第一棵树的根结点
    • 中序遍历除去第一棵树以后剩余的树构成的森林

树的应用——并查集

并查集支持三种操作

Union(S,Root1,Root2);//把集合s中的子集合Root2并入子集合Root1.要求Root1和Root2不相交,否则不执行合并
Find(S,x);//查找集合S中元素x所在的子集合的名字。
Initial(S); //将集合S中每个元素都初始化为只有一个单元素的子集合
#define SIZE 100
int UFSets[SIZE];
void Initial(int S[]){
    for(int i=0;i<size;i++){
        S[i]=-1;
    }
}
int Find(int S[],int x){
    while(S[x]>=0){
        x = S[x];
    }
    return x;
}
void Union(int S[],int Root1,int Root2){
    S[Root2] = Root1;
}

树与二叉树的应用

二叉排序树(BST)

左子树结点值>根结点值>右子树结点值

二叉排序树的非递归查找算法

BSTNode *BST_Search(BiTree T,ElemType key,BSTNode &p){
    p=NULL;
    while(T!=NULL&&key!=T->data){
        p=T;
        if(key<T->data) T=T->lchild;
        else T=T->rchild;
    }
    return T;
}

二叉排序树的插入

int BST_Insert(BiTree &T,KeyType k){
    if(T == NULL){ //原树为空,新插入的为根节点
        T = (BiTree)malloc(sizeof(BSTNode));
        T->key = k;
        T-lchild = T->rchild = NULL;
        return 1;
    }else if(k == T->key)return 0;
    else if(k<T->key)
        return BST_Insert(T->lchild,k);
    else 
        return BST_Insert(T->rchild,k);
}

二叉排序树的构造

void Creat_BST(BiTree &T,KeyType str[],int n){
    T=NULL;
    int i=0;
    while(i<n){
        BST_Insert(T,str[i]);
        i++;
    }
}

二叉排序树的删除

平衡二叉树(AVL)

平衡因子:定义结点左子树与右子树的高度差为该结点的平衡因子

平衡二叉树的插入

  • LL平衡旋转

由于在结点A的左孩子的左子树上插入了新结点

  • RR平衡旋转

由于在结点A的右孩子的右子树上插入了新结点

  • LR平衡旋转

由于在结点A的左孩子的右子树上插入了新结点

  • RL平衡旋转

由于在结点A的右孩子的左子树上插入了新结点

哈夫曼树和哈夫曼编码

在许多实际应用中,树中结点常常被赋予一个表示某种意义的数值,称为该结点的权。从树根结点到任意结点的路径长度(经过的边数)与该结点上权值的乘积,称为该结点的带权路径长度,树中的所有叶结点的带权路径长度之和称为该树的带权路径长度,记为WPL=i=1nwiliWPL = \sum_{i=1}^nw_il_i

在含有n个带全叶子结点的二叉树中,其中带权路径长度最小的二叉树称为哈夫曼树,也称最优二叉树。

哈夫曼树的构造

  • 将n个结点分别作为n棵仅含一个结点的二叉树,构成森林F
  • 构造一个新结点,从F中选取两棵根结点权值最小的树作为新结点的左右子树,并且将新结点的权值置为左右子树上根结点的权值之和。
  • 从F中删除刚才选出的两棵树,同时将新得到的树加入F中。
  • 重复23,直到F剩下最后一颗树

哈夫曼编码