8609 哈夫曼树

8609 哈夫曼树

时间限制:1000MS 代码长度限制:10KB
提交次数:3178 通过次数:1263

题型: 编程题 语言: G++;GCC

Description 利用静态链表建立赫夫曼树,建树过程中要求左子树权值小于右子树权值,求各结点的编码。要求:叶子结点的个数n及结点值由键盘录入。本题给出程序代码,要求修改以满足测试要求.

思路
n个节点  会合并n-1次最后存在2n-1个节点
先找到节点里最小的两个  然后合并成新节点 
重复操作 直到合成为一颗二叉树 
这个oj题代码模版给的乱七八糟
有两个版本
这个是填满模版  能够查看测试的版本  


#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
#include<vector>
#include<string.h>
#include<algorithm>
#include<queue>
#include "stdio.h"
#include "malloc.h"
#include "string.h"

using namespace std;

typedef struct {
    unsigned int weight;
    unsigned int parent, lchild, rchild;
}HTNode, * HuffmanTree;
typedef char** HuffmanCode;

void Select(HuffmanTree HT, int n, int& s1, int& s2)
//在HT[1..n]中选择parent为0且weight最小的两个结点,
// 其序号分别为s1和s2。
{
    int i;
    s1 = s2 = 0;
    HT[0].weight = 1e9;
    for (int i = 1; i <= n; i++) {
        //如果没有该节点被合并  即父节点为0
        //找 两个最小的  s1 s2   s1要小于s2  
        if(HT[i].parent == 0){
            //迭代赋值
            if (HT[i].weight < HT[s1].weight) {
                s2 = s1;
                s1 = i;
            }
            else if (HT[i].weight < HT[s2].weight) {
                s2 = i;
            }
        }
    }
}


void HuffmanCoding(HuffmanTree & HT, HuffmanCode & HC, int* w, int n){
    // 并求出n个字符的哈夫曼编码HC
  int i, j, m, s1, s2, start; 
        char* cd;
        unsigned int c, f;
        //如果节点数小于等于一  说明已合并
        if (n <= 1) return;
        //n个节点  合并n-1次   最终得到2*n-1个节点
        m = 2 * n - 1;
        //因为下标从1开始用  所以申请 m+1 内存空间
        HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));  // 0号单元未用
        //原有的节点初始化
        for (i = 1; i <= n; i++) { //初始化
            //初始化权值
            HT[i].weight = w[i - 1];
            HT[i].parent = 0;
            HT[i].lchild = 0;
            HT[i].rchild = 0;
        }
        //新合并的节点初始化   权值为0
        for (i = n + 1; i <= m; i++) { //初始化
            HT[i].weight = 0;
            HT[i].parent = 0;
            HT[i].lchild = 0;
            HT[i].rchild = 0;
        }
        printf("\n哈夫曼树的构造过程如下所示:\n");
        printf("HT初态:\n  结点  weight  parent  lchild  rchild");
        for (i = 1; i <= m; i++)
            printf("\n%4d%8d%8d%8d%8d", i, HT[i].weight,
                HT[i].parent, HT[i].lchild, HT[i].rchild);
        printf("    按任意键,继续 ...");
        //getch()为输入一个字符,但是不显示,需要加头文件conio
        getch();
        //建树  新节点从n+1到m
        for (i = n + 1; i <= m; i++) {  // 建哈夫曼树
          // 在HT[1..i-1]中选择  parent为0  且  weight最小  的  两个结点,
          // 其序号分别为s1和s2。
            Select(HT, i - 1, s1, s2);
            //两节点父节点即为  i
            HT[s1].parent = i;  HT[s2].parent = i;
            //小的为左子树   大的为右子树
            HT[i].lchild = s1;  HT[i].rchild = s2;
            //新的节点i的权值即为  两子树权值之和
            HT[i].weight = HT[s1].weight + HT[s2].weight;
            printf("\nselect: s1=%d   s2=%d\n", s1, s2);
            printf("  结点  weight  parent  lchild  rchild");
            //从1到i再次查看树的构建
            for (j = 1; j <= i; j++)
                printf("\n%4d%8d%8d%8d%8d", j, HT[j].weight, HT[j].parent, HT[j].lchild, HT[j].rchild);
            printf("    按任意键,继续 ...");
            getch();
        }
        //--- 从叶子到根 逆向 求每个字符的哈夫曼编码 ---
        cd = (char*)malloc(n * sizeof(char));    // 分配求编码的工作空间
        cd[n - 1] = '\0';                         // 编码结束符。
        for (i = 1; i <= n; ++i) {                  // 逐个字符求哈夫曼编码
            start = n - 1;                          // 编码结束符位置
            for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
                // 从叶子到根逆向求编码
                if (HT[f].lchild == c) cd[--start] = '0';
                else cd[--start] = '1';
            HC[i] = (char*)malloc((n - start) * sizeof(char));
            // 为第i个字符编码分配空间
            strcpy(HC[i], &cd[start]);    // 从cd复制编码(串)到HC	

        }
        free(cd);   //释放工作空间
    } //HuffmanCoding

    int main(void)
    {
        int i, n;
        int* w;
        HuffmanTree HT;
        HuffmanCode HC;
        printf("Node Number:");
        scanf("%d", &n);  //权值个数
        w = (int*)malloc(n * sizeof(int));
        printf("Input weights:");
        for (i = 0; i < n; i++)  //录入权值
            scanf("%d", &w[i]);

        HC = (char**)malloc((n + 1) * sizeof(char*)); //0空间未用
        HT = (HuffmanTree)malloc((2 * n + 1 + 1) * sizeof(HTNode));//0空间未用
        HuffmanCoding(HT, HC, w, n);
        printf("\n");
        for (i = 1; i < n + 1; i++) {
            puts(HC[i]);  //输出哈夫曼编码
            free(HC[i]);  //释放空间
        }
        free(HC);
        free(HT);
        return 0;
    }//main
