赫夫曼树编码解码实例(C)

//HuffmanTree.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define OVERFLOW -1

typedef struct{
    char data;           //节点所存字符
    unsigned int weight;    //节点权重
    unsigned int parent,lchild,rchild;
}HTNode, *HuffmanTree;     //动态分配数组存储赫夫曼树
typedef char** HuffmanCode;//动态分配数组存储赫夫曼编码表

//从T的1到n个节点中找出没有结合(即parent=0)的节点中权重weight最小的两个节点的下标;用l,r带回;
void Select(HuffmanTree T,int n,int&l,int&r)
{
    HuffmanTree p=T+1;int a=0,b=0;
    for(int i=1;i<=n;++i,++p){
        if(!p->parent){//找出双亲节点为空的节点;
            if(!a){l=i;a=1;}
            else if(!b){r=i;b=1;}
            else if(p->weight<(T+l)->weight||p->weight<(T+r)->weight){
                if((T+l)->weight<=(T+r)->weight)r=i;
                else l=i;
            }
        }
    }
}

//w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC
//HT为赫夫曼树,HC为赫夫曼编码,w为权重数组,n为w长度
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, char* c, int n){

    if(n<=1) return;
    int m = 2*n-1;
    HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode)); //0号单元未用
    HuffmanTree p;
    int i;
    for(p=HT+1,i=1; i<=n; ++i,++p,++w) *p = {c[i-1],*w,0,0,0};
    for(i=n+1; i<=m; ++i, ++p)         *p = {0,0,0,0,0};

    for(i=n+1; i<=m; ++i){ //建赫夫曼树
        //在HT[1..i-1]选择parent为0且weight最小的两个节点,其序号分别为s1和s2。
        int 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;
    }
    //---从叶子到根逆向求每个字符的赫夫曼编码---
    HC = (HuffmanCode)malloc((n+1)*sizeof(char *)); //分配n个字符编码的头指针向量
    char* cd = (char *)malloc(n*sizeof(char));          //分配求编码的工作空间
    cd[n-1] = ‘\0‘;    //编码结束符
    for(i=1; i<=n; ++i){
        //逐个字符求赫夫曼编码
        int start = n-1;  //编码结束符位置
        int c,f;
        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);  //释放工作空间
}

//输出赫夫曼编码
//HC为赫夫曼编码,w为权重数组,n为w长度,c为字符数组
void PrintHuffmanCode(HuffmanCode HC,int* w,char* c,int n)
{
    char *p;
    int i;
    for(i=1;i<=n;++i){
        printf("字符:%c,权重:%3d,编码:", c[i-1], w[i-1]);
        p=HC[i];
        printf("%s\n",p);
    }
}

//返回某字符的赫夫曼编码
//HC为赫夫曼编码,c为字符数组,n为c长度,ch为要编码的字符
char* EnCode(HuffmanCode HC, char* c, char ch, int n)
{
    int i;
    for(i=0;i<n;++i){
        if(c[i]==ch){
            char *p = HC[i+1];
            return p;
        }
    }
}

//解码
//s为待解码字符串,HT为赫夫曼树
char* DeCode(const char*s, HuffmanTree HT){
    int i; HuffmanTree p=HT;
    static char result[500];
    int j=0;

    //寻找根节点
    while(p->parent!=0) p++;
    const HuffmanTree root = p;

    for(i=0; i<strlen(s); ++i){
        if(s[i]==‘0‘){
            if(p->lchild!=0){
                p=HT+p->lchild;
            }
        }
        else if(s[i]==‘1‘){
            if(p->rchild!=0){
                p=HT+p->rchild;
            }
        }
        if(p->lchild==0&&p->rchild==0){
            result[j]=p->data;++j;
            p = root;
        }
    }
    result[j] = ‘\0‘;
    return result;
}
#include "HuffmanTree.h"
#include <stdio.h>

int main(void){

    char s[500];

READ:
    printf("请输入一段话:");
    gets(s);

    int i=0,w[1000]={0},*word; char *c; //word记录权值,c记录字符

    while(s[i]!=‘\0‘){ //出现次数计数
        w[s[i]+500]++;
        ++i;
    }

    int j=0; word = (int*)malloc(sizeof(int));
             c = (char*)malloc(sizeof(char));
    for(i=-500;i<500;++i){
        if(w[i+500]!=0){
            word = (int*)realloc(word,(j+1)*sizeof(int));
            c = (char*)realloc(c,(j+1)*sizeof(char));
            word[j] = w[i+500];
            c[j] = i;
            ++j;
        }
    }

    const int len = j; //字符数组、权重数组长度

    if(len==1){
        printf("请输入大于1种字符!\n");
        goto READ;
    }

    HuffmanCode HC;HuffmanTree HT;
    HuffmanCoding(HT,HC,word,c,len);
    PrintHuffmanCode(HC,word,c,len);

    i=0;
    printf("赫夫曼编码后结果为:");
    char code[1000]={‘\0‘};
    while(s[i]!=‘\0‘){
        strcat(code,EnCode(HC,c,s[i],len));
        ++i;
    }
    printf("%s\n",code);

    printf("解码结果为:%s",DeCode(code,HT));
    printf("\n");
    getchar();
    return 0;
}

运行截图:

