zoukankan      html  css  js  c++  java
  • 树的应用

    1.并查集

      并查集是一种将元素划分到不同集合的数据结构,采用树的双亲表示法来实现。

    /**@数据结构:树->并查集 
     **@作者:9761滴  
     **@存储结构:双亲表示法 
     **/
     
    //本文件中实现了并查集的
        /*
            1.初始化 
            2.查找 
            3.合并 
        */
         
    //等操作
    #include<cstdio>
    #define Max_Size 100
    int father[Max_Size]; 
    //初始化
    void init(){
        for(int i=0;i<Max_Size;i++){
            father[i]=i;
        }
    } 
    //查找元素x所在的集合 
    int findParent(int x){
        int a=x;
        while(x!=father[x]){
            x=father[x];
        }
        //压缩路径
         while(a!=x){
             int z=a;
             a=father[a];
             father[z]=x;
         }
        return x;
    } 
    //合并两个集合
    void unify(int a,int b){
        int fa=findParent(a);
        int fb=findParent(b);
        if(a!=b)
            father[fa]=fb;
    } 

    2.二叉排序树BST  ->  AVL树

      定义:首先它是一颗二叉树,其次每个结点的左子树上的结点要小于该结点的值,右子树上结点的值要大于该结点的值。

      性质:由于二叉排序树结点之间大小关系的特性,使得在二叉排序树中查找的效率会比较高(O(Logn)),但是如果对一棵BST进行一定次数的插入删除操作之后,它就会变成一个渐线性结构,从而使得查找效率降低(O(N)),因此插入删除结点之后需要保持二叉排序树的平衡,从而出现了AVL(平衡二叉树)树。

      AVL树的实现:

    /**@数据结构:树->AVL树 
     **@作者:9761滴  
     **@存储结构:链表 
     **/
     
    //本文件中实现了AVL树的
        /*
            1.查找
            2.插入
            3.创建 
        */
         
    //等操作
    #include<cstdio>
    #include<stdlib.h>
    typedef int ElementType;
    typedef struct node{
        int height;
        ElementType data;
        node* lchild;
        node* rchild;
    }node,AVLTree;
    //生成一个新的结点 
    node* newNode(ElementType x){
        node* p=(node*)malloc(sizeof(node));
        if(p==NULL)
            return NULL;
        p->data=x;
        p->height=1;
        p->lchild=NULL;
        p->rchild=NULL;
        return p;
    }
    //返回以root为根节点的子树的高度 
    int getHeight(node* root){
        if(root==NULL)
            return 0;
        return root->height;
    } 
    //计算root的平衡因子
    int getBalanceFactor(node* root){
        return getHeight(root->lchild)-getHeight(root->rchild);
    } 
    int max(int a,int b){
        if(a>b)
            return a;
        else
            return b;
    }
    //跟新以root为根节点的子树的高度
    void updateHeight(node* root){
        root->height=max(getHeight(root->lchild),getHeight(root->rchild))+1;
    }
    //查找AVL树中数据域为x的结点 
    node* search(node* root,ElementType x){
        if(root==NULL)
            return NULL;
        if(root->data==x)
            return root;
        if(x>root->data) 
            return search(root->rchild,x);
        else
            return search(root->lchild,x);
    }
    //左旋操作
    void LeftRotation(node* &root){
        node* temp=root->rchild;
        root->rchild=temp->lchild;
        temp->lchild=root;
        updateHeight(root);
        updateHeight(temp);
        root=temp;
    } 
    //右旋操作
    void RightRotation(node* &root){
        node* temp=root->lchild;
        root->lchild=temp->rchild;
        temp->rchild=root;
        updateHeight(root);
        updateHeight(temp);
        root=temp; 
    } 
    //往AVL树中插入一个数据域为x的新结点,并保持AVL树特性
    bool insert(node* &root,ElementType x){
        node* p=newNode(x);
        if(p==NULL)
            return false;
        if(root==NULL){
            root=p;
            return true;
        }
        if(x>root->data){
            insert(root->rchild,x);
            updateHeight(root);
            if(getBalanceFactor(root)==-2){
                if(getBalanceFactor(root->rchild)==-1){
                    LeftRotation(root);
                }
                else if(getBalanceFactor(root->rchild)==1){
                    RightRotation(root->rchild);
                    LeftRotation(root);
                }
            }
        }
        else{
            insert(root->lchild,x);
            updateHeight(root);
            if(getBalanceFactor(root)==2){
                if(getBalanceFactor(root->lchild)==1){
                    RightRotation(root);
                }
                else if(getBalanceFactor(root->lchild)==-1){
                    LeftRotation(root->lchild);
                    RightRotation(root);
                }
            }
        }
    }
    //创建AVL树
    node* Create(ElementType data[],int n){
        node* root=NULL;
        for(int i=0;i<n;i++){
            insert(root,data[i]);
        }
        return root;
    } 
    int main(){
        return 0;
    }

    3.哈夫曼树

      首先搞清楚几个概念:

        权:在很多应用中,树中结点常常被赋予一个表示某种意义的数值,称为该结点的权。

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

        树的带权路径长度WPL:树中所有叶结点(注意是叶结点哦)的带权路径长度之和称为该树的带权路径长度。

        哈夫曼树:含有n个带权叶节点的二叉树中,WPL最小的二叉树称为哈夫曼树。

      将n个权值分别为w1,w2...wn的结点构造成一棵哈夫曼树的方法:

        1.将这n个结点分别作为n棵仅含有一个结点的二叉树,构成森林F

        2.构造一个新的结点,从F中选取两棵根节点权值最小的树作为新结点的左、右孩子,并且将新结点的权值置为左右子树上根节点的权值之和

        3.从F中删除刚才选出的两棵树,同时将新得到的树加入F中

        4.重复步骤 2、3, 直到F中只剩下一棵树。

      哈夫曼树性质:

        每个初始结点最终都称为叶节点,且权值越小的结点到根节点的路径长度越大

        构造过程中一共新建了n-1个结点,因此哈夫曼树的结点总数为2n-1

        每次构造都选择2棵树作为新结点的孩子,因此哈夫曼树中不存在度为1的结点

        n个权值结点构造的哈夫曼树不唯一

    4.哈夫曼编码

      固定长度编码:在字符编码中,常用长度相等的二进制位表示每个字符,这种编码方式称为固定长度编码。

      可变长度编码:用不等长的二进制位表示不同字符

      哈夫曼编码:可变长度编码的一种,用于数据压缩。

      前缀编码:没有一个编码是另一个编码的前缀,这样的编码叫做前缀编码。如对a,b,c编码,a=0,b=101,c=100, 那么串码就00101100就可以唯一的识别为aabc,而不产生歧义

      哈夫曼编码过程:

        将每个字符当作一个独立的结点,其权值为它出现的频度,构造哈夫曼树。

        构造好哈夫曼树之后,所有字符都出现在了叶节点中,可以将字符的编码解释为从根到该节点字符的路径上边标记的序列,其中0表示“转向左孩子”的边,1表示转向有孩子的边。

  • 相关阅读:
    codeforces#1343E. Weights Distributing(bfs)
    Windows编程调试技巧-控制台调试
    Windos编程中窗口的尺寸cxClient和cyClient初始化的问题
    windows下pip安装python模块时报错总结
    .md即markdown文件的基本常用编写语法(图文并茂)
    如何转载cnsd的博客
    codeforces#1332F. Independent Set(树上dp)
    codeforces#1333 E. Road to 1600(构造)
    codeforces#1329C
    codeforces#1293E. Xenon's Attack on the Gangs(树上dp)
  • 原文地址:https://www.cnblogs.com/foodie-nils/p/13986190.html
Copyright © 2011-2022 走看看