3:Huffman编码树

总时间限制: 
1000ms 
内存限制: 
65535kB
描述


构造一个具有n个外部节点的扩充二叉树,每个外部节点Ki有一个Wi对应,作为该外部节点的权。使得这个扩充二叉树的叶节点带权外部路径长度总和最小:

                                     Min( W1 * L1 + W2 * L2 + W3 * L3 + … + Wn * Ln)

Wi:每个节点的权值。

Li:根节点到第i个外部叶子节点的距离。

编程计算最小外部路径长度总和。

输入
第一行输入一个整数t,代表测试数据的组数。
对于每组测试数据,第一行输入一个整数n,外部节点的个数。第二行输入n个整数,代表各个外部节点的权值。
2<=N<=100
输出
输出最小外部路径长度总和。
样例输入
231 2 341 1 3 5
样例输出
917
提示
仅考查huffman树的建立,数据范围小,可以不需要使用堆结构.
不过鼓励使用第一题实现的堆来寻找最小和次小元素。



优先队列用堆实现。

这题曾RE十几次。。只因用的全局变量没有初始化。。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<assert.h>
#include<ctype.h>
#include<stdlib.h>
using namespace std;

struct node{
    int huffman;
    struct node *l,*r;
}a[300],b[220];///b节点数组用来保存 a节点数组原来的值。
int n,fu,sum;
void siftdown( int wz )///wz是下标的意思。 这里的操作是如果此节点比子节点的权大的话,就交换 直到找到合适的位置为止
{
    if(wz>n)return ;
    int twz = wz;
    node temp = a[twz];
    int j = 2*wz;
    while(j <= n )
    {
        if( j+1 <= n   && a[j].huffman > a[j+1].huffman )j++;///左孩子比右孩子大。J + 1
        if(temp.huffman > a[j].huffman )///找到合适位置。
        {
            a[twz] = a[j];
            twz = j;
            j = j*2;
        }
        else break;
    }
    a[twz] = temp;
}
void siftup( int wz )///向上调整 子节点比父节点小的话。
{
    int twz = wz;
    node temp = a[wz];
    while( twz > 1 && a[twz/2].huffman > temp.huffman )
    {
        a[twz] = a[twz/2];
        twz /= 2;
    }
    a[twz] = temp;
}
void build(  )///建堆  由下往上建堆。。由下标大的往上。。由孙子到祖宗,课程说这样建堆比较好。具体原因 望你分析给我听。
{
    int i;
    for(i = n/2+1; i >0; i--)
        siftdown(i);
    for(i = n/2+1;i > 1;i--)
        siftdown(i);
}

void del(int wz)///删除堆中最小的节点。 也就是根。删除方法是 拿这个完全二叉树的最后一个节点替换掉根 再向下调整。
{
    if(n<=1)return ;
    a[1] = a[n--];
    siftdown(1);
}

node jianshu( node a1,node a2 )///建huffman树。又是静态拼装。。想请教怎么动态。。看有个视频运用链表。。指针的指针。。= -
{
    b[fu++] = a1;
    b[fu++] = a2;
    node temp;
    temp.l = &b[fu-2];
    temp.r = &b[fu-1];
    temp.huffman = a1.huffman + a2.huffman;
    return temp;
}
/*void vis(int a,int level)
{
    printf("%d_____%d_))((\n",a,level);
}*/

void bianli(node *T,int level)///遍历  计算最小外部路径和。
{
    if(T)
    {
        if(!T->l&&!T->r)sum += (level) *(T->huffman);
        //vis(T->huffman,level);
        bianli(T->l,level+1);
        bianli(T->r,level+1);
    }
}

int main()
{

    int t;
    scanf("%d",&t);
    while(t--)
    {
        fu=1;
        sum = 0;
        scanf("%d",&n);
        int i;
        for(i= 1; i <= n; i++)///初始化。
        {
            scanf("%d",&a[i].huffman);
            a[i].l = a[i].r = NULL;
        }
        build();
        int tme = n-1;///拼装的次数。

        while(tme--)
        {
            if(n>=3&&a[2].huffman>a[3].huffman){node temp= a[2];a[2] = a[3]; a[3] = temp;}
            if(n>=2)a[2] = jianshu(a[1],a[2]);
            del(1);
            build();
        }
        bianli(&a[1],0);
        printf("%d\n",sum);

    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值