二叉树の哈夫曼树构造和哈夫曼编码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxSize 100

typedef struct HTNode{//定义哈夫曼树结点
    int weight;
    int parent,lchild,rchild;
}HTNode,*HuffmanTree;

typedef char** HuffmanCode;//定义哈夫曼编码的指针类型,用二级指针管理各叶子节点对应的哈夫曼编码字符串

void Select(HuffmanTree HT,int n,int &s1,int &s2){//定义函数选出权重最小的两个结点索引s1,s2
    int min1=0,min2=0;
    for(int i=0;i<=n;i++){
        if(HT[i].parent==0){//如果当前结点i无父节点
            if(min1==0){//第一次找到无父的结点,将其索引赋给min1
                min1=i;
            }else if (min2==0){//第二次找到无父的结点,将其索引赋给min2,并调整min1指向的节点权重小于min2
                min2=i;
                if(HT[min1].weight > HT[min2].weight){
                    int temp=min1;
                    min1=min2;
                    min2=temp;
                }
            }else{//已经找到两个无父结点,继续查找比较
                if(HT[i].weight < HT[min1].weight){//如果当前找到的无父结点权重比min1小,将min1赋给min2,当前结点索引赋给min1,保证目前找到的两个小无父结点min1<min2
                    min2=min1;
                    min1=i;
                }else if(HT[i].weight < HT[min2].weight){//如果当前无父结点大于min1,小于min2,将其索引赋给min2
                    min2=i;
                }
            } 
        }
    }
    s1=min1;
    s2=min2;
}

void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int w[],int n){//构建哈夫曼树和哈夫曼编码
    if(n<=1) return;
    int m=2*n-1;//哈夫曼树结点总数
    HT=(HTNode*)malloc((m+1)*sizeof(HTNode));//分配哈夫曼树结点数组内存空间,多分配一个方便下标从1开用
    for(int i=1;i<=n;i++){
        HT[i].weight=w[i];
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
    }
    for(int i=n+1;i<=m;i++){//构建哈夫曼树
        int s1,s2;
        Select(HT,i-1,s1,s2);//选出权值最小的两个结点
        HT[i].weight=HT[s1].weight+HT[s2].weight;//新结点权重
        HT[s1].parent=i;
        HT[s2].parent=i;
        HT[i].lchild=s1;
        HT[i].rchild=s2;
    }
    HC=(HuffmanCode)malloc((n+1)*sizeof(char));//分配哈夫曼编码数组内存,存指向每个叶结点编码的指针
    char *temp=(char*)malloc(n*sizeof(char));//n个叶结点时,最长的哈夫曼编码有n-1位,此处添加一个结束符
    temp[n-1]='\0';//结束符
    int start,pos,parent;
    for(int i=1;i<=n;i++){
        start=n-1;//编码的起始位置初始化为临时编码的最后一位,结束符的位置
        pos=i;
        parent=HT[i].parent;
        while (parent!=0){//沿父结点路径回溯到根结点,直到没有父结点
            if(HT[parent].lchild==pos){
                temp[--start]='0';
            }else{
                temp[--start]='1';
            }
            pos=parent;
            parent=HT[parent].parent;
        }
        HC[i]=(char*)malloc((n-start)*sizeof(char));//给每个叶结点分配各自实际编码长度的空间
        strcpy(HC[i],&temp[start]);//将临时编码数组,从start开始复制到HC[i]
    }
    free(temp);
}

void printHTandHC(HuffmanTree HT,HuffmanCode HC,int n){//输出哈夫曼树和编码
    printf("哈夫曼树结点信息:\n");
    for(int i=1;i<=2*n-1;i++){
        printf("编号:%d,权重:%d,父:%d,左子:%d,右子:%d\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
    }
    printf("哈夫曼编码:\n");
    for(int i=1;i<=n;i++){
        printf("权重:%d,编码:%s\n",HT[i].weight,HC[i]);
    }
}

int main(){
    int n;
    int w[MaxSize];
    HuffmanTree HT;
    HuffmanCode HC;
    printf("叶结点数:");
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        printf("请输入第%d个结点的权值:",i);
        scanf("&d",&w[i]);
    }
    HuffmanCoding(HT,HC,w,n);
    printHTandHC(HT,HC,n);
    return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值