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. THE LAST ONE!! 2017《面向对象程序设计》课程作业八

    THE LAST ONE!! 2017<面向对象程序设计>课程作业八 031602230 卢恺翔 GitHub传送门 题目描述 1.时间匆匆,本学期的博客作业就要结束了,是否有点不舍,是否 ...

  2. Beta阶段冲刺-6

    一. 每日会议 1. 照片 2. 昨日完成工作 3. 今日完成工作 4. 工作中遇到的困难 杨晨露:各种问题,虽然都是开发上面的问题,但是都提出来就有点头大了. 戴志斌:对小程序公众号的开发不了解,因 ...

  3. 从零开始学Kotlin-泛型(8)

    从零开始学Kotlin基础篇系列文章 与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼. 泛型类的基本使用 泛型,即 "参数化类型",将类型参数 ...

  4. TCP/IP之大明内阁 转

    原创: 刘欣 码农翻身 2016-11-02 本文是<TCP/IP之大明王朝邮差>的前传,  讲一讲大明内阁的各位大人是怎么设计TCP/IP网络的.大明天启年间,  明熹宗朱由校醉心于木工 ...

  5. dotTrace 每行执行时间和执行次数

    如果代码中出现效率问题,使用dotTrace来跟踪分析代码的效率问题还是很方便的.使用dotTrace不但可以看到每一个方法被调用的次数和总时间,而且可以引入源代码,查看源代码中每一行执行的次数和时间 ...

  6. mac 关闭显示器 & 快捷键

    mac 关闭显示器 & 快捷键 https://support.apple.com/zh-cn/HT201236 https://support.apple.com/zh-cn/HT20705 ...

  7. Before NOIP2017

    明天就比赛了呢! 说起来,这是我第二次,可能也是最后一次正式参加提高组的比赛了. 虽然是从初中就有参加信息学的学习,但是认真学习信息竞赛还是去年七月开始的.NOIP2016 中,我凭着两天的简单题和一 ...

  8. SPFA最短路算法

    SPFA是改良后的BellmanFord(在刘汝佳的入门经典2上,甚至直接将SPFA归为BellmanFord的队列优化版本). 这是算法的伪代码 d[s] = 0, 其余d[?] = INF; 将s ...

  9. 学习Spring Boot:(十一) 自定义装配参数

    前言 SpringMVC 中 Controller 中方法的参数非常灵活,得益于它的强大自动装配,这次将根据上次遗留下的问题,将研究下装配参数. 正文 SpringMVC中使用了两个接口来处理参数: ...

  10. oracle存储过程批量插入测试数据

    前几天测试中债时,自定义资产有一级类型和二级类型,一级类型下有很多分类,每个分类下又有很多二级分类,而要做的是每种类型都要建立一个自定义资产,并做一笔交易,然后测试是否出值,于是写了一个存储过程批量插 ...