Bootstrap

【复旦大学历年机试题】2016-03(哈夫曼树)

在这里插入图片描述
题目:给定一个字符串,求哈夫曼编码的最短长度。

输入样例:
aaaaabbbbcccdde
输出样例:
33

题解:本题需要模拟手动创建哈夫曼树的过程,最终计算结果 = Σ(每个叶子结点出现频次*其哈夫曼编码的长度),过程如下:
(1)创建结点node结构体,其内容要包括:①val:代表频次和;②指向父结点的指针,用以计算层数;③name:表示结点名,用以后续寻找该结点;
(2)遍历给定的字符串,用数组记录各字母出现频次,然后建立结点记录这些字母及出现频次,而后初始化两个vector保存它们(一个临时保存,一个用于最后的计算总和);
(3)sort排序,每次挑选最小的两个结点生成一个新结点,构建哈夫曼树,加入数组,遍历size-1次(这是由于哈夫曼树的新结点是叶结点总数-1个);
(4)每个叶结点(保存在一个vector中)的层数-1(编码长度) 乘以 频次,求和即可得字符串的哈夫曼编码长度。

代码(C++)

#include <bits/stdc++.h>
using namespace std;

struct node{
    char name;
    struct node *parent;
    int val;
    node(char name,struct node *parent,int val) : name(name), parent(parent),val(val) {}
};

int main(){
    string str;  // 输入字符串
    vector<node *> vec,temp;  // 存储字符串元素构成的结点
    int cnt[26] = {0};  // 字符串元素计数
    int res = 0;  // 求和

    // 输入
    cin >> str;

    // 主体
    for(char c : str){  // 计数
        cnt[c - 'a']++;
    }
    for(int i = 0; i < sizeof (cnt) / sizeof (int); i++){  // 构建存储结点的数组
        if(cnt[i] != 0){
            node *cur = new node('a'+i, nullptr,cnt[i]);
            temp.push_back(cur);
            vec.push_back(cur);
        }
    }
    for(int i = 0; i < vec.size() - 1; i++){  // 构建哈夫曼树
        sort(temp.begin(), temp.end(), [](node *p1, node *p2){return p1->val < p2->val;});
        node *c1 = temp[0];  // 取出来两个结点
        node *c2 = temp[1];
        node *p = new node('0'+i, nullptr,c1->val + c2->val);
        c1->parent = p;
        c2->parent = p;
        temp.push_back(p);
        temp.erase(temp.begin());
        temp.erase(temp.begin());
    }
    for(auto p : vec){  // 计算每个结点的层数-1 * 频次,而后求和
        int level = 0;  // 层数
        int num = p->val;  // 频次
        while(p->parent != nullptr){
            level++;
            p = p->parent;
        }
        res += level * num;
    }

    //输出
    printf("%d",res);

    return 0;
}

写在后面

这个专栏主要是我在刷题的过程中总结的一些笔记,因为我学的也很一般,如果有错误和不足之处,还望大家在评论区指出。希望能给大家的学习带来一点帮助,共同进步!!!

;