5-9 Huffman Codes

点击打开链接

符合两个要求就可以判断该树是否满足要求

判断输入的编码是否符合要求(1、编码长度与Huffman编码长度相同 2、前缀编码)

首先想到的避免建一棵哈弗曼树,是用一个结构体node来保存学生提交的节点的编码

但估计在判断前缀编码时会超时(N<=63 ,两层for循环),不能拿满分

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<queue>
#include<algorithm>
#include<map>
#include<vector>
#include<cstring>
#include<math.h>
#include<stack>
using namespace std;
判断输入的编码是否符合要求(1、编码长度与Huffman编码长度相同 2、前缀编码)
int N;
struct node
{
    string s; //学生提交的节点的编码
    int Count;//节点的频率
}p[80];

map<char,int >ha;//频率
priority_queue<int ,vector<int>,greater<int> > q;//从小到大排

bool check()
{
    int i,j;
    for( i=0;i<N;i++)
    {
        string temp=p[i].s.substr(0,p[i].s.length());
        for( j=0;j<N;j++)
        {
            if(i==j)
                continue;
            else
            {
                if(temp==p[j].s.substr(0,p[i].s.length()))
                    break;
            }

        }
        if(j<N)
            return false;
    }
    return true;
}


int main()
{
    char c;
    scanf("%d",&N);
    int wpl=0;
    for(int i=0;i<N;i++)
    {
        //scanf("%c ",&c);
        cin>>c;
        scanf("%d",&ha[c]);//记录每个节点的频率
        q.push(ha[c]);
    }
    int cur;
    while(!q.empty())
    {
        cur=q.top();
        q.pop();
        if(q.empty())//最后一次不用加
        {
            break;
        }
        cur+=q.top();
        q.pop();
        wpl+=cur;
        q.push(cur);
    }
    int num;
    scanf("%d",&num);
    while(num--)
    {
       int sum=0;
       int flag=0;
       for(int i=0;i<N;i++)
       {
           cin>>c;
           p[i].Count=ha[c];
           cin>>p[i].s;
           sum+=p[i].Count * p[i].s.length();
           if(p[i].s.length() > N-1)
           {
               flag=1;
           }
       }
       if(flag)
       {
           cout<<"No"<<endl;
           continue;
       }
       else if(check() && sum == wpl)
            cout<<"Yes"<<endl;
       else
            cout<<"No"<<endl;
    }
}



所以改用一个最小堆来实现这个哈弗曼树,定义 struct treenode 为树的节点,定义struct heapnode  为堆,创立一个最小堆,先取出一个最小值的节点为左节点 ,在取一个最小值为右节点,然后把左右节点的和的节点再放入最小堆,循环反复,就可以生成哈弗曼树。然后再判定一下前缀码,即当在一个图中,遍历到这一节点时,该节点不能曾经被遍历过,然后遍历到最后一个节点时,该节点不能再有左右子节点。即所有存信息的节点为叶子节点。

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<queue>
#include<algorithm>
#include<map>
#include<vector>
#include<cstring>
#include<math.h>
#include<stack>
#include <string>
using namespace std;
#define maxnum 64

struct treenode//树的节点
{
    int weight=0;
    treenode *left=NULL;
    treenode *right=NULL;
};
struct heapnode//堆
{
    treenode data[maxnum];
    int Size=0;
};
heapnode* createheap(int N)//创建一个小根堆
{
    heapnode *H= new(heapnode);
    H->data[0].weight= -1;
    return H;//返回指向小根堆堆首的元素
}
treenode* deletemin(heapnode *H)//传入指向小根堆堆首的元素,从堆中删除一个元素
{
    int parent=0,child=0;
    treenode temp;
    treenode *minitem= new(treenode);
    *minitem = H->data[1];

    temp= (H->data[(H->Size)--]);

    for(parent=1; parent*2 <= H->Size ; parent=child)
    {
        child= parent*2;
        if((child !=H->Size ) && (H->data[child].weight) > (H->data[child+1].weight))
        {
            child++;
        }
        if((temp.weight) <= H->data[child].weight)
        {
            break;
        }
        else
        {
            H->data[parent] = H->data[child];
        }
    }
    H->data[parent]=temp;
    return minitem;//返回指向最小堆的头节点的指针
}

void Insert(heapnode *H,treenode *item)
{
    int i=0;
    i=++(H->Size);
    for( ; H->data[i/2].weight > item->weight ;i/=2)
    {
        H->data[i]= H->data[i/2];
    }
    H->data[i]= *item;
}

heapnode* readdata(int N,heapnode *H,int A[])
{
    char s='\0';
    int value= 0;
    for(int i=0;i<N;i++)
    {
        cin>>s;
        cin>>value;
        A[i]= value;
        treenode *T= new(treenode);
        T->weight= value;
        Insert(H,T);
    }
    return H;
}

treenode* huffman(heapnode *H)
{
    treenode *T=NULL;
    int num= H->Size;
    for(int i=0;i<num-1;i++)
    {
        T=new(treenode);
        T->left= deletemin(H);
        T->right= deletemin(H);
        T->weight= T->left->weight + T->right->weight;
        Insert(H,T);
    }
    T=deletemin(H);
    return T;
}

int wpl(treenode *T,int depth)//depth代表深度 , 此函数计算wpl
{
    if(T->left==NULL && T->right==NULL)
    {
        return depth * T->weight;
    }
    else
    {
        return ( wpl(T->left,depth+1) + wpl(T->right,depth+1) );
    }
}

struct JNode
{
    int Flag=0;
    JNode *Left=NULL;
    JNode *Right=NULL;
};

bool Judge(string s,JNode *j)//判断该次编码能否符合前缀编码的要求
{
    int i=0;
    for( ; i<s.length() ; i++)
    {
        if(s[i]== '0')
        {
            if( j->Left==NULL )//如果左边不存在节点
            {
                JNode *j_1=new(JNode);
                j->Left=j_1;
            }
            else
            {
                if(j->Left->Flag==1)
                {
                    return false;
                }
            }
            j=j->Left;
        }
        else
        {
            if(j->Right==NULL)
            {
                JNode *j_1=new(JNode);
                j->Right=j_1;
            }
            else
            {
                if(j->Right->Flag==1)
                {
                    return false;
                }
            }
            j=j->Right;
        }
    }
    j->Flag=1;
    if(j->Left==NULL && j->Right==NULL )
    {
        return true;
    }
    else
    {
        return false;
    }
}

int main()
{
    int n=0,N=0;
    cin>>N;
    heapnode *H= createheap(N);//创立最小堆H
    int Value[maxnum]={};
    H=readdata(N,H,Value);

    treenode *T= huffman(H);//建立一棵哈弗曼树T

    int codelen=wpl(T,0);

    cin>>n;
    string temp="\0";
    char c='\0';
    bool result=false;

    for(int i=0;i<n;i++)
    {
        int Count=0,flag=0;
        JNode *j=new(JNode);
        for(int k=0;k<N;k++)
        {
            cin>>c>>temp;
            Count+= temp.length() * Value[k];
            if(!flag)
            {
                result=Judge(temp,j);
                if(!result)
                {
                    flag=1;
                }
            }
        }
        delete j;
        if(result && Count==codelen)
        {
            cout<<"Yes"<<endl;
        }
        else
        {
            cout<<"No"<<endl;
        }
    }
}



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值