Huffman树编码(数据结构)

本文介绍了一种使用Huffman树进行二进制前缀编码的方法,并提供了完整的C++实现代码。通过构造Huffman树并遍历它来为给定的字符集生成最优的编码方案,实现了电文总长最短的目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Huffman树的典型应用是用于二进制编码

可以利用二叉树来设计二进制的前缀编码,约定左分支表示字符“0”,右分支表示字符“1”,为得到电文总长最短的二进制前缀编码就可以利用Huffman树来解决

代码如下:

#include"Huffman.cpp"
#include"StackLink.cpp"
typedef char **HuffmanCode;//动态分配数组空间存储Huffman树编码
void HuffmanCoding(HuffmanTree HT,HuffmanCode &HC,int n);
void Coding(HuffmanTree T,HuffmanCode &HC,int i,LinkStack &s);
void HCTraverse(HuffmanCode HC,int n);
int main()
{
    int n;
    printf("n=");
    scanf("%d",&n);
    HuffmanTree HT;
    CreateHuffmanTree(HT,n);
    HTreeTraverse(HT,n);
    HuffmanCode HC;
    HuffmanCoding(HT,HC,n);
    HCTraverse(HC,n);
    return 0;
}

void HuffmanCoding(HuffmanTree HT,HuffmanCode &HC,int n)
{
    //先序遍历Huffman树HT,求得树上n个叶子结点的编码存入HC
    LinkStack S;
    HC=new char* [n];
    InitStack_L(S);//初始化栈空间
    Coding(HT,HC,HT.root,S);
}
void Coding(HuffmanTree T,HuffmanCode &HC,int i,LinkStack &S)
{
    if(i>=0)
    {
        if((T.HTree[i].lchild==-1)&&(T.HTree[i].rchild==-1))
        {
            HC[i]=new char[StackLength_L(S)+1];
            StackCopytoArray_L(S,HC[i]);//从栈低到栈顶将栈中字符复制到HC[i]中

        }
        else
        {
            ElemType e;
            Push_L(S,'0');
            Coding(T,HC,T.HTree[i].lchild,S);
            Pop_L(S,e);
            Push_L(S,'1');
            Coding(T,HC,T.HTree[i].rchild,S);
            Pop_L(S,e);
        }
    }
}

void HCTraverse(HuffmanCode HC,int n)
{
    int i;
    cout<<"The code is:"<<endl;
    for(i=0;i<n;i++)
         cout<<HC[i]<<endl;
}

Huffman.cpp

#include<stdio.h>
#include<memory.h>
#include<iostream>
using namespace std;
typedef struct
{
    int weight;
    int lchild,rchild;
}HTNode;
typedef struct
{
    HTNode *HTree;//动态分配数组存储树结点
    int root;//根结点的位置
}HuffmanTree;
int arr[100]={0};//标志变量用来标记结点是否已经访问过
int select(HTNode *HTree,int n)
{
    int s=0,i;
    while(arr[s]==1)
        s++;
    for(i=s;i<=n;i++)
    {
        if(HTree[i].weight<HTree[s].weight&&arr[i]==0)
        {
            s=i;
        }
    }
    arr[s]=1;
    return s;
}
void CreateHuffmanTree(HuffmanTree &HT,int n)
{
    if(n<=1)
        return ;
    int m=2*n-1;
    //int *arr,i;
    //arr=new int[m];//标志变量用来标记结点是否已经访问过
    int i;
    memset(arr,0,sizeof(arr));
    HT.HTree=new HTNode[m];
    printf("Elem:");
    int temp;
    for(i=0;i<n;i++)
    {
        scanf("%d",&temp);//输入n个权值
        HT.HTree[i].weight=temp;
        HT.HTree[i].lchild= HT.HTree[i].rchild=-1;//n个带权结点形成初始化森林,每个结点的左右之树为空
    }
    for(;i<m;i++)
    {
        HT.HTree[i].weight=0;
        HT.HTree[i].lchild= HT.HTree[i].rchild=-1;//初始化尚未使用的结点
    }
    int s1,s2;
    for(i=n;i<m;i++)
    {
        s1=select(HT.HTree,i-1);//s1,s2是当前最小的两个结点
        s2=select(HT.HTree,i-1);
        HT.HTree[i].lchild=s1;
        HT.HTree[i].rchild=s2;
        HT.HTree[i].weight=HT.HTree[s1].weight+HT.HTree[s2].weight;//取左右结点树根结点权值之和
    }
    HT.root=m-1;
}
void HTreeTraverse(HuffmanTree &HT,int n)
{
    printf("**************************************************\n");
    cout<<"weight"<<'\t'<<"lchild"<<'\t'<<"rchild"<<endl;
    for(int i=0;i<2*n-1;i++)
    {
         cout<<HT.HTree[i].weight<<'\t'<<HT.HTree[i].lchild<<'\t'<<HT.HTree[i].rchild<<endl;
    }
}
int main()
{
    int n;
    printf("n=");
    scanf("%d",&n);
    HuffmanTree HT;
    CreateHuffmanTree(HT,n);
    HTreeTraverse(HT,n);
    return 0;
}

StackLink.cpp:

//链栈,链栈中指针的方向是从栈顶指向栈底
#include<stdio.h>
#include<cstring>
#include<iostream>
using namespace std;
typedef char ElemType;
struct LNode
{
	ElemType data;
	struct LNode  *next;
};//S为栈顶指针
typedef LNode *LinkStack;
void InitStack_L(LinkStack &S)
{
	S=NULL;
}
void Push_L(LinkStack &S,ElemType e)
{
	LinkStack p;
	p=new LNode;
	p->data=e;
	p->next=S;
	S=p;
}
bool Pop_L(LinkStack &S,ElemType &e)
{
	if(S)
	{
		LinkStack p=S;
		S=S->next;
		e=p->data;
		delete p;
		return true;
	}
	return  false;

}
int StackLength_L(LinkStack S)
{
    LinkStack p;
    p=S;
    int i=0;
    while(p)
    {
        i++;
        p=p->next;
    }
    return i;
}
void StackCopytoArray_L(LinkStack S,char *arr)
{
    LinkStack p=S;
    int n=StackLength_L(S);
    arr[n]='\0';
    n--;
    while(p)
    {
        arr[n]=p->data;
        n--;
        p=p->next;
    }
}

过程如下:(由于Huffman中挑选最小的两个结点的顺序不尽相同所以最后得到的编码不完全相同,但是编码的长度是相同的)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值