数据结构 赫夫曼树

Posted 上山打老虎D

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 赫夫曼树相关的知识,希望对你有一定的参考价值。

1. DS二叉树–赫夫曼树的构建与编码(含代码框架)

题目描述

给定n个权值,根据这些权值构造huffman树,并进行huffman编码

参考课本算法,注意数组访问是从位置1开始

要求:赫夫曼的构建中,默认左孩子权值不大于右孩子权值

代码框架参考如下:

输入

第一行输入t,表示有t个测试实例
第二行先输入n,表示第1个实例有n个权值,接着输入n个权值,权值全是小于1万的正整数
依此类推

输出

逐行输出每个权值对应的编码,格式如下:权值-编码
即每行先输出1个权值,再输出一个短划线,再输出对应编码,接着下一行输入下一个权值和编码。
以此类推

输入样例

1
5 15 4 4 3 2

输出样例

15-1
4-010
4-011
3-001
2-000

参考代码

#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int MaxW = 9999;
class huffNode //结点定义
{
public:
    int weight; //权值
    int parent; //父结点下标
    int left;   //左下标
    int right;  //右下标
};
class huffman
{
private:
    void maketree();
    void selectmin(int pos, int *s1, int *s2);

public:
    int len;            //结点数量
    int lnum;           //叶子数量
    huffNode *hufftree; //赫夫曼树,用数组表示
    string *huffcode;   //赫夫曼编码
    void maketree(int n, int wt[]);
    void coding();
    void destroy();
};
void huffman::maketree(int n, int wt[])
{
    int i;
    lnum = n;
    len = 2 * n - 1;
    hufftree = new huffNode[2 * n];
    huffcode = new string[lnum + 1];
    for (i = 1; i <= len; i++)
        hufftree[i].weight = wt[i - 1];
    for (i = 1; i <= len; i++)
    {
        if (i > n)
            hufftree[i].weight = 0;
        hufftree[i].parent = 0;
        hufftree[i].left = 0;
        hufftree[i].right = 0;
    }
    maketree();
}

void huffman::selectmin(int pos, int *s1, int *s2)
{
    int w1, w2, i;
    w1 = w2 = MaxW;
    *s1 = *s2 = 0;
    for (i = 1; i <= pos; i++)
    {
        if (hufftree[i].weight < w1 && hufftree[i].parent == 0)
        {
            w2 = w1;
            *s2 = *s1;
            *s1 = i;
            w1 = hufftree[i].weight;
        }
        else if (hufftree[i].weight < w2 && hufftree[i].parent == 0)
        {
            *s2 = i;
            w2 = hufftree[i].weight;
        }
    }
}
void huffman::maketree()
{
    int i, s1, s2;
    for (i = lnum + 1; i <= len; i++)
    {
        selectmin(i - 1, &s1, &s2);
        hufftree[s1].parent = i;
        hufftree[s2].parent = i;
        hufftree[i].left = s1;
        hufftree[i].right = s2;
        hufftree[i].weight = hufftree[s1].weight + hufftree[s2].weight;
    }
}
void huffman::destroy()
{
    len = 0;
    lnum = 0;
    delete[] hufftree;
    delete[] huffcode;
}
void huffman::coding()
{
    char *cd;
    int i, c, f, start;
    cd = new char[lnum];
    cd[lnum - 1] = '\\0';
    for (i = 1; i <= lnum; i++)
    {
        start = lnum - 1;
        for (c = i, f = hufftree[i].parent; f != 0; c = f, f = hufftree[f].parent)
        {
            if (hufftree[f].left == c)
            {
                start--;
                cd[start] = '0';
            }
                
            else
            {
                start--;
                cd[start] = '1';
            }
        }
        //huffcode[i] = new char[lnum-start];
        huffcode[i].assign(&cd[start]);
    }
    delete[] cd;
}
int main()
{
    int t, n, i, j;
    int wt[800];
    huffman myhuff;
    cin >> t;
    for (i = 0; i < t; i++)
    {
        cin >> n;
        for (j = 0; j < n; j++)
            cin >> wt[j];
        myhuff.maketree(n, wt);
        myhuff.coding();
        for (j = 1; j <= n; j++)
        {
            cout << myhuff.hufftree[j].weight << '-';
            cout << myhuff.huffcode[j] << endl;
        }
        myhuff.destroy();
    }
    return 0;
}

2. DS二叉树–赫夫曼树解码(含代码框架)

题目描述

已知赫夫曼编码算法和程序,在此基础上进行赫夫曼解码

在赫夫曼树的类定义中增加了一个公有方法:

int Decode(const string codestr, char txtstr[]);//输入编码串codestr,输出解码串txtstr

该方法如果解码成功则返回1,解码失败则返回-1,本程序增加宏定义ok表示1,error表示-1

解码方法的代码框架如下:

输入

第一行输入t,表示有t个测试实例
第二行先输入n,表示第1个实例有n个权值,接着输入n个权值,权值全是小于1万的正整数
第三行输入n个字母,表示与权值对应的字符
第四行输入k,表示要输入k个编码串
第五行起输入k个编码串
以此类推输入下一个示例

输出

每行输出解码后的字符串,如果解码失败直接输出字符串“error”,不要输出部分解码结果

输入样例

2
5 15 4 4 3 2
A B C D E
3
11111
10100001001
00000101100
4 7 5 2 4
A B C D
3
1010000
111011
111110111

输出样例

AAAAA
ABEAD
error
BBAAA
error
DCD

参考代码

