赫夫曼樹以及赫夫曼編碼

1.概念

赫夫曼樹

赫夫曼樹,又稱最優樹,是一類帶權路徑長度最短的樹。
首先給出路徑和路徑長度的概念。從樹中一個節點到另一個節點之間的分支構成這兩個節點之間的路徑,路徑上的分支數目叫做路徑長度樹的路徑長度是從樹根到每一節點的路徑長度之和。
考慮上帶權的節點。節點的帶權路徑長度爲從該結點到樹根之間的路徑長度與節點上權的乘積。樹的帶權路徑長度爲樹中所有葉子節點的帶權路徑長度之和,通常記作WPL=nk=0 wklk
舉個例子,如下圖
這裏寫圖片描述
WPL=7*2+5*2+2*2+4*2=36
上圖中的樹不是赫夫曼樹,由7,5,2,4構成的赫夫曼樹如圖所示
這裏寫圖片描述
WPL=7*1+5*2+2*3+4*3

赫夫曼編碼

按照上面的赫夫曼樹,我們將在父節點左邊的路徑用0表示,右邊的用1表示。由此得到
A (0)
B (10)
C (110)
D (111)
這樣的二進制編碼我們稱爲赫夫曼編碼。

赫夫曼樹算法分析

1.根據給定的n個權值構成n棵二叉樹的合集F。(每棵二叉樹的左右子樹爲空)
2.在F中選取兩棵根結點的權值最小的樹作爲左右子樹構造一棵新的二叉樹,且置新的二叉樹的根結點的權值爲其左右子樹上根結點的權值之和。
3.在F中刪除這兩棵樹,同時將新得到的二叉樹加入F中。
4.重複步驟2和步驟3,直到F中只剩一棵樹爲指。這棵樹便是赫夫曼樹。

代碼

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<limits.h>

typedef struct Tree              //創建一個樹結構
{
    int weight;   //權值
    int left;     //左子樹
    int right;    //右子數
    int flag;     //標記,用來鑑定是否使用
    int parent;   //父節點
}HaffTree;

void CreateHaffTree(int* weight,int n,HaffTree* pHaffTree)    //創建赫夫曼樹
{
    int i,j,min1,min2,x1,x2;   //min1,min2分別爲最小值和次最小值,x1,x2分別爲最小值和次最小值對應下標
    for(i=0;i<2*n-1;i++)       //初始化HaffTree
    {
        if(i<n)
            pHaffTree[i].weight=weight[i];
        else
            pHaffTree[i].weight=0;
        pHaffTree[i].left=0;
        pHaffTree[i].right=0;
        pHaffTree[i].flag=0;    //未使用的初始化爲0
        pHaffTree[i].parent=0;
    }
    for(i=0;i<n-1;++i)
    {
        min1=min2=INT_MAX;    //INT_MAX對應頭文件爲limits.h
        x1=x2=0;
        for(j=0;j<n+i;++j)
        {
            if(pHaffTree[j].weight<min1&&pHaffTree[j].flag==0)  
            {
                min2=min1;
                x2=x1;
                min1=pHaffTree[j].weight;
                                x1=j;
            }
            else if(pHaffTree[j].weight<min2&&pHaffTree[j].flag==0)
            {
                min2=pHaffTree[j].weight;
                x2=j;
            }
        }
        pHaffTree[x1].flag=1;
        pHaffTree[x2].flag=1;
        pHaffTree[x1].parent=pHaffTree[x2].parent=n+i;
        pHaffTree[n+i].weight=min1+min2;
        pHaffTree[n+i].left=x1;
        pHaffTree[n+i].right=x2;
    }
}
void HaffCode(HaffTree* pHaffTree,int n,char*** code)   //根據赫夫曼樹求赫夫曼碼,由葉子到根求赫夫曼編碼,因此start--
{
    int i;
    char ch[20]="";
    int start;
    int parent;
    int child;
    int len;
    *code=(char**)malloc(sizeof(char**)*n);
    for(i=0;i<n;++i)
    {
        parent=pHaffTree[i].parent;
        child=i;
        start=18;
        while(parent!=0)
        {
            if(pHaffTree[parent].left==child)
                ch[start--]='0';
            else
                ch[start--]='1';
            child=parent;
            parent=pHaffTree[parent].parent;
        }
        len=strlen(ch+start+1)+1;
        (*code)[i]=(char*)malloc(len);
        strcpy((*code)[i],ch+start+1);
    }

}

void main()
{
    int weight[]={7,5,2,4};
    int n=sizeof(weight)/sizeof(int);
    HaffTree* pHaffTree=(HaffTree*)malloc(sizeof(HaffTree)*(2*n-1));  //有n個葉子節點,因此總節點個數爲2n-1
    CreateHaffTree(weight,n,pHaffTree);
    char** code=NULL;
    HaffCode(pHaffTree,n,&code);
    for(int i=0;i<n;++i)
    {
        printf("%d ",weight[i]);
        puts(code[i]);
    }
}

看看結果吧
這裏寫圖片描述
和根據赫夫曼樹中推出的結果一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章