哈夫曼树凹入法输出,嵌套循环时出现空指针

Rencoci 2017-12-21 10:58:33
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>


typedef char datatype;
typedef struct
{
int weight;
datatype data;
int lchild,rchild,parent;
}hufmtree;//Huffman树的储存表示

typedef struct
{
char bits[50];
int start;
datatype data;
}codetype;//Huffman编码的储存表示

int DEPTH=0;

void CreateHUFMT(hufmtree *tree,int n,codetype *code)
{//创建huffman树,求出n个字符的huffman编码
int i,j,p1,p2,small1,small2,m;
char ch;
m=2*n-1;
for(i=0;i<m;i++)
{
tree[i].lchild=(-1); tree[i].rchild=(-1);
tree[i].parent=(-1); tree[i].weight=(-1);
tree[i].data='0';
}
for(i=1;i<=n;i++)
{
while((getchar())!='\n');
printf("请输入第%d个字符及权值(格式:字符 权值):",i);
scanf("%c %d",&tree[i-1].data,&tree[i-1].weight);
}
for(i=n;i<m;i++)
{
p1=p2=0;small1=small2=1000;
for(j=0;j<=i-1;j++)
if(tree[j].parent==(-1))
if(tree[j].weight<small1)
{small2=small1;
small1=tree[j].weight; p2=p1; p1=j;
}
else if(tree[j].weight<small2)
{small2=tree[j].weight; p2=j;}
tree[p1].parent=tree[p2].parent=i;
tree[i].lchild=p1;
tree[i].rchild=p2;
tree[i].weight=tree[p1].weight+tree[p2].weight;
}

int c,p;
codetype *cd;
cd=(codetype*)malloc(n*sizeof(codetype));
for(i=0;i<n;i++)
{
cd[i].start=n; c=i;
p=tree[c].parent;
cd[i].data=tree[c].data;
while(p!=(-1))
{
cd[i].start--;
if(tree[p].rchild==c) cd[i].bits[cd[i].start]='1';
else cd[i].bits[cd[i].start]='0';
c=p;
p=tree[c].parent;
}
for(int s=0;s<cd[i].start;s++)cd[i].bits[s]='#';
code[i]=cd[i];
}
free(cd);
}

//***************************编译码*****************************//
void Decode(hufmtree *tree,char*size,int n)
{
int i,j,k;
char p[100];
printf("请输入需要译码的代码:");
getchar();
gets(p);
i=2*n-2; k=0;
for(j=0;p[j]!='\0';j++)
{
if(p[j]=='0')i=tree[i].lchild;
else i=tree[i].rchild;
if(tree[i].lchild==(-1))
{size[k++]=tree[i].data;
i=2*n-2;
}
}
size[k]='\0';
}

void Encode(codetype code[],char*coding,int n)
{
int i,j,t,k=0;
char p[100];
printf("请输入需要编码的文本:");
getchar();
gets(p);
for(i=0;p[i]!='\0';i++)
{
if((p[i]>='A'&&p[i]<='Z')||p[i]==' ')
for(j=0;j<=n;j++)
{
if(p[i]==code[j].data)
for(t=0;code[j].bits[t]!='\0';t++)
if(code[j].bits[t]!='#')
coding[k++]=code[j].bits[t];
}
}
coding[k]='\0';
}


//******************************打印操作********************************//

void printcode(hufmtree *tree,codetype *code,int n,FILE *fp)
{
//打印字符的编码,结果存放在fp中
int i,j,t;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(code[j].data==tree[i].data)
{
fprintf(fp,"字符%c的编码:",tree[i].data);
for(t=0;code[j].bits[t]!='\0';t++)
if(code[j].bits[t]!='#')
fprintf(fp,"%c",code[j].bits[t]);
fprintf(fp,"\n");
}
}
for(j=0;j<n;j++)
{
if(code[j].data==' ')
{
fprintf(fp,"字符空格的编码:");
for(t=0;code[j].bits[t]!='\0';t++)
if(code[j].bits[t]!='#')
fprintf(fp,"%c",code[j].bits[t]);
fprintf(fp,"\n");
}
}
}
//**************************************************************************************
void inorder(hufmtree *tree,int k,FILE *fp) //问题函数
{ //函数功能是实现哈夫曼树的凹入法输出
//但是在进行嵌套循环时,tree指针好像变成了空指针 ,不知道为什么
//中序遍历并打印树,结果存放于fp中,k为根结点的下标 //求解惑
int i;
if(tree[k].rchild!=0){
DEPTH++;
inorder(tree,tree[k].rchild,fp);
DEPTH--;
}

for(i=1;i<=DEPTH;i++)fprintf(fp," ");
fprintf(fp,"%c\n",tree[k].data);

if(tree[k].lchild!=0){
DEPTH++;
inorder(tree,tree[k].lchild,fp);
DEPTH--;
}
if(tree[k].lchild&&tree[k].rchild==(-1))return;
return;
}

