1、描述

Huffman编码,将字符串利用C++编码输出该字符串的Huffman编码。

Huffman树是一种特殊结构的二叉树,由Huffman树设计的二进制前缀编码,也称为Huffman编码在通信领域有着广泛的应用。在word2vec模型中,在构建层次Softmax的过程中,也使用到了Huffman树的知识。

在通信中,需要将传输的文字转换成二进制的字符串,假设传输的报文为:“AFTERDATAEARAREARTAREA”,现在需要对该报文进行编码。

2、实现过程

  • 统计字符串中出现字符的频率
  • 列出字符串的Huffman树

3、实现代码

#include<iostream>
#include<string>
using namespace std;

struct huffTree
{
    int parent;//父亲
    int lchild;//左孩子
    int rchild;//右孩子
    int weight;//权重
    string flag;//标志
};

struct Lowest_Node//第0级节点的字符与频度
{
    char ch;
    int ch_num;
};
//确定每个字符的huffman编码,输出参数为a、b
void coding(int length, huffTree tree[], int n, int &a, int &b)
{
    int i;
    int r, s;
    r = s = length;//节点个数最大不会超过字符串的长度
    for (i = 0; i < n; i++)
    {
        if ((tree[i].weight < r) && (tree[i].parent == -1))
        {
            r = tree[i].weight;
            a = i;
        }
    }
    for (i = 0; i < n; i++)
    {
        if ((tree[i].weight < s) && (i != a) && (tree[i].parent == -1))
        {
            s = tree[i].weight;
            b = i;
        }
    }
}

//计算每个字符出现的频度并排序
void frequency(string str)
{
    int length = str.length();//长度
    // 开辟结构体数组
    Lowest_Node *node = new Lowest_Node[length];//声明最0级节点

    int i, j;//循环因子
    for (i = 0; i < length; i++)
        node[i].ch_num = 0;//初始化频度

    int char_type_num = 0;//初始为0种字符
    for (i = 0; i < length; i++)//循环整个字符串
    {
        for (j = 0; j < char_type_num; j++)
            if (str[i] == node[j].ch || // 判断字符频率结构中,这个字符是否相等
                (node[j].ch >= 'a'&&node[j].ch <= 'z'&& //判断是否为字符
                    str[i] + 32 == node[j].ch  //判断字符串的大写是否与字符频率结构中字符相等
                    ))
                break;//该字符没有出现过,跳出循环

        if (j < char_type_num)//该字符重复出现,对应的记数器加1
            node[j].ch_num++;
        else//新出现的字符,记录到ch[j]中,对应计数器加1
        {
            if (str[i] >= 'A'&&str[i] <= 'Z')
                node[j].ch = str[i] + 32;   //字符转换为大写存储起来
            else
                node[j].ch = str[i];
            node[j].ch_num++;
            char_type_num++;//字符的种类数加1
        }
    }

    //按频度从大到小排序
    for (i = 0; i < char_type_num; i++) //字符长度
    {
        for (j = 0; j < char_type_num-1; j++)
        {

            //判断为字符就往下走,否则就不往下
            if (node[j].ch >= 'a'&&node[j].ch <= 'z')
            {
                if (node[j].ch_num < node[j + 1].ch_num)//如果前一个小于后一个,交换
                {
                    int temp;//临时频度
                    char ch_temp;//临时字符
                    temp = node[j].ch_num;
                    ch_temp = node[j].ch;
                    node[j].ch_num = node[j + 1].ch_num;
                    node[j].ch = node[j + 1].ch;
                    node[j + 1].ch_num = temp;
                    node[j + 1].ch = ch_temp;

                }
            }
        }
    }

    for (i = 0; i < char_type_num; i++)//打印字符频度
        cout << "字符" << node[i].ch << "出现了" << node[i].ch_num << "次" << endl;

    huffTree *huff = new huffTree[2 * char_type_num - 1];//此变量的声明需位于确定char_type_num值后
    huffTree temp;
    string *code = new string[2 * char_type_num - 1];//存放各个字符的编码

    for (i = 0; i < 2 * char_type_num - 1; i++)//节点初始化
    {
        huff[i].lchild = -1;
        huff[i].parent = -1;
        huff[i].rchild = -1;
        huff[i].flag = -1;
    }
    for (j = 0; j < char_type_num; j++)//将排序后的第0级节点权重赋给树节点
    {
        huff[j].weight = node[j].ch_num;
    }
    int min1, min2;
    for (int k = char_type_num; k < 2 * char_type_num - 1; k++)//赋值0级之上的节点
    {
        coding(length, huff, k, min1, min2);
        huff[min1].parent = k;
        huff[min2].parent = k;
        huff[min1].flag = "0";
        huff[min2].flag = "1";
        huff[k].lchild = min1;
        huff[k].rchild = min2;
        huff[k].weight = huff[min1].weight + huff[min2].weight;
    }

    for (i = 0; i < char_type_num; i++)
    {
        temp = huff[i];
        while (1)
        {
            code[i] = temp.flag + code[i];
            temp = huff[temp.parent];
            if (temp.parent == -1)
                break;
        }
    }
    cout << "字符串的每个字符huffman编码为:" << endl;
    for (i = 0; i < char_type_num; i++)
        cout << node[i].ch << "  " << code[i] << endl;

    cout << "整个字符串的huffman编码为:" << endl;
    for (i = 0; i < length; i++)
    {
        for (j = 0; j < char_type_num; j++)
        {
            if (str[i] == node[j].ch)
                cout << code[j];
        }
    }

    //释放内存
    delete[] node;
    node = NULL;
    delete[] huff;
    huff = NULL;
    delete[] code;
    code = NULL;
}

