//已更改,之前是Select函数存在问题 选出的s1与s2大小不定,故结果显示不唯一。
#include <stdio.h> #include <string.h> #define ERROR 0 #define OK 1 #define Status int #define N 1050 /* 构造赫夫曼树:n个初始结点,则赫夫曼树中会存在2n-1个结点,0号位置不使用的情况下,共需要2n个结点; 思想: 1、初始化:将所有的单元中的双亲及其左右孩子的结点坐标都初始化为0;再输入前n个结点的值 2、通过n-1次的选择、删除、合并来创建赫夫曼树: 选择:从之前的所有结点中选择双亲为0,并且其权值为最小的两个;(这里构造一个Select函数来进行选择,选择结果放入s1与s2中) 删除:将选中的两个结点的双亲改为非0; 合并:将s1和s2的权值相加,作为一个新的结点权值,依次存入到数组的第n+1之后的单元中,同时记录这个新结点的左右孩子分别为s1,s2;并且双亲结点为0; */ /* 赫夫曼树的应用:赫夫曼编码: 选择最优前缀编码的一种形式; 另外,赫夫曼编码的实现是建立在已有赫夫曼树的基础上的; 思想: 从结点开始向根结点回溯,将数据倒叙临时存入一个一维数组中cd;start记录编码在cd中的起始位置; 当到最终的根结点时,将cd中的变法复制到该字符相应的编码串中; */ //结点类型: typedef struct LNode { int number; int parent,l,r; }LNode,*LinkList; void Select(LNode f[],int t,int &s1,int &s2) { //在前i-1个元素中选择出两个权值最小的;并且其双亲值为0; int tt=1,m; for(int i=1;i<=t;i++) if(f[i].parent==0) { if(tt==1) {s1=i;tt++;m=i;} else {s2=i;break;} } for(int i=1;i<=t;i++) if(f[i].number<f[s1].number && f[i].parent==0) s1=i; if(s1==s2) s2=m; for(int i=1;i<=t;i++) if(i!=s1 && f[i].number<f[s2].number && f[i].parent==0) s2=i; if(s1>s2) {int t=s1;s1=s2;s2=t;} } void Creat(LinkList &L,int n) { //构造赫夫曼树:需要提前输入n个结点的值得大小; int m,i; m=2*n; L = new LNode[m]; for(i=1;i<m;i++) {L[i].number=0;L[i].l=0;L[i].r=0;L[i].parent=0;}//初始化开设的数组; for(i=1;i<=n;i++)//输入前n个元素; scanf("%d",&L[i].number); //我是一个万恶的分割线--------------------------------------初始化工作完毕! for(i=n+1;i<m;i++) { int s1=1,s2=1; Select(L,i-1,s1,s2); //从数组L中的前i-1个中选择出来两个; L[i].parent=0;L[i].l=s1,L[i].r=s2; L[s1].parent=i;L[s2].parent=i; L[i].number=L[s1].number+L[s2].number; //新生节点的权值为左右孩子权值之和; } } //根据赫夫曼树构造赫夫曼编码: void Creat1(char HC[100][100],LinkList &L,int n) { //HC是新建的字符数组,用来存生成的每个编码; //L是之前创造好的郝夫曼树一维数组; /*HC = new char *[n+1];*/ char *cd = new char[n];cd[n-1]='\0';//编码结束符; int i,j,start; for(i=1;i<=n;i++) { start=n-1; int c=i,f=L[i].parent; while(f!=0) { start--; if(L[f].l==c) cd[start]='0'; else cd[start]='1'; c=f;f=L[f].parent; } /*HC[i]=new char[n-start];*/ strcpy(HC[i],&cd[start]); //int p=0; //for(j=start;j<n;j++) // HC[i][p++]=cd[j]; } } int main() { int i,j,k,n; printf("请输入一个数字n:代表需要提前输入n个结点的权值:\n");scanf("%d",&n); //创建赫夫曼树; LinkList L; Creat(L,n); // char HC[100][100]; Creat1(HC,L,n); for(i=1;i<2*n;i++) { printf("%s\n",HC[i]); } return 0; }