这个是根据题设的 输入输出  的模版   少了查看数据过程的代码


#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
#include<vector>
#include<string.h>
#include<algorithm>
#include<queue>
#include "stdio.h"
#include "malloc.h"
#include "string.h"

using namespace std;

typedef struct {
    unsigned int weight;
    unsigned int parent, lchild, rchild;
}HTNode, * HuffmanTree;
typedef char** HuffmanCode;

void Select(HuffmanTree HT, int n, int& s1, int& s2)
//在HT[1..n]中选择parent为0且weight最小的两个结点,
// 其序号分别为s1和s2。
{
    int i;
    s1 = s2 = 0;
    HT[0].weight = 1e9;
    for (int i = 1; i <= n; i++) {
        //如果没有该节点被合并  即父节点为0
        //找 两个最小的  s1 s2   s1要小于s2  
        if(HT[i].parent == 0){
            //迭代赋值
            if (HT[i].weight < HT[s1].weight) {
                s2 = s1;
                s1 = i;
            }
            else if (HT[i].weight < HT[s2].weight) {
                s2 = i;
            }
        }
    }
}


void HuffmanCoding(HuffmanTree & HT, HuffmanCode & HC, int* w, int n){
    // 并求出n个字符的哈夫曼编码HC
  int i, j, m, s1, s2, start; 
        char* cd;
        unsigned int c, f;
        //如果节点数小于等于一  说明已合并
        if (n <= 1) return;
        //n个节点  合并n-1次   最终得到2*n-1个节点
        m = 2 * n - 1;
        //因为下标从1开始用  所以申请 m+1 内存空间
        HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));  // 0号单元未用
        //原有的节点初始化
        for (i = 1; i <= n; i++) { //初始化
            //初始化权值
            HT[i].weight = w[i - 1];
            HT[i].parent = 0;
            HT[i].lchild = 0;
            HT[i].rchild = 0;
        }
        //新合并的节点初始化   权值为0
        for (i = n + 1; i <= m; i++) { //初始化
            HT[i].weight = 0;
            HT[i].parent = 0;
            HT[i].lchild = 0;
            HT[i].rchild = 0;
        }
        //建树  新节点从n+1到m
        for (i = n + 1; i <= m; i++) {  // 建哈夫曼树
          // 在HT[1..i-1]中选择  parent为0  且  weight最小  的  两个结点,
          // 其序号分别为s1和s2。
            Select(HT, i - 1, s1, s2);
            //两节点父节点即为  i
            HT[s1].parent = i;  HT[s2].parent = i;
            //小的为左子树   大的为右子树
            HT[i].lchild = s1;  HT[i].rchild = s2;
            //新的节点i的权值即为  两子树权值之和
            HT[i].weight = HT[s1].weight + HT[s2].weight;
        }
        //--- 从叶子到根 逆向 求每个字符的哈夫曼编码 ---
        cd = (char*)malloc(n * sizeof(char));    // 分配求编码的工作空间
        cd[n - 1] = '\0';                         // 编码结束符。
        for (i = 1; i <= n; ++i) {                  // 逐个字符求哈夫曼编码
            start = n - 1;                          // 编码结束符位置
            for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
                // 从叶子到根逆向求编码
                if (HT[f].lchild == c) cd[--start] = '0';
                else cd[--start] = '1';
            HC[i] = (char*)malloc((n - start) * sizeof(char));
            // 为第i个字符编码分配空间
            strcpy(HC[i], &cd[start]);    // 从cd复制编码(串)到HC	

        }
        free(cd);   //释放工作空间
    } //HuffmanCoding

    int main(void)
    {
        int i, n;
        int* w;
        HuffmanTree HT;
        HuffmanCode HC;
        scanf("%d", &n);  //权值个数
        w = (int*)malloc(n * sizeof(int));
        for (i = 0; i < n; i++)  //录入权值
            scanf("%d", &w[i]);

        HC = (char**)malloc((n + 1) * sizeof(char*)); //0空间未用
        HT = (HuffmanTree)malloc((2 * n + 1 + 1) * sizeof(HTNode));//0空间未用
        HuffmanCoding(HT, HC, w, n);
        for (i = 1; i < n + 1; i++) {
            puts(HC[i]);  //输出哈夫曼编码
            free(HC[i]);  //释放空间
        }
        free(HC);
        free(HT);
        return 0;
    }//main
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值