赫夫曼树的创建

数据结构 专栏收录该内容
12 篇文章 0 订阅

赫夫曼树,即最优二叉树。

给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

构造赫夫曼树:

在这里插入图片描述

  1. 把节点的权值按从小到大的顺序排列。
  2. 从序列中取出前两个(最小),作为孩子节点,求出其父节点的权重并加入到序列。
  3. 重复1,2,直到序列中只剩一个节点。这个节点就是赫夫曼树的根节点。

C++实现:

#include <iostream>
#include <cstring>
using namespace std;
//赫夫曼树
typedef struct Hfmtree {
    char node_val;
    unsigned int weight;
    Hfmtree *lchild, *rchild;
}*pHfmtree;
//队列节点(链表实现)
typedef struct link_node {
    pHfmtree ptree;
    link_node *next;
}Lnode,*pLnode;


//得到权重
int* get_weight( char *inputString );
//初始化链表
void init_link( pLnode &p );
//按照权重,插入链表
void insert_into_linklist ( pLnode &head, pLnode val );
//从链表中取出节点
pHfmtree remove_from_list( pLnode &head );
//生成赫夫曼树
pHfmtree createHfmtree( char *inputString, int *weight, pLnode &head );
//释放内存
void clearTree ( pHfmtree head );
//编码
void encode( pHfmtree root , char *res ,int index );
//解码
void decode( char *code, pHfmtree root );



int main(int argc, char const *argv[])
{
    char input[50];
    cin>>input;
    //得到输入字符对应的权重
    int *weight_res = get_weight( input );

    pLnode head;
    init_link( head );
    //cout << "init_link success\n";

    pHfmtree root = createHfmtree( input, weight_res, head );
    //cout << "CreateHfmtree success\n"<<endl;

    char res[20];//存放编码结果
    //初始化
    res[0] = '0';
    for( int i=1; i<sizeof(res); ++i )
        res[i] = '\0';

    if( NULL==root ){
        cout << "Hfmtree is empty. Fail to encode.\n";
    }
    else{

        cout << "Encode result are:\n";
        encode( root, res , 0 );

        cout << "Decode result are:\n";
        decode( "0101110100110",root );

        clearTree( root );
    }

    delete[] weight_res;
    //cout << "Finally.\n";
    return 0;
}


//得到权重
int* get_weight( char *inputString ) {

    if( !inputString ){
        cout << "input error!\n";
        return NULL;
    }
    int* weight_result = new int[256];
    //初始化权重表
    for( int i=0; i<256; ++i )
        weight_result[i] = 0;

    for( int i=0; inputString[i]!='\0'; ++i ){

        weight_result[ (char)inputString[i] ]++;
    }
    return weight_result;
}

//初始化链表
void init_link( pLnode &p ) {

    p = new Lnode;
    p->ptree = NULL;
    p->next = NULL;
}


//按照权重,插入链表队列
void insert_into_linklist ( pLnode &head, pLnode val ){

    pLnode temp = new Lnode;
    temp->ptree = val->ptree;
    temp->next = NULL;

    //如果队列为空,则直接插在头节点的后面
    if( NULL==head->next ){
        //cout << "list is empty.\n";
        head->next = temp;
    }
    //否则,根据权重比较,p最终指向
    else{

        pLnode p = head;
        while( NULL!=p->next && p->next->ptree->weight<val->ptree->weight )
            p = p->next;
        temp->next = p->next;
        p->next = temp;
    }
    //cout << "insert one.\n";
}

//从队列中取出节点
pHfmtree remove_from_list( pLnode &head ){

    if( NULL==head->next ){
        cout << "List is empty! Fail to remove."<<endl;
        return NULL;
    }

    pHfmtree first = head->next->ptree;

    pLnode todel = head->next;
    head->next = todel->next;
    delete todel;

    //cout << "remove ing\n";
    return first;
}

//生成赫夫曼树
pHfmtree createHfmtree( char *inputString, int *weight_res, pLnode &head ){

    //生成链表
    for( int i=0; i<256; ++i ) {

        if( weight_res[ i ]>0 ) {
            pHfmtree tempTree = new Hfmtree;
            tempTree->node_val = (char)i;
            tempTree->weight = weight_res[ i ];

            //cout << (char)i<<"    "<<weight_res[i]<<endl;

            pLnode tempNode = new Lnode;
            tempNode->ptree = tempTree;

            insert_into_linklist( head, tempNode );
        }
    }
    //cout << "insert success...."<<endl;

    pHfmtree  node_1,node_2, sum_node;
    //当队列中还有至少2个节点时,继续取出,直到只剩一个节点
    while( NULL!=head->next->next ) {

        //每次取出前两个(权重最小),并插入一个新的节点(权重是这两个的权重之和)
        node_1 = remove_from_list( head );
        node_2 = remove_from_list( head );
        sum_node = new Hfmtree;
        sum_node->weight = node_1->weight + node_2->weight;

        sum_node->lchild = node_1;
        sum_node->rchild = node_2;

        pLnode sum_link_node = new Lnode;
        sum_link_node->ptree = sum_node;
        insert_into_linklist( head, sum_link_node );
    }

    //最后,队列中只剩头结点和赫夫曼树的根节点,将其释放,这个队列也就清理了。
    delete head->next;
    delete head;

    return head->next->ptree;//返回赫夫曼树的根
}

//清理赫夫曼树
void clearTree ( pHfmtree head ) {

    if( NULL==head )
        return;
    if( NULL!=head->lchild )
        clearTree( head->lchild );
    if( NULL!=head->rchild )
        clearTree( head->rchild );
    delete head;
}

//编码
void encode( pHfmtree node , char *res, int index ){

    if( NULL==node->lchild&&NULL==node->rchild ){
        cout<< node->node_val <<" :   "<< res <<endl;
        return;
    }

    pHfmtree left = node->lchild;
    if( NULL!=left ){
        res[index] = '0';
        encode( left, res,index+1 );
        res[index] = '\0';
    }


    pHfmtree right = node->rchild;
    if( NULL!=right ){
        res[index] = '1';
        encode( right, res , index+1 );
        res[index] = '\0';
    }
}

//解码
void decode( char *code, pHfmtree root ){

    //如果赫夫曼树只有一个跟节点
    if( NULL==root->lchild&&NULL==root->rchild ) {
        for( int i=0; i<strlen(code); ++i ) {
            cout << root->node_val;
        }
        cout << endl;
        return;
    }
    //有多个节点
    pHfmtree p = root;
    for( int i=0; i<strlen(code); ++i ){

        if( code[i]=='0' )
            p = p->lchild;
        if( NULL==p->lchild&&NULL==p->rchild ) {

            cout << p->node_val;
            p = root;
            continue;
        }

        if( code[i]=='1' )
            p = p->rchild;
        if( NULL==p->lchild&&NULL==p->rchild ) {

            cout << p->node_val;
            p = root;
            continue;
        }
    }
    cout << endl;
}

运行结果:

在这里插入图片描述

  • 3
    点赞
  • 0
    评论
  • 4
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值