21. 计算WPL——New

1 描述

Huffman编码是通信系统中常用的一种不等长编码,它的特点是:能够使编码之后的电文长度最短。

输入:
    第一行为要编码的符号数量n
    第二行~第n+1行为每个符号出现的频率

输出:
    对应哈夫曼树的带权路径长度WPL

  测试输入 期待的输出 时间限制 内存限制 额外进程
测试用例 1 以文本方式显示
  1. 5↵
  2. 7↵
  3. 5↵
  4. 2↵
  5. 4↵
  6. 9↵
以文本方式显示
  1. WPL=60↵
1秒 64M 0
测试用例 2 以文本方式显示
  1. 5↵
  2. 2↵
  3. 4↵
  4. 2↵
  5. 3↵
  6. 3↵
以文本方式显示
  1. WPL=32↵
1秒 64M 0

2 解题

<1> Huffman树

这里发现了一篇很详细的博客 https://blog.csdn.net/qq_29519041/article/details/81428934

<2> 带权路径长度

  • 路径: 从一个祖先结点到子孙结点之间的分支构成这两个结点间的路径
  • 路径长度: 路径上的分支数目称为路径长度
  • 结点的权: 给树中结点所赋有物理意义的值
  • 结点的带权路径长度: 从根到该结点的路径长度与该结点权的乘积
  • 树的带权路径长度 = 树中所有叶子结点的带权路径之和, 通常记作
    WPL= sum( wi x Li )
  • 举个例子
    21. 计算WPL——New_第1张图片
    上面这个huffman树的带权路径长度:
    (3+5)*5+ 7*4+
    (8+11+14)*3+
    (23+29)*2
    =271

<3>基本思想

21. 计算WPL——New_第2张图片

  • 其实用的就是一个一维结构数组来储存这棵树
  • 这里我在教材的基础上增加了一个路径(深度链),方便后面的计算
    21. 计算WPL——New_第3张图片

<4> 代码

#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef struct
{//我在教材的基础上又增加了一个链,形成静态四叉链表,同时存权值,父亲,左孩子,右孩子,路径(也就是深度)
    int weight;
    int parent, lchild, rchild;
    int depth;
} HTNode, *HuffmanTree;

void Select(HuffmanTree HT, int n, int *s1, int *s2)
{
    int i;
    *s1 = n;//最后一个是刚刚建立的,一定没有使用过(parent值肯定为0)
    for (i = 1; i < n; i++)
    {
        if (HT[i].parent)
            continue;
        if (HT[*s1].weight > HT[i].weight)
            *s1 = i;
    }
    for (i = 1; i <= n; i++)
    {//这个循环用来s2一个初值
        if (HT[i].parent)
            continue;
        if (*s1 == i)
            continue;
        else
        {
            *s2 = i;
            break;
        }
    }
    for (i = 1; i <= n; i++)
    {
        if (HT[i].parent || i == *s1)//确保s2和s1的指向不一样
            continue;
        if (HT[*s2].weight > HT[i].weight)
            *s2 = i;
    }
}

void Setdepth(HuffmanTree HT, HTNode *ht)
{//利用了递归
    if (!ht->lchild && !ht->rchild)
        ht->depth++;//到达叶节点
    else
    {
        ht->depth++;
        HTNode *p;
        if (ht->lchild)
        {
            p = &HT[ht->lchild];
            Setdepth(HT, p);
        }
        if (ht->rchild)
        {
            p = &HT[ht->rchild];
            Setdepth(HT, p);
        }
    }
}

int TreeCreat(HuffmanTree &HT, int *w, int n)
{//引用类型的赋值也是一样的
    if (n <= 1)//如果只有一个节点,路径为0,直接返回
        return 0;
    int m = 2 * n - 1;
    HT = (HuffmanTree)malloc(sizeof(HTNode) * (m + 1));
    HuffmanTree p;
    int *q;
    int i;
    for (p = HT + 1, q = w + 1, i = 1; i <= n; i++, p++, q++)
    {//初始化,因为最后一组数据的深度不会算进去,所以最开始我直接让depth为1
        *p = {*q, 0, 0, 0, 1};
    }
    int s1, s2;//两个最小值的下标
    for (i = n + 1; i < m; i++, p++)
    {
        Select(HT, i - 1, &s1, &s2);
        HT[s1].parent = i;
        HT[s2].parent = i;
        HT[i].lchild = s1;
        HT[i].rchild = s2;
        HT[i].parent = 0;
        HT[i].depth = 1;
        HT[i].weight = HT[s1].weight + HT[s2].weight;
        Setdepth(HT, &HT[i]);
    }
    return 0;
}

void Treeprint(HuffmanTree HT, int n)
{
    int i;
    for (i = 1; i <= n; i++)
    {
        cout << HT[i].weight << endl;
        cout << HT[i].depth << endl
             << endl;
    }
}

int WPLcalcu(HuffmanTree HT, int n)
{
    int sum = 0;
    int i;
    for (i = 1; i <= n; i++)
    {
        sum += HT[i].weight * HT[i].depth;
    }
    return sum;
}

int main()
{

    int *w;//存储用户输入
    int n;
    int i;
    int value = 0;//最短带权路径长度
    // freopen("file out.txt", "r", stdin);
    cin >> n;
    w = (int *)malloc(sizeof(int) * (n + 1));

    for (i = 1; i <= n; i++)
    { //第0个位置不用
        cin >> w[i];
    }

    HuffmanTree HT;

    TreeCreat(HT, w, n);

    // Treeprint(HT,n);
    value = WPLcalcu(HT, n);
    cout << "WPL=" << value << endl;
    return 0;
}

  • 小结:
    指针和引用的简单区别

你可能感兴趣的:(数据结构与算法设计,数据结构,霍夫曼树,树堆)