哈夫曼树的建立

 

一、实验目的

  1. 理解哈夫曼树及其应用。
  2. 掌握生成哈夫曼树的算法。

二、实验原理

哈夫曼树,即最优树,是带权路径长度最短的树。有着广泛的应用。在解决某些判定问题上,及字符编码上,有着重要的价值。

构造一棵哈夫曼树,哈夫曼最早给出了算法,称为哈夫曼算法:

(1)根据给定的N个权值   W1,W2,W3,……,Wn    ,构成N棵二叉树的集合F=     T1,T2,T3,……,Tn      ,其中每棵二叉树T1只有一个带权为Wi的根结点,其左右子树均空。

(2)在 F中选出两棵根结点权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的权值为其左右子树上的根结点的权值之和。

(3)在F中删除这两棵树,同时将新得到的加到F之中。重复(2)和(3),直至F中只剩一个为止。


#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define MAXSIZE 100

#include<stdio.h>
#include<malloc.h>
#define MAXSIZE 100
typedef struct HTnode
{  
     int weight;
     int parent,lchild,rchild;
}STKzone;
typedef STKzone *STK,*stack;

typedef char **huffman;
STK HT,tree,tree1;
 int a[20][20],count;
STK creat(){
    int ye,number,quanzhi,shu1,shu2,shu3,i,jie,biao=0,min1=0,min2=1,j,k=0;
//ye代表叶子的数目nnumber代表 需要开辟多少个空间quanzhi需要输入的叶子的权值
//shu1代表第一个最小的数shu2代表第二个最小的数shu3代表shu1+shu2的和
//min1,min2代表第一个最小数的下标,第二个最小数的下标
    printf("\n赫夫曼树的建立:\n");
    printf("请输入权值(叶子)数目:");
    scanf("%d",&ye);
    while(ye<1){
        printf("\n输入错误,请重新输入权值数目:");
        scanf("%d",&ye);
        printf("\n");
    }
    if(ye==1){
        printf("\n只有一个权值,无须建立赫夫曼树!\n");
    }else{
        number=ye*2-1;//需要开辟空间的数目
        tree=(struct HTnode *)malloc(number*sizeof(struct HTnode));//开辟空间
        printf("\n 输入 %d权值(=>0),建立赫夫曼树:\n",ye);
        count=ye;//编码用到
        for(i=0;i<ye;i++){
            scanf("%d",&quanzhi);//输入权植
            while(quanzhi<=0){//全职小于0,重新输入
                printf("\n 权值错(=>0),重新输入此权值:\n");
                scanf("%d",&quanzhi);
            }
        


            
            (tree+i)->weight=quanzhi;//给叶子的权值赋值
            (tree+i)->parent=0;
            (tree+i)->lchild=0;
            (tree+i)->rchild=0;
            biao=i;//biao 用来记当前链表中用了几个节点
        }
    }
 
    int wo1,wo2;
    

    while(true){//while start1
        for(i=0;i<=biao;i++)//找第一个最小的数
        {
            
            if(((tree+i)->parent)==0){//如果其父不为0,说明该节点已有父节点,则跳过该节点
            
                if((tree+min1)->weight>(tree+i)->weight){
                    min1=i;//把最小的数的下表给min1


                }
            }
        }

        if(min1==min2){//判断min1和min2是不是同一个位置的数
                
            (tree+min1)->parent=-1;//如果min1和min2是同一个数,则把min1的父等于-1
            
            for(i=0;i<=biao;i++)//寻找第二个最小的数
            {
            
                if((tree+i)->parent==0){
                    min2=i;
                    
                    break;
        
        
                }
            }




        }else{//如果而这下标不想等的话,执行下面代码
        
            for(i=0;i<=biao;i++)
            {
                if((tree+i)->parent==0){
            
                    if((tree+min2)->weight>(tree+i)->weight&&min1!=i){
                        min2=i;
    
                    }
                }
            }
        }
        biao=biao+1;//因为链表中多了一个数据所以要+1
        shu1=0;shu2=0;//为shu1和shu2初始化
        wo1=0;wo2=0;//标志位,用来判断shu1和shu2书否被赋值
        for(i=0;i<=biao;i++){
            
            if(min1==i){
                shu1=(tree+min1)->weight;//给shu1赋值
                
                wo1=1;
            }
            if(min2==i&&min1!=min2){
                shu2=(tree+min2)->weight;//给shu2赋值
                wo2=1;

            }

            if(wo1==1&&wo2==1){
            
                shu3=shu1+shu2;
                
                (tree+biao)->weight=shu3;//该节点就是两个最小节点的父节点
                (tree+biao)->lchild=min1;//把最小值的下表给父节点的lchild
                (tree+biao)->rchild=min2;
                
                (tree+biao)->parent=0;//由于父节点现在还没有父节点,所以暂时=0
                (tree+min1)->parent=biao;
                (tree+min2)->parent=biao;//把父节点的下标给孩子
                
                
                break;            
            
            
            
            
            }
            
        }
        min1=0;
        min2=1;

        for(i=0;i<=biao;i++)//为了给min1初始化
        {
            
            if((tree+i)->parent==0){
                min1=i;
                
                break;
        
        
            }
        }
        for(i=0;i<=biao;i++)//为了给min2初始化
        {
            if((tree+i)->parent==0&&min1!=i){
            
            
                    min2=i;
                        
                
                
                
            }
        }            
    
        if(biao==number-1){//如果链表满了就跳出循环 ,结束
            
            break;    
        }
    }//while end1


    return tree;
}



 void huffmancode(){
    int i=0,start=0,c,f;
    huffman HC;
    char *cd;
    for(i=0;i<2*count-1;i++){
        printf("----%d---%d---%d---%d--\n",(tree+i)->parent,(tree+i)->lchild,(tree+i)->rchild,(tree+i)->weight);
    }

    HC=(huffman)malloc(count*sizeof(char *));
    cd=(char *)malloc(count*sizeof(char));
    cd[count-1]='\0';
    for(i=0;i<count;++i){//因为从叶子节点开始查找,所以循环的次数就等于叶子数
        start=count-1;
        for(c=i,f=(tree+i)->parent;f!=0;c=f,f=(tree+f)->parent)//循环结束的条件是f=0;
            if((tree+f)->lchild==c)
                cd[--start]='0';
            else
                cd[--start]='1';
        HC[i]=(char *)malloc((count-start)*sizeof(char));//开辟一个空间哈夫曼编码那么长的空间
        strcpy(HC[i],&cd[start]);//把cd里面的数据给hc
    
    }
    printf("\n对应的二进制赫夫曼编码为:\n");
    for(i=0;i<count;++i){
        printf("%s",*(HC+i));
       printf("   ");
      }



}
    
int main()
{
    
    tree1=creat();
    huffmancode();
   
    return 0;
}/*main_end*/

posted @ 2018-06-26 08:54  会飞的猪仔  阅读(612)  评论(0编辑  收藏  举报