哈夫曼编码 C语言实现

C语言实现哈夫曼编码

程序功能:提供一段字符串,输出哈夫曼编码压缩后的总比特数(计入小写字母和空格)

#include<stdio.h>
#include<malloc.h>
//定义二叉树结构
typedef struct Node
{
int data;
struct Node * LChild;
struct Node * RChild;
}BiTNode, *BiTree;
//定义栈结构,此处的栈用来储存二叉树节点
typedef struct{
    BiTree elem[30];
    int top;
}stack;
//操作栈的方法
void initStack(stack *s)
{
    s->top=-1;
}
void Push(stack *s,BiTree a)
{
    s->top++;
    s->elem[s->top]=a;
}
BiTree Pop(stack *s)
{
    s->top--;
    return s->elem[s->top+1];
}
//把数变成节点并入栈,便于后续操作
stack forest(int *arr,int length)//入栈跟数组顺序是反的
{
    stack s;
    initStack(&s);
    for(int i=0;i<=length-1;i++)
    {
        //写sizeof(*BiTNode))或者sizeof(BiTree)会卡死,猜想申请的内存不够,*BiTNode比BiTNode小
        //C语言这种访问底层内存的程序太不好把握了
        BiTree tree=(BiTree)malloc(sizeof(BiTNode));
        tree->data=arr[i];
        tree->LChild=tree->RChild=NULL;
        Push(&s,tree);
    }
    return s;
}
void sortStack(stack *s)//让栈中顶部元素小底部元素大
{
    BiTree temp;
    for(int i=0;i<=s->top-1;i++)
    {
        for(int j=0;j<=s->top-1;j++)
        {
            if(s->elem[j]->data<s->elem[j+1]->data)
            {
                temp=s->elem[j];
                s->elem[j]=s->elem[j+1];
                s->elem[j+1]=temp;
            }
        }
    }
}
BiTree buildTree(stack *s)
{
    while(s->top>0)//栈只有一个元素时结束
    {
        //栈顶两个出栈
        BiTree m1=Pop(s);
        BiTree m2=Pop(s);//不知道为什么不能加&了,难道是传进来的本身是指针的缘故?
        BiTree m=(BiTree)malloc(sizeof(BiTNode));
        m->data=m1->data+m2->data;
        m->LChild=m1;
        m->RChild=m2;
        //将新节点入栈
        Push(s,m);
        //让栈排序
        sortStack(s);
    }
    return s->elem[s->top];
}
//先序遍历,用于测试生成树的结果
void inOrder(BiTree tree)
{
    if(tree!=NULL)
    {
        printf("%d ",tree->data);
        inOrder(tree->LChild);
        inOrder(tree->RChild);
    }
}
//用来记录最后的和,不得已的全局变量,实在不知道如果传进去该怎么搞
int sum=0;
//先序遍历的一个变形
void caculation(BiTree tree,int step)
{
    if(tree!=NULL)
    {
        if(tree->RChild==NULL&&tree->LChild==NULL)//判断是否是叶子节点
        {
            sum+=tree->data*step;
            //printf("%d += %d * %d\n",sum,tree->data,step);
        }
        //每走一步带权路径应该加一
        caculation(tree->LChild,step+1);
        caculation(tree->RChild,step+1);
    }
}
int dealString(char *s,int *arr)
{
    int count=0;//统计字母个数
    int num[27]={0};//存放每个字母的个数,a对应0,多出来的一个放空格
    for(int i=0;s[i]!='\0';i++)
    {
        if(s[i]==' ')//遇到空格也算一个
        {
            if(num[26]==0)
            {
                count++;
            }
            num[26]++;
            continue;//后面的不应该执行了
        }

        if(num[s[i]-97]==0)//如果这个字母从未出现过
        {
            count++;
        }
        //a的ASCII码是97
        num[s[i]-97]++;
    }
    for(int i=0,j=0;i<=26;i++)//把数组转移到arr里去
    {
        if(num[i]!=0)
        {
            arr[j]=num[i];
            j++;
        }
    }
    int temp;
    for(int i=0;i<=count-2;i++)//给arr冒泡排序,使其降序
    {
        for(int j=0;j<=count-2;j++)
        {
            if(arr[j]<arr[j+1])
            {
                temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
        }
    }
    return count;
}
int main()
{
    //请确保数组降序
    int arr[30];
    //测试用的字符串
    char str[]="shaonianyi cchyi";
    //length是有效数组长度,也就是除了0以外的
    int length=dealString(str,arr);
    //把数组变成森林存到栈里
    stack s=forest(arr,length);
    //构造哈夫曼树
    BiTree root=buildTree(&s);
    //计算带权路径,也就是哈夫曼编码的最短位数
    caculation(root,0);
    printf("WPL=%d",sum);
    //inOrder(root);
}


作者:少年弈 转载请声明

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值