时间: 2024-10-10 00:55:02

赫夫曼树编码解码实例(C)的相关文章

赫夫曼树编码的表示与实现--自己写数据结构

头文件huffman.h #ifndef _HUFFMAN_H_ #define _HUFFMAN_H_ #define MAX_WEIGHT 10000 typedef struct _HTNode { int weight; int parent,lchild,rchild; char data; }HTNode,*pHTNode; typedef char** huffmancode; void select_min_weight(HTNode* btree,int mn,int* s1,

基础数据结构-二叉树-赫夫曼树的解码(详解)

本篇是上一篇赫夫曼树构建与编码的后续,稍微详细讲一下解码的算法. Huffman解码算法流程: 1.定义指针p指向赫夫曼树结点,实际是记录结点数组的下标: 2.定义指针i指向编码串,定义ch逐个取编码串的字符: 3.初始化:读入编码串,设置p指向根结点,i为0: 4.执行以下循环: a)取编码串的第i个字符放入ch: b)如果ch是字符0,表示往左孩子移动,则p跳转到右孩子: c)如果ch是字符1,表示往右孩子移动,则p跳转到右孩子: d)如果ch非0非1,表示编码串有错误,输出error表示解

看数据结构写代码(32) 赫夫曼树编码以及译码

杂谈:最近有点慵懒,不好不好.好几天都没写代码,原本准备上星期完结 树 这一章节的.现在 又耽误了.哎.要抓紧时间啊. 下面直接上代码: 可以到我的网盘下载源代码,或者 直接拷贝下面的源代码 运行 网盘地址:点击打开链接 // HuffmanTree.cpp : 定义控制台应用程序的入口点. //哈弗曼编码,译码 #include "stdafx.h" #include <stdlib.h> #include <cstring> enum E_State { E

赫夫曼树编码

在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN) 树和哈夫曼编码.哈夫曼编码是哈夫曼树的一个应用.哈夫曼编码应用广泛,如 JPEG中就应用了哈夫曼编码. 首先介绍什么是哈夫曼树.哈夫曼树又称最优二叉树, 是一种带权路径长度最短的二叉树.所谓树的带权路径长度,就是树中所有的叶结点 的权值乘上其到根结点的 路径长度(若根结点为0层,叶结点到根结点的路径长度 为叶结点的层数).树的带权路径长度记为WPL= (W1*L1+W2*L2+W3*L3+...+Wn*Ln) ,

从头结点开始编码的赫夫曼树

#include<stdio.h> #include<string.h> #include<stdlib.h> #ifndef MACRO_//宏 #define MACRO_ #define OK 1 #define FALSE 0 #define ERROR 0 #define TURE 1 #define OVERFLOW -2 #define INFEASIBLE -1 typedef int Status; typedef int BOOL; #endif /

赫夫曼树的构建、编码、译码解析

当你開始看这篇博文的时候.我相信你对树及二叉树的基本概念已有所了解.我在这里就不再赘述. 我们主要对赫 夫曼树的特点.构建.编码.译码做一个具体的介绍,并附有代码,全部函数代码都通过了測试.我不保证全部代码是最优的(毕竟是我一个人苦思冥想出来的,我相信在大家的集思广益之下还有优化的空间),但我保证全部代码是正确的. 一.赫夫曼树的特点 赫夫曼树又称作最优二叉树,是一类带权路径长度最短的树. 首先给出路径和路径长度的概念.从树中一个节点到 还有一个节点之间的分支构成这两个节点之间的路径.路径上的分

20172303 2018-2019-1《程序设计与数据结构》哈夫曼树编码与解码

20172303 2018-2019-1<程序设计与数据结构>哈夫曼树编码与解码 哈夫曼树简介 定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近. 带权路径长度(Weighted Path Length of Tree,简记为WPL) 结点的权:在一些应用中,赋予树中结点的一个有某种意义的实数. 结点的带权路径长度:结点到树根之间的路径长度与

赫夫曼树JAVA实现及分析

一,介绍 1)构造赫夫曼树的算法是一个贪心算法,贪心的地方在于:总是选取当前频率(权值)最低的两个结点来进行合并,构造新结点. 2)使用最小堆来选取频率最小的节点,有助于提高算法效率,因为要选频率最低的,要么用排序,要么用堆.用堆的话,出堆的复杂度为O(logN),而向堆中插入一个元素的平均时间复杂度为O(1),在构建赫夫曼树的过程中,新生成的结点需要插入到原来的队列中,故用堆来维持这种顺序比排序算法要高效地多. 二,赫夫曼算法分析 ①用到的数据结构分析 首先需要构造一棵赫夫曼树,因此需要二叉链

13.赫夫曼树及其应用

一.赫夫曼树定义与原理 1.路径长度:从树中一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称作路径的长度; 2.树的路径长度:即从树根到每一结点的路径长度之和; 3.结点的带权的路径长度:即从该结点从到树根之间的路径长度与结点上权的乘积; 4.树的带权路径长度:为树中所有叶子结点的带权路径长度之和; 5.赫夫曼树定义:假设有n个权值{w1,w2,....,wn},构造一颗有n个叶子结点的二叉树,每个叶子结点带权wk,每个叶子的路径长度为lk,则其中带权路径长度WPL最小的