zoukankan      html  css  js  c++  java
  • 深入学习二叉树(06)霍夫曼树/哈夫曼编码/最优二叉树

    简介

       哈夫曼树

      构建原理

           树的节点

           初始化树

           对哈夫曼树编码

           完整的代码(C)

    几个名称

    路径: 在一棵树中,一个节点到另一个节点之间的通路,称为路径

    路径的长度:在一条路径中,每经过一个节点,路径的长度加 1 ,如下图中, C 节点的路径长度为 3

    节点的权: 节点出现的频率,每出现一次就+1

    节点的带权路径长度:指从根节点到该节点之间的路径与该节点权的乘积

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

     

    WPL = 7 * 1 + 5 * 2 + 2 * 3 + 4 * 3

    哈夫曼树

    当用 n 个节点(都做叶子节点且都有各自的权值),试图构建一棵树时,如果这颗树的带权路径长度最小,称为这课树为 “最优二叉树”,有时也叫 “赫夫曼树” 、 “哈夫曼树”

    在构建树时,要使的带权路径长度最小,只要遵循一个原则:权重越大的节点离根越近

    构建哈夫曼树的过程

    1.在 n 个权值中选出两个最小的权值,对应的两个节点组成新的二叉树,且新的二叉树的根节点的权值作为左右孩子权值的和

    2.在原有的 n 个权值中删除那 2 个最小的权值,同时将新的权值加入到 n-2 个权值的行列中,依次类推

    3.重复上述,直到创建一棵二叉树为止

    哈夫曼树节点

    key :代表关键字

    weight: key 出现的频率/权重

    left/right :左/右节点

    parent :父节点下标

    *code : 代表该节点的哈夫曼编码 

    typedef struct node{
        int key;
        int weight;
        int left,parent,right;
        int *code;
    }TreeNode;

    哈夫曼树初始化

        int data[2][8] = {{1,2,5,8,4},{1,2,5,8,4}};
    TreeNode* initialTree(int data[2][5],int n){
        TreeNode *root = (TreeNode *)malloc((2*n-1)*sizeof(TreeNode));
        int i; 
        for(i=0;i<n;i++){
            root[i].left = -1;
            root[i].right = -1;
            root[i].parent = -1;
            root[i].code = NULL;
            root[i].key = data[0][i];
            root[i].weight = data[1][i];
        }
        return root;
    } 

    二维数组,第一行保存数据key ,第二行保存权重

    创建哈夫曼树

    //创建树 
    TreeNode* createTree(TreeNode *root,int n){
        int i,j,k1,k2;
        for(i=0;i<n-1;i++){
            for(k1=0;k1<n+i&&root[k1].parent!=-1;k1++);
            for(k2=k1+1;k2<n+i&&root[k2].parent!=-1;k2++);
            for(j=k2;j<n+i;j++){
                if(root[j].parent==-1){
                    if(root[j].weight<=root[k1].weight){
                        k2 = k1;
                        k1 = j;
                    }else if(root[j].weight<=root[k2].weight){
                        k2 = j;
                    }
                }
            }
            root[n+i].left = k1;
            root[n+i].right = k2;
            root[n+i].parent = -1;
            root[n+i].code = NULL;
            root[n+i].key = root[k1].key+root[k2].key;
            root[n+i].weight = root[k1].weight + root[k2].weight;
            root[k1].parent = n+i;
            root[k2].parent = n+i;
        }     
        return root;
    }

    依次从森林中找到最小的2个可用节点,组成新的节点,同时修改这2个节点的parent = -1

    对哈夫曼树编码

    //对哈弗曼树进行编码 
    TreeNode* CreatCode(TreeNode * root,int n){
        printf("哈弗曼树编码:............
    ");
        int i,parent,temp;
        int *p;
        for(i=0;i<n;i++){
            root[i].code=p=(int *)malloc(n*sizeof(int));
            p[0]=0;
            temp=i;
            while(root[temp].parent!=-1){
                parent=root[temp].parent;
                if(root[parent].left==temp){
                    p[++p[0]]=0;
                }else{
                    p[++p[0]]=1;
                }
                temp=parent;
            }
         }
     return root;
    }

    哈夫曼树的 int *code ,指向一个int 数组。数组中每个单元保存 0/1 .如果当前节点在父节点的左边,则保存 0 ,右边则保存 1

    由于0/1 的个数是节点的路径,最大不超过叶子个数 N ,因此数组的长度为 N ,同时第一个节点标记 0/1 的个数

     

     输出

     完整代码

    #include<stdio.h>
    #include<stdlib.h>
    typedef struct node{
        int key;
        int weight;
        int left,parent,right;
        int *code;
    }TreeNode;
    
    //初始化树 
    TreeNode* initialTree(int data[2][5],int n){
        TreeNode *root = (TreeNode *)malloc((2*n-1)*sizeof(TreeNode));
        int i; 
        for(i=0;i<n;i++){
            root[i].left = -1;
            root[i].right = -1;
            root[i].parent = -1;
            root[i].code = NULL;
            root[i].key = data[0][i];
            root[i].weight = data[1][i];
        }
        return root;
    } 
    
    //对哈弗曼树进行编码 
    TreeNode* CreatCode(TreeNode * root,int n){
        printf("哈弗曼树编码:............
    ");
        int i,parent,temp;
        int *p;
        for(i=0;i<n;i++){
            root[i].code=p=(int *)malloc(n*sizeof(int));
            p[0]=0;
            temp=i;
            while(root[temp].parent!=-1){
                parent=root[temp].parent;
                if(root[parent].left==temp){
                    p[++p[0]]=0;
                }else{
                    p[++p[0]]=1;
                }
                temp=parent;
            }
         }
     return root;
    }
     
    
    //创建树 
    TreeNode* createTree(TreeNode *root,int n){
        int i,j,k1,k2;
        for(i=0;i<n-1;i++){
            for(k1=0;k1<n+i&&root[k1].parent!=-1;k1++);
            for(k2=k1+1;k2<n+i&&root[k2].parent!=-1;k2++);
            for(j=k2;j<n+i;j++){
                if(root[j].parent==-1){
                    if(root[j].weight<=root[k1].weight){
                        k2 = k1;
                        k1 = j;
                    }else if(root[j].weight<=root[k2].weight){
                        k2 = j;
                    }
                }
            }
            root[n+i].left = k1;
            root[n+i].right = k2;
            root[n+i].parent = -1;
            root[n+i].code = NULL;
            root[n+i].key = root[k1].key+root[k2].key;
            root[n+i].weight = root[k1].weight + root[k2].weight;
            root[k1].parent = n+i;
            root[k2].parent = n+i;
        }     
        return root;
    }
    
    //输出 
    void print(TreeNode *root,int n){
        int i,j;
        for(i=0;i<n;i++){
            printf("[%d] key:%3d  , left[%d] , parent[%d] , right[%d] ",i,root[i].key,root[i].left,root[i].parent,root[i].right); 
            for(j=root[i].code[0];j>0;j--){
                printf("%d",root[i].code[j]);
            }
            printf("
    ");
        }
    }
    
    int main(void){
        int data[2][5] = {{1,2,5,8,4},{1,2,5,8,4}};
        TreeNode *root = initialTree(data,5);
        root = createTree(root,5);
        root = CreatCode(root,5);
        print(root,5); 
        return 0;
    }
  • 相关阅读:
    wxpython的安装

    拓扑排序
    树,二叉树,森林,三者的转换
    二叉树的遍历
    最短路径
    图的遍历
    图的最小生成树
    哈夫曼树的应用
    哈夫曼树
  • 原文地址:https://www.cnblogs.com/baizhuang/p/11612828.html
Copyright © 2011-2022 走看看