#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int MaxW = 9999;
class huffNode //结点定义
{
public:
    int weight; //权值
    int parent; //父结点下标
    int left;   //左下标
    char word;
    int right;  //右下标
};
class huffman
{
private:
    void maketree();
    void selectmin(int pos, int *s1, int *s2);

public:
    int len;  //结点数量
    int lnum; //叶子数量
    huffNode *hufftree; //赫夫曼树,用数组表示
    string *huffcode;   //赫夫曼编码
    void maketree(int n, int wt[],char ct[]);
    void coding();
    void destroy();
    bool decode(const string codestr, char txtstr[]);
};
void huffman::maketree(int n, int wt[],char ct[])
{
    int i;
    lnum = n;
    len = 2 * n - 1;
    hufftree = new huffNode[2 * n];
    huffcode = new string[lnum + 1];
    for (i = 1; i <= len; i++)
    {
        hufftree[i].weight = wt[i - 1];
        hufftree[i].word = ct[i - 1];
    }
        
    for (i = 1; i <= len; i++)
    {
        if (i > n)
            hufftree[i].weight = 0;
        hufftree[i].parent = 0;
        hufftree[i].left = 0;
        hufftree[i].right = 0;
    }
    maketree();
}

void huffman::selectmin(int pos, int *s1, int *s2)
{
    int w1, w2, i;
    w1 = w2 = MaxW;
    *s1 = *s2 = 0;
    for (i = 1; i <= pos; i++)
    {
        if (hufftree[i].weight < w1 && hufftree[i].parent == 0)
        {
            w2 = w1;
            *s2 = *s1;
            *s1 = i;
            w1 = hufftree[i].weight;
        }
        else if (hufftree[i].weight < w2 && hufftree[i].parent == 0)
        {
            *s2 = i;
            w2 = hufftree[i].weight;
        }
    }
}
void huffman::maketree()
{
    int i, s1, s2;
    for (i = lnum + 1; i <= len; i++)
    {
        selectmin(i - 1, &s1, &s2);
        hufftree[s1].parent = i;
        hufftree[s2].parent = i;
        hufftree[i].left = s1;
        hufftree[i].right = s2;
        hufftree[i].weight = hufftree[s1].weight + hufftree[s2].weight;
    }
}
void huffman::destroy()
{
    len = 0;
    lnum = 0;
    delete[] hufftree;
    delete[] huffcode;
}
void huffman::coding()
{
    char *cd;
    int i, c, f, start;
    cd = new char[lnum];
    cd[lnum - 1] = '\\0';
    for (i = 1; i <= lnum; i++)
    {
        start = lnum - 1;
        for (c = i, f = hufftree[i].parent; f != 0; c = f, f = hufftree[f].parent)
        {
            if (hufftree[f].left == c)
            {
                start--;
                cd[start] = '0';
            }

            else
            {
                start--;
                cd[start] = '1';
            }
        }
        //huffcode[i] = new char[lnum-start];
        huffcode[i].assign(&cd[start]);
    }
    delete[] cd;
}

bool huffman::decode(const string codestr, char txtstr[])
{
    int i, k, c;
    char ch;
    c = len;
    k = 0;
    for (i = 0; i < codestr.size(); i++)
    {
        ch = codestr[i];
        if (ch == '0')
        {
            c = hufftree[c].left;
        }
        else if (ch == '1')
        {
            c = hufftree[c].right;
        }
        else
        {
            return false;
        }
        if (!hufftree[c].left && !hufftree[c].right)
        {
            txtstr[k] = hufftree[c].word;
            k++;
            c = len;
        }
        else
        {
            ch = '\\0';
        }
        
    }
    if (ch == '\\0')
        return false;
    else
    {
        txtstr[k] = '\\0';
    }
    return true;
}

int main()
{
    int t, n, i, j;
    int wt[800];
    char ct[800];
    huffman myhuff;
    cin >> t;
    for (i = 0; i < t; i++)
    {
        cin >> n;
        char txtstr[800];
        for (j = 0; j < n; j++)
            cin >> wt[j];
        for (j = 0; j < n; j++)
            cin >> ct[j];
        myhuff.maketree(n, wt, ct);
        myhuff.coding();
        cin >> n;
        while(n--)
        {
            string codestr;
            cin >> codestr;
            if(myhuff.decode(codestr,txtstr))
            {
                cout << txtstr << endl;
            }
            else 
            {
                cout << "error" << endl;
            }
        }
        myhuff.destroy();
    }
    return 0;
}

3. DS树–带权路径和

题目描述

计算一棵二叉树的带权路径总和,即求赫夫曼树的带权路径和。

已知一棵二叉树的叶子权值,该二叉树的带权案路径和APL等于叶子权值乘于根节点到叶子的分支数,然后求总和。如下图中,叶子都用大写字母表示,权值对应为:A-7,B-6,C-2,D-3

树的带权路径和 = 71 + 62 + 23 + 33 = 34

输入

第一行输入一个整数t,表示有t个二叉树

第二行输入一棵二叉树的先序遍历结果,空树用字符‘0’表示,注意输入全是英文字母和0,其中大写字母表示叶子

第三行先输入n表示有n个叶子,接着输入n个数据表示n个叶子的权值,权值的顺序和前面输入的大写字母顺序对应

以此类推输入下一棵二叉树

输出

输出每一棵二叉树的带权路径和

输入样例

2
xA00tB00zC00D00
4 7 6 2 3以上是关于数据结构 赫夫曼树的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法:树 赫夫曼树

数据结构与算法:树 赫夫曼树

学习数据结构笔记(10) --- [赫夫曼树(Huffman Tree)与赫夫曼编码(Huffman coding)]

数据结构与算法:树 赫夫曼树

数据结构与算法:树 赫夫曼树

数据结构与算法:树 赫夫曼树