数据结构——哈夫曼树构造、编码、输出C++(其实就是一道作业题,嗯)

学数据结构第七周老师布置的作业:
(小白历经千辛万苦才ac,哭)

题目:
哈夫曼编码构造算法:
(老师害挺好的,直接把算法给贴上了,但其实上课都讲过(小声)
  【步骤1】由给定的 n 个字母 {C0,C1,C2,…, Cn-1}和权值 {W0,W1,W2,…, Wn-1},
构造具有n棵扩充二叉树的森林F = { T0,T1,T2,…, Tn-1 },
其中每棵扩充二叉树Ti只有一个带权值Wi的根结点,其左、右子树均为空;
  【步骤2】在F中选取两棵根结点权值最小的扩充二叉树,作为左、右子树构造一棵新的二叉树,
并置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和
  【步骤3】在F中删去这两棵二叉树;
  【步骤4】把新的二叉树加入F中;
  【步骤5】重复步骤2~步骤4, 直到F中仅剩下一棵二叉树为止,即为所求哈夫曼树。
说白了,就是不停的找两个权值最小的然后把他们链接到一个根节点上。为什么要找最小值,是因为哈夫曼树本身要实现的功能

输入格式(这个好烦
第一行:结点的数量
第二行:各个结点的权值
输出格式
第一行:计算该哈夫曼树的WPL
第二行:按照括号的形式输出其哈弗曼树(参考样例输出格式)
第三行:按照哈夫曼编码的由左子树到右子树输出对应权重的编码,不同编码中间用空格隔开
(为了减轻难度,最后一个编码后面需加上空格)(如果编码长度相等,从左到右按照0到1的格式输出,参考样例输出格式)

样例输入:
5
7 5 3 1 8
样例输出: //这个好像其实就是一个遍历的过程
52
24(9(4(1,3),5),15(7,8)) //调试的时候猛然发现这个数字的顺序和前序遍历的顺序是一样的
000 001 01 10 11

小白的思考:
1.只写这个题就不用写类了,累了,好像还没啥必要叭,用结构体好了。

struct TreeNode {
    TreeNode* Leftchild;
    int value;
    TreeNode* Rightchild;
};

2.构造树的函数需要:

  • 在树长大之前储存结点,想着用一个指针数组,数组中的每个指针指向一个结点。没有放结点的即为NULL
  • 找到最小权值和次小权值的结点,把他们连起来,再把新的结点存入数组中,把多余出的改为NULL,以便于下次的循环。
  • 判断树是不是建立好,这里我用数组中元素个数来判断。

3.求WPL的函数:

  • 找到叶子结点,记录叶子结点所在的深度。
  • 递归吧。

4 第二个输出:发现他的顺序和前序遍历的一样,所以在前序遍历的函数中加入符号就好了。然后根据题目可知,在遍历左子树前加"(",左子树右子树之间加",“右子树遍历后加”)"

5.哈夫曼编码:
同样也是递归,需要记录深度,然后根据深度输出,遍历左子树前赋值1,遍历右子树前赋值0.

#include<iostream>

struct TreeNode {
    TreeNode* Leftchild;
    int value;
    TreeNode* Rightchild;
};

//建树
TreeNode* creat(int n) {
    TreeNode* Store[30] = { NULL };
    TreeNode* temp;
    for (int i = 0; i < n; i++) {
        temp = new TreeNode;
        std::cin >> temp->value;
        temp->Leftchild = NULL;
        temp->Rightchild = NULL;
        Store[i] = temp;
    }
    int flag = 0;
    TreeNode* p = NULL;
    while (!flag) {
        //遍历两次确实比较好写,但是好傻哦
        int Min1 = 0, Min2 = 0;
        int count = 0;
        for (int i = 0; i < n; i++) {       //这个循环就可以保证Min1指的是最小的数
            if (Store[i] != NULL) {
                if ((Store[Min1]->value) > Store[i]->value)
                    Min1 = i;
            }
            else continue;
        }
        if (Min1 == 0) Min2 = 1;
        for (int i = 0; i < n; i++) {
            if (i == Min1) continue;
            if (Store[Min2] == NULL && Min2 < n) Min2++;
            if (Store[i] != NULL && Store[Min2] != NULL) {
                if (Store[i]->value < Store[Min2]->value)
                    Min2 = i;
            }
            else continue;
        }
        //这两个循环确实可以保证Min1最小Min2第二小
        temp = new TreeNode;
        temp->value = Store[Min1]->value + Store[Min2]->value;
        temp->Leftchild = Store[Min1];
        temp->Rightchild = Store[Min2];
        Store[Min1] = temp;
        Store[Min2] = NULL;
        for (int i = 0; i < n; i++) {
            if (Store[i] != NULL) {
                p = Store[i];
                count++;
            }
            else continue;
        }
        if (count == 1) {
            return p;
        }
    }

}

//前序遍历
void Preorder(TreeNode* tree) {         //前序遍历证明这个树没啥问题
    if (tree == NULL) return;
    std::cout << tree->value;
    if (tree->Leftchild) {
        std::cout << "(";
        Preorder(tree->Leftchild);
        std::cout << ",";
    }
    if (tree->Rightchild) {
        Preorder(tree->Rightchild);
        std::cout << ")";
    }
}
//求WPL
int WPL(TreeNode* tree, int length)
{
    TreeNode* p = tree;
    if (p==NULL)        //判断是不是空树
        return 0;
    else        //如果不是空树
    {
        if (!p->Leftchild && !p->Rightchild)
            return p->value * length;
        else
            return WPL(p->Leftchild, length + 1) + WPL(p->Rightchild, length + 1);
    }
}

void Huffmancode(TreeNode* huff, int length)
{
    TreeNode* p = huff;
    static int code[30];
    int i;
    if (p)
    {
        if (!p->Leftchild && !p->Rightchild)  //左右都是空的,找到叶子结点了!!!
        {
            for (i = 0; i < length; i++)
                std::cout << code[i];
            std::cout << " ";

        }
        else
        {
            code[length] = 0;
            Huffmancode(p->Leftchild, length + 1);
            code[length] = 1;
            Huffmancode(p->Rightchild, length + 1);
        }
    }
}


int main() {
    int n;
    std::cin >> n;
    TreeNode* tree;
    tree = creat(n);
    int wpl;
    wpl = 0;
    wpl = WPL(tree, wpl);
    std::cout << wpl << std::endl;
    Preorder(tree);
    std::cout << "\n";
    int length = 0;
    Huffmancode(tree, length);
}

找最小数次小数,用一次循环可以解决的算法:
Min1储存最小数,Min2储存此小数。Min1和数组(Store[])中i元素比较,如果Store[i]<min1, 把Store[i]赋给Min1,Min2储存Min1 之前的那个值,就可以保证Min2次小。(但我没改代码,手残该打)

嗯,就先酱叭,感觉还是不太好,但是整整花了10小时去学二叉树和哈夫曼,过程中确实收获了很大的进步。

继续努力学习!!!

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值