int main()
{
    int length = 0;//字符串长度
    string str; //目标字符串
    cout << "请输入一个字符串:";
    cin >> str;
    frequency(str);//求各个元素的频度
    printf("\n");
    system("pause");
    return 0;
}

4、参考

数据结构和算法——Huffman树和Huffman编码
http://blog.csdn.net/google19890102/article/details/54848262

【算法】Huffman编码(数据结构+算法)的更多相关文章

  1. 贪心算法-Huffman编码

    伪代码: 例子:

  2. 《数据结构与算法分析:C语言描述》复习——第十章“算法设计技巧”——Huffman编码

    2014.07.06 16:47 简介: 给定一段有固定符号集合S构成的文本T,集合S中总共有n种符号.如果对于每种符号,使用一种不同的由‘0’和‘1’构成的位字符串来代替,比如: ‘a’->‘ ...

  3. 【uva 10954】Add All(算法效率--Huffman编码+优先队列)

    题意:有N个数,每次选2个数合并为1个数,操作的开销就是这个新的数.直到只剩下1个数,问最小总开销. 解法:合并的操作可以转化为二叉树上的操作[建模],每次选两棵根树合并成一棵新树,新树的根权值等于两 ...

  4. [C++]哈夫曼树(最优满二叉树) / 哈夫曼编码(贪心算法)

    一 哈夫曼树 1.1 基本概念 算法思想 贪心算法(以局部最优,谋求全局最优) 适用范围 1 [(约束)可行]:它必须满足问题的约束 2 [局部最优]它是当前步骤中所有可行选择中最佳的局部选择 3 [ ...

  5. 数据结构+算法面试100题~~~摘自CSDN

    数据结构+算法面试100题~~~摘自CSDN,作者July 1.把二元查找树转变成排序的双向链表(树) 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点,只调 ...

  6. 1.数据结构&算法的引言+时间复杂度

    一.什么是计算机科学? 首先明确的一点就是计算机科学不仅仅是对计算机的研究,虽然计算机在科学发展的过程中发挥了重大的作用,但是它只是一个工具,一个没有灵魂的工具而已.所谓的计算机科学实际上是对问题.解 ...

  7. 数据结构&算法的引言+时间复杂度

    一.什么是计算机科学? 首先明确的一点就是计算机科学不仅仅是对计算机的研究,虽然计算机在科学发展的过程中发挥了重大的作用,但是它只是一个工具,一个没有灵魂的工具而已.所谓的计算机科学实际上是对问题.解 ...

  8. 一.数据结构&算法的引言+时间复杂度

    目录(contents): 1.什么是计算机科学?什么是算法? 2.如何形象化的理解算法? 3.什么是算法分析? 4.时间复杂度 5.数据结构 6.总结算法和数据结构之间的关联 一.什么是计算机科学? ...

  9. [算法]Huffman树(哈夫曼树)

    目录 一.关于Huffman树 二.具体实现 例1:P1090 合并果子 例2:P2168 [NOI2015]荷马史诗 一.关于Huffman树 Huffman树(哈夫曼树)可以解决下述问题: 一颗\ ...

随机推荐

  1. # linux读书笔记(3章)

    linux读书笔记(3章) 标签(空格分隔): 20135328陈都 第三章 进程管理 3.1 进程 进程就是处于执行期的程序(目标码存放在某种存储介质上).但进程并不仅仅局限于一段可执行程序代码( ...

  2. C#使用结构体,输入5个人的学号,姓名,分数,按照成绩高低排列打印出来

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. A总结

    Alpha 答辩总结 评审表 组名 格式 内容 ppt 演讲 答辩 总计 天机组 15 15 14 15 14 73 PMS 16 16 15 15 16 78 日不落战队 16 16 16 15 1 ...

  4. We are a 团队

    虽然在团队中只是拖后腿的存在,但是几个人一起摸索着前进也确实有着不一样的感觉. 我们队伍共有五个人:董强强.张振鑫.王鼎.高庆阳还有我(排名不分先后) 我们有自己的关于软件工程的QQ群,会在群里讨论一 ...

  5. css3-文本新增属性

    rgba:a是设透明度值 应用:background:rgb(255,255,255,0.5) color:rgb(255,255,255,0.5) border:1px solid rgb(255, ...

  6. centos 7 安装截图软件shutter

    1.解决 epel-release依赖问题 ,执行命令: yum insatll epel-release 2.然后下载nux-dextop-release-0-5.el7.nux.noarch.rp ...

  7. spring动态数据源+事务

    今天在尝试配置spring的动态数据源和事务管理的时候,遇到了几处配置上的问题,在此记录下: 1.使用了spring的aop思想,实现了动态数据源的切换. 2.spring的事务管理,是基于数据源的, ...

  8. nodejs nodemailer 使用

    index.js const nodemailer=require("nodemailer") let sendEmail=function () { var transporte ...

  9. Java之Set的使用场景

    2.Set使用场景 API介绍: java.util.Set接口和java.util.List接口一样,同样继承自Collection接口, 它与Collection接口中的方法基本一致,并没有对Co ...

  10. MySQL 主从复制详解

    读写分离的意思是,写入的时候向 a 服务器写入,而读出的时候从 b c d 甚至更多的服务器读出:这样的架构适合于读多写少的应用,最典型的就是火车购票系统,一般我们买票的时候要先查询好多次,包括车次啊 ...