//***********************主函数**************************//
int main()
{
FILE *fp1,*fp2;
int n,m,j=0;
char a[50],b[50],coding[100],size[100],ch;
printf("输入字符长度:");
scanf("%d",&n);
m=2*n-2;
hufmtree *tree; codetype *code;
tree=(hufmtree*)malloc((2*n)*sizeof(hufmtree));
code=(codetype*)malloc((n+1)*sizeof(codetype));
printf("\n");
CreateHUFMT(tree,n,code);
printf("\n");
printf("请输入哈夫曼树文件存放地址:");
fp1=fopen("G:\\code\\hufmtree.txt","w+");
printf("\n");
printf("请输入字符编码文件存放地址:");
fp2=fopen("G:\\code\\hufmcode.txt","w+");
printf("\n");
inorder(tree,m,fp1);
printcode(tree,code,n,fp2);
fclose(fp1); fclose(fp2);
printf("\n");
printf("e:编码(Encode)\nd:译码(Decode)\nq:退出(Quit)\n");
printf("请输入操作:");
getchar();
ch=getchar();
printf("\n");
do
{
switch(ch)
{
case 'e':{Encode(code,coding,n);
printf("文本的哈夫曼编码是:%s\n",coding);
printf("编码完毕,请选择操作:\n");
printf("e:编码(Encode)\nd:译码(Decode)\nq:退出(Quit)\n");
break;
}
case 'd':{Decode(tree,size,n);
printf("文本的译码是:%s\n",size);
printf("译码完毕,请选择操作:\n");
printf("e:编码(Encode)\nd:译码(Decode)\nq:退出(Quit)\n");
break;
}
case 'q':exit(0);break;
default :exit(0);break;
}
ch=getchar();
}while(ch!='q');
}

上面是本人写的哈夫曼树,目的是满足下面的要求
1、从终端读入字符集大小为n(即字符的个数),逐一输入n个字符和相应的n个权值(即字符出现的频度)。并将建立好的哈夫曼树以树或凹入法形式输出;对每个字符进行编码并且输出。
2、利用已建好的哈夫曼编码文件 hfmtree ,对已编码的正文进行译码,输出译码后的正文。
3、采用文本文件存放文本,先统计文本中的每个字符出现的频率,然后再建立哈夫曼树,并进行编码和译码。
求大佬看一看Orz
...全文
966 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2017-12-22
  • 打赏
  • 举报
回复
崩溃的时候在弹出的对话框按相应按钮进入调试,按Alt+7键查看Call Stack即“调用堆栈”里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处,看不懂时双击下一行,直到能看懂为止
Rencoci 2017-12-21
  • 打赏
  • 举报
回复
//************************编码与译码操作**********************************   
void Decoding(HuffmanTree HT,hfmlist HL,char*size,int n)//这个函数是用来译码的    
    {int i,j,k;   
     char p[30];   
     printf("请输入需要译码的代码:");gets(p);//接受需要译码的字符串   
     i=2*n-1;   
     k=0;   
     for(j=0;p[j]!='\0';j++){   
         if(p[j]=='0'){ if(HT[i].lchild!=0)i=HT[i].lchild;   
                        else{   size[k++]=HL[i].letter;   
                                i=2*n-1;   
                                j--;}   
             }   
         else{  if(HT[i].rchild!=0)i=HT[i].rchild;   
                else{   size[k++]=HL[i].letter;   
                        i=2*n-1;   
                        j--;}   
             }   
     }//for   
     if( p[j-1]=='0')size[k++]=HL[i].letter;   
     else size[k++]=HL[i].letter;   
     size[k]='\0';   
  }//decoding   
void Encoding(HuffmanCode HC,hfmlist HL,char *coding,int n){   
    int i,j,t,k=0;   
    char p[100];   
    printf("请再次输入需要编码的文本:");   
    gets(p);   
    for(i=0;p[i]!='\0';i++){   
        if((p[i]>='a'&&p[i]<='z')||p[i]==' ')   
          for(j=1;j<=n;j++)   
            if(p[i]==HL[j].letter)   
              for(t=0;HC[j][t]!='\0';t++)   
                coding[k++]=HC[j][t];   
         }//for   
    coding[k]='\0';   
}//encoding   
   
