数据结构--哈弗曼树

// Huffman.cpp : Defines the entry point for the console application.
/*-----CODE FOR FUN---------------
-------CREATED BY Dream_Whui------
-------2015-2-8-------------------*/

#include "stdafx.h"
#include <iostream>
using namespace std;

typedef struct//定义哈弗曼树的结构
{
    unsigned int weight;//权重
    unsigned int parent, lchild, rchild;//双亲结点,做孩子,右孩子
}HTNode, *HuffmanTree;

typedef char** HuffmanCode;

void Select(HuffmanTree HT, int n, int &s1, int &s2)//选出哈弗曼树HT中权值最小,双亲结点序号为0,的两个结点,序号赋值给s1,s2
{
    int i,f1,f2;
    unsigned int k = UINT_MAX;
    for(i=1; i<=n; i++)//找到权值最小的结点
    {
        if(HT[i].parent == 0)
            if(HT[i].weight < k)
            {
                k = HT[i].weight;
                f1 = i;
            }
    }
    HT[f1].parent = 1;//双亲结点设为1,做为标记(不会再被选到)
    s1 = f1;

    k = UINT_MAX;
    for(i=1; i<=n; i++)//找到权值第二小的结点
    {
        if(HT[i].parent == 0)
            if(HT[i].weight < k)
            {
                k = HT[i].weight;
                f2 = i;
            }
    }
    HT[f2].parent = 1;
    s2 = f2;

    int temp;
    if(s1>s2)
    {
        temp = s1;
        s1 = s2;
        s2 = temp;
    }
}

void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n)
{    //构造哈弗曼树HT,哈弗曼树编码HC,w为结点的权重值,n个字符(即n个结点)
    if(n<=1)
        return ;
    int m = 2*n-1;//n个字符,需要构造2n-1个结点
    HT = (HuffmanTree)malloc( (m+1)*sizeof(HTNode) );
    HuffmanTree  p;
    int i;
    int s1,s2;
    for(p=HT+1, i=1; i<=n; i++, p++, w++)//n个字符(结点)初始化
    {
        //*p = {*w,0,0,0};
        p->weight = *w;
        p->lchild = 0;
        p->rchild = 0;
        p->parent = 0;
    }
    for(; i<=m; i++, p++)//后面结点初始化
    {
        p->weight = 0;
        p->lchild = 0;
        p->rchild = 0;
        p->parent = 0;
    }
    for(i=n+1; i<=m; i++)// 建赫夫曼树   
    {                    // 在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
        Select(HT,i-1,s1,s2);
        HT[s1].parent = i;
        HT[s2].parent = i;
        HT[i].lchild = s1;
        HT[i].rchild = s2;
        HT[i].weight = HT[s1].weight + HT[s2].weight;
        //cout<<i<<":"<<HT[s1].weight<<" "<<HT[s2].weight<<endl;
    }
#define HC_1
#ifdef HC_1      //从叶子到根逆向求每个字符的哈弗曼编码
    cout<<"从叶子到根"<<endl;
    HC = (HuffmanCode)malloc( (n+1)*sizeof(char*) );
    char *cd = (char*)malloc( n*sizeof(char));
    cd[n-1] = '\0';//编码结束符
    int start, c, f;
    for(i=1; i<=n; i++)//逐个字符求哈弗曼编码
    {
        start = n-1;//编码结束位置
        for(c=i, f=HT[i].parent; f!=0; c=f, f=HT[f].parent)//从叶子到根逆向求编码
        {
            if(HT[f].lchild == c)
                cd[--start] = '0';
            else
                cd[--start] = '1';
        }
        HC[i] = (char*)malloc( (n-start)*sizeof(char) );//为第i个字符编码分配空间
        strcpy(HC[i],&cd[start]);//从cd复制编码(串)到HC
    }
    free(cd);
#endif

//#define HC_2
#ifdef HC_2
    cout<<"从根到叶子"<<endl;
    HC = (HuffmanCode)malloc( (n+1)*sizeof(char*) );
    char *cd = (char*)malloc( n*sizeof(char));
    int num=m;
    int cdlen = 0;
    for(int i=1; i<=m; i++)
        HT[i].weight = 0;//遍历哈弗曼树时用作结点状态标志
    while(num)
    {
        if(HT[num].weight==0)//向左
        {
            HT[num].weight=1;
            if(HT[num].lchild != 0)
            {
                num = HT[num].lchild;
                cd[cdlen++] = '0';
            }
            else if(HT[num].rchild == 0)
            {
                HC[num] = (char*)malloc( (cdlen+1)*sizeof(char) );
                cd[cdlen] = '\0';
                strcpy(HC[num],cd);
            }
        }
        else if(HT[num].weight == 1)//向右
        {
            HT[num].weight = 2;
            if(HT[num].rchild != 0)
            {
                num = HT[num].rchild;
                cd[cdlen++] = '1';
            }
        }
        else//左右都遍历完后,退回到双亲结点
        {
            HT[num].weight = 0;
            num = HT[num].parent;
            --cdlen;
        }
    }
#endif
}

int main(int argc, char* argv[])
{
    HuffmanTree T;
    HuffmanCode HC;
    cout<<"输入字符个数n(0~20):";
    int n;
    cin>>n;
    int *weight = (int*)malloc( n*sizeof(int) );
    int i;
    for(i=0; i<n; i++)
    {
        cout<<"输入第"<<i+1<<"个字符的权重值:";
        cin>>weight[i];
    }
    HuffmanCoding(T,HC,weight,n);
    cout<<"哈弗曼编码"<<endl;
    for(i=1; i<=n; i++)
    {
        cout<<"第"<<i<<"个字符编码:"<<HC[i]<<endl;
    }
    cout<<endl;
    free(weight);
    return 0;
}

    原文作者:哈夫曼树
    原文地址: https://blog.csdn.net/dream_whui/article/details/44020803
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