数据结构 赫夫曼树(上)

简介: 数据结构 赫夫曼树

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


题目描述


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


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


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


代码框架参考如下:


78d2dde93f3b40e788f83363d183f30e.png

78e2aef3774a4ff9899d5f343d9aa1b3.png


5f76c05924364e509a37a161ff4e20bf.png


输入


第一行输入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


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


8b51c0e6a3244d55be1706f656446386.png


输入


第一行输入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


3449ed869e3c486383d275e1ce77c813.png


输入


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


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


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


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


输出


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


输入样例


2

xA00tB00zC00D00

4 7 6 2 3

ab0C00D00

2 10 20


输出样例


34

40


参考代码

#include <iostream>
#include <string>
using namespace std;
class BitreeNode
{
public:
    char data;
    int weight;
    int height;
    BitreeNode *left;
    BitreeNode *right;
    BitreeNode()
    {
        weight = 0;
        height = 0;
        left = NULL;
        right = NULL;
    }
};
class Bitree
{
public:
    BitreeNode *Root;
    int pos, index; ///index控制数组非0权值
    string strtree;
    int API;
    Bitree(int *w, string str)
    {
        pos = index = 0;
        API = 0;
        strtree = str;
        Root = CreateBitree(w, 0); ///根结点无双亲,双亲高度为0
    }
    BitreeNode *CreateBitree(int *w, int fatherheight)
    {
        char ch = strtree[pos];
        pos++;
        if (ch == '0')
        {
            return NULL;
        }
        else
        {
            BitreeNode *T = new BitreeNode();
            T->data = ch;
            T->height = fatherheight + 1;
            if (T->data >= 'A' && T->data <= 'Z')
            {
                T->weight = w[index];
                index++;
            }
            T->left = CreateBitree(w, T->height);
            T->right = CreateBitree(w, T->height);
            return T;
        }
    }
    void preorder(BitreeNode *T)
    {
        if (T != NULL)
        {
            API += T->weight * (T->height - 1); ///高度减1才是对应乘的值
            preorder(T->left);
            preorder(T->right);
        }
        return;
    }
};
int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        string str;
        cin >> str;
        int n;
        cin >> n;
        int *a = new int[n];
        for (int i = 0; i < n; i++)
            cin >> a[i];
        Bitree Tree(a, str);
        Tree.preorder(Tree.Root);
        cout << Tree.API << endl;
    }
    //system("pause");
    return 0;
}


相关文章
|
3月前
|
C++
【数据结构】—AVL树(C++实现)
【数据结构】—AVL树(C++实现)
|
3月前
|
存储
数据结构 B树
数据结构 B树
31 0
|
8天前
|
算法 DataX
二叉树(中)+Leetcode每日一题——“数据结构与算法”“剑指Offer55-I. 二叉树的深度”“100.相同的树”“965.单值二叉树”
二叉树(中)+Leetcode每日一题——“数据结构与算法”“剑指Offer55-I. 二叉树的深度”“100.相同的树”“965.单值二叉树”
|
29天前
|
存储 算法 程序员
【数据结构】【版本2.0】【树形深渊】——二叉树入侵
【数据结构】【版本2.0】【树形深渊】——二叉树入侵
|
30天前
|
存储 算法 数据库
【C/C++ 数据结构 】树的 四种表示方法
【C/C++ 数据结构 】树的 四种表示方法
30 0
|
30天前
|
存储 算法 C语言
【C/C++ 数据结构 树】探索C/C++中的二叉树:从理论到实践
【C/C++ 数据结构 树】探索C/C++中的二叉树:从理论到实践
60 0
|
存储
【树和二叉树】数据结构二叉树和树的概念认识
【树和二叉树】数据结构二叉树和树的概念认识
|
2月前
|
存储
数据结构【树+二叉树】
数据结构【树+二叉树】
28 3
|
2月前
|
存储
数据结构:Trie树
数据结构:Trie树
35 1
数据结构:Trie树
|
2月前
|
人工智能 算法
【数据结构入门精讲 | 第十三篇】考研408、公司面试树专项练习(二)
【数据结构入门精讲 | 第十三篇】考研408、公司面试树专项练习(二)
29 0