//************************打印操作****************************   
void Print(FILE *fp1,FILE *fp2){   
    //将文件fp1中的代码以紧凑格式显示在终端上,每行50个代码   
    //同时将此字符形式的编码文件写入文件fp2中   
    char c[200];   
    int i;   
    fgets(c,200,fp1);   
    for(i=0;c[i]=='0'||c[i]=='1';i++){   
        printf("%c",c[i]);   
        fprintf(fp2,"%c",c[i]);   
        if((i+1)/50*50==(i+1)){   
            printf("\n");   
            fprintf(fp2,"\n");   
        }   
    }//for   
    printf("\n");   
}//Print   
//********************************************************************!!!!!!!!!!!!!   
void PreOrderTraverse(HuffmanTree HT,int k,FILE *fp){   
    //中序遍历并打印树,结果存放于fp中,k为根结点的下标   
    int i;   
                                                      //这个函数跟我自己写的函数看上去没什么差异,但是却可以正常运行 
    if(HT[k].rchild!=0){                              //百思不得其解   
        DEPTH++;   
        PreOrderTraverse(HT,HT[k].rchild,fp);   
        DEPTH--;   
    }
    
	for(i=1;i<=DEPTH;i++)fprintf(fp,"   "); 
	fprintf(fp,"%d\n",HT[k].weight); 
	
    if(HT[k].lchild!=0){   
        DEPTH++;   
        PreOrderTraverse(HT,HT[k].lchild,fp);   
        DEPTH--;   
    }   
    if(HT[k].lchild==0&&HT[k].rchild==0)return;   
    return;   
} //PreOrderTraverse   
 //********************************************************************!!!!!!!!!!!!!!!!  
void TreePrinting(HuffmanTree HT,int n,FILE *fp){   
    //打印树HT,结果存于文件fp中,n为树的叶子结点数   
    int i,k;   
    for(i=1;i<=2*n;i++)if(HT[i].parent==0){k=i;break;}//寻找根结点   
    PreOrderTraverse(HT,k,fp);   
    return;   
}//TreePrinting    
   
//**************************主函数*********************************   
int main()   
{   
    FILE *fp1,*fp2,*fp3,*fp4,*fp5;   
    HuffmanTree HT;   
    HuffmanCode HC;   
    hfmlist HL;   
    
    unsigned int i,n;   
    char  *b,c[100],cha,ch;   
   
    b=(char *)malloc(100*sizeof(char));   
    printf("请选择操作:\n");   
    printf("i:初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");   
    printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");b=(char *)malloc(100*sizeof(char));   
    HL=(hfmlist)malloc(30*sizeof(hfm));//存储字符与权值,线性表长30   
    printf("\n");   
    printf("选择操作(i,e,d,p,t,q):");   
    ch=getchar();   
    getchar();   
    printf("\n");   
    do{   
      switch(ch){   
        case 'i':printf("正在进行初始化……\n");   
                 printf("输入字符长度:");   
                 scanf("%d",&n);   
                 getchar();   
                 printf("\n");   
                 HC=(HuffmanCode)malloc((n+1)*sizeof(char));   
                 HT=(HuffmanTree)malloc((2*n)*sizeof(HTNode));   
                 for(i=1;i<=n;i++){   
                     printf("请输入第%d个字符及权值(格式:字符 权值):",i);   
                     scanf("%c %d",&(HL+i)->letter,&(HL+i)->wt);   
                     getchar();                    
                 }//for   
                 if((fp5=fopen("G:\\code\\hufmtree.txt","w+"))==NULL){   
                     printf("cannot open file!\n");   
                     exit(0);   
                 }//if   
                 for(i=1;i<=n;i++){   
                     fprintf(fp5,"第%d个字符及权值:\t\t\t",i);   
                     fprintf(fp5,"%c %d\n",(HL+i)->letter,(HL+i)->wt);   
                 }//for   
                 fclose(fp5);   
                 HuffmanCoding(HT,HC,HL,n);   
                 printf("\n已经将Huffman树存入文件hfmTree.txt中\n\n");   
                 printf("初始化完毕,请选择操作:\n");   
                 printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");   
                 printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n\n");   
                 break;   
        case 'e':   
                 printf("请输入编码,以#结尾:");   
                 if((fp2=fopen("ToBeTran.txt","w"))==NULL){   
                         printf("cannot open file\n");exit(0);   
                 }//if   
                     cha=getchar();   
                 while(cha!='#')   
                 {   
                      fputc(cha,fp2);   
                      cha=getchar();   
                 }//while   
                 getchar();   
                 fclose(fp2);    
                   
                 printf("已经把编码存入文件ToBeTran.txt中\n\n");   
                 Encoding(HC,HL,b,n);   
                 printf("文本的哈夫曼编码是:");    
                 printf("%s\n",b);   
                 printf("下面进行保存:");   
                 save(b);   
                 printf("编码完毕,请选择操作:\n");   
                 printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");   
                 printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");   
                 break;   
        case 'd':   
                 Decoding(HT,HL,c,n);   
                 printf("输入要译码的编码:");   
                 printf("正在进行译码……\n");   
                 printf("%s\n",c);   
                 save(c);   
                 printf("已经将结果存入文件%s中\n",a);   
                 printf("译码完毕,请选择操作:\n");   
                 printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");   
                 printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");                
                 break;   
        case 'p':   
                 for(i=1;i<=n;i++)   
                    printf("字符:%c\t\t\t译码:%s\n",HL[i].letter,HC[i]);   
                 if((fp1=fopen("CodePrin.txt","w"))==NULL){   
                      printf("cannot open the file!\n");   
                      exit(0);   
                 }//if   
                    
                 if((fp4=fopen("CodeFile.txt","r"))==NULL){   
                     printf("cannot open the file!\n");   
                     exit(0);   
                 }//if   
                 Print(fp4,fp1);   
                 printf("该代码文件已经存在并命名为CodePrin.txt\n");   
                 fclose(fp4);   
                 fclose(fp1);   
                 break;   
        case 't':printf("打印树存在于文件TreePrin中\n");   
                 if((fp3=fopen("G:\\code\\hufmtree.txt","w+"))==NULL)   
                 {printf("cannot open file\n");exit(0);}   
                 TreePrinting(HT,n,fp3);   
                 fclose(fp3);   
                 break;   
        case 'q':exit(0);break;   
        default :exit(0);break;   
      }//switch   
      printf("\n请选择操作(i,e,d,p,t,q):");   
      ch=getchar();   
      getchar();   
    }while(ch!='q');//do   
}
接上面的
Rencoci 2017-12-21
  • 打赏
  • 举报
回复
#include <string.h>   
#include <stdio.h>   
#include <stdlib.h>   
#include <malloc.h>   
   
typedef struct {   
    char letter;   
    int  wt;   
}hfm,*hfmlist;   
   
//*************************全局变量************************************   
unsigned int s1,s2,n;   
char choose;   
int DEPTH=0;   
char a[20];   
   
//***************Huffman树和Huffman编码的存储表示**********************   
typedef struct{   
    unsigned int weight;   
    unsigned int code;   
    unsigned int parent,lchild,rchild;   
}HTNode, *HuffmanTree;           //动态分配数组存储Huffman树   
typedef char * *HuffmanCode;     //动态分配数组存储Huffman编码表   
   
//***************************初始化Huffman树***************************   
void select(HuffmanTree HT,int l){   
    int a,b,c,j;   
    s1=s2=1;   
    a=b=1000;   
    for(j=1;j<=l;j++){   
        if(HT[j].code==0){   
          c=HT[j].weight;   
          if(c<a){b=a;a=c;s2=s1;s1=j;}   
          else if(c<b){b=c;s2=j;}   
             }//if   
        }//for   
    HT[s1].code=HT[s2].code=1;   
    }//select   
   
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC, hfmlist HL,unsigned int n){   
    //w存放n个权值(均>0),构造Huffman树HT,并求出n个字符的Huffman编码HC.   
    unsigned int i,f,start,c,m;   
    char*cd;   
           
    if (n<=1) return;   
    m =2*n-1;   
    HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));    
    for(i=1;i<=m;++i){HT[i].weight=HT[i].parent=HT[i].lchild=HT[i].rchild=HT[i].code=0;}   
    for(i=1;i<=n;++i)HT[i].weight=HL[i].wt;   
    for (i=n+1;i<=m;++i){   
        select(HT,i-1);   
        HT[s1].parent=i;HT[s2].parent=i;   
        HT[i].lchild=s1;HT[i].rchild=s2;   
        HT[i].weight=HT[s1].weight+HT[s2].weight;   
    }   
   
    HC=(HuffmanCode)malloc((n+1)*sizeof(char*));   
    cd=(char*)malloc(n*sizeof(char));   
    cd[n-1]='\0';   
    for(i=1;i<=n;++i){   
        start=n-1; 
        for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)   
            if (HT[f].lchild==c) cd[--start]='0';   
            else cd[--start]='1';   
        HC[i]=(char*)malloc((n-start)*sizeof(char));   
        strcpy(HC[i],cd+start);   
    }   
    free(cd);   
}   
   
//*************************文件操作*****************************   
void save (char *p){   
      FILE *fp;   
      int i;   
         
      printf("input the name:");   
      if((fp=fopen(gets(a),"w+"))==NULL){   
          printf("cannot open the file!\n");   
          exit(0);}//if   
      for(i=0;p[i]!='\0';i++){   
          if(fwrite(p+i,sizeof(char),1,fp)!=1){//fwrite函数写数据块   
              printf("File write error!\n");exit(0);}//if   
      }//for   
      fclose(fp);   
}//save   
这个是我在网上找到的类似的代码,但是这个代码可以正常运行,不知道我跟这个的区别在哪里

70,037

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