1. 程式人生 > >資料結構 哈夫曼樹的建立

資料結構 哈夫曼樹的建立

實驗4 哈夫曼樹的建立

一、實驗目的

1. 理解哈夫曼樹及其應用。

2. 掌握生成哈夫曼樹的演算法。

二、實驗原理

構造哈夫曼樹就是找帶全路徑長度最短的樹,再根據構造出來的樹找出結點對應的哈夫曼編碼

1Select()函式:從無雙親的結點中選出權值最小的一個

實現步驟:先假設一個無雙親的結點k為最小結點,接著遍歷所有無雙親的結點,只要檢查到某個結點的權值比當前結點k的權值更小,就把這個更小的結點設為最小結點k,所以最後得到的K就是最小權值結點

2main()函式:

1、輸入合法權值

2、給(2*l-1)個結點初始化

3、運用Select()函式來構造哈夫曼樹

4、根據構造好的哈夫曼樹找到每個葉子結點對應的哈夫曼編碼(從葉子結點到

根節點,每走一步找一個編碼)

三、參考程式

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#define LEN sizeof(struct HTnode)

int i,l,n,w=0,c,start,a1,a2,f;

struct HTnode {

unsigned int weight;

unsigned int parent,lchild,rchild;

}*p,*HT;

typedef char **Huffmancode;

Huffmancode HC;

char *cd;

//選出當前權值最小的結點

select(){

int k=1,j,flag=0;//k一直記錄當前最小值

  while((HT+k)->parent!=0) k++;

  for(j=k+1;j<=n;j++,flag=0){

  if((HT+j)->parent!=0) flag=1;

    if((HT+j)->weight==0) flag=1;

    if(!flag) {

   if((HT+j)->weight<(HT+k)->weight)

    k=j;

}

        return(k);

    }

}

main(){

printf("\n赫夫曼樹的建立

:\n");

  printf("請輸入權值(葉子)數目:");

  scanf("%d",&l);

  while(l<1) {printf("輸入錯誤,請重新輸入權值數目:"); scanf("%d",&l); }

  if(l==1) printf("\n只有一個權值,無須建立赫夫曼樹!");

  else {

  n=2*l-1;

     HT=(struct HTnode*)malloc((n+1)*LEN);

        printf("請按對應順序輸入權值(輸入一權值,鍵入一回車):\n");

for(i=1,p=HT+1;i<=l;++i,++p){//1~l是葉節點,給葉節點輸入權值

scanf("%d",&w);

  while(w<=0){printf("權值錯,重新輸入此權值:"); scanf("%d",&w);}

  p->weight=w; p->parent=0;

    p->lchild=0; p->rchild=0;

}

for(i=l+1;i<=n;++i,++p){//l+1~n為雙親結點初始化

p->weight=0; p->parent=0;

p->lchild=0;

       }

//構造哈弗曼樹

   for(i=l+1;i<=n;++i){//構造雙親結點,選擇合適的左右結點,構造子二叉樹

        //選出當前結點中權值最小的兩個a1,a2,並把這兩個結點的雙親指定為i

    a1=select(); (HT+a1)->parent=i;

a2=select(); (HT+a2)->parent=i;

//對應的i的左右孩子設為a1,a2,且權值為兩者之和

        (HT+i)->lchild=a1;

        (HT+i)->rchild=a2;

        (HT+i)->weight=(HT+a1)->weight+(HT+a2)->weight;

    }

//為哈弗曼樹編碼

HC=(Huffmancode)malloc((l+1)*sizeof(char *));

cd=(char *)malloc(l*sizeof(char));

*(cd+(l-1))='\0';

//l個葉子結點找哈弗曼編碼

for(i=1;i<=l;++i){

start=l-1;

for(c=i,f=(HT+i)->parent;f!=0;c=f,f=(HT+f)->parent){//從葉子結點開始找對應編碼,直到從此葉子結點一直找到根節點為止

    //左結點為0,右結點為1

if((HT+f)->lchild==c) *(cd+(--start))='0';

else *(cd+(--start))='1';

//把每次得到的一位編碼組合,最後得到此結點的最終編碼

*(HC+i)=(char *)malloc((l-start)*sizeof(char));

strcpy(*(HC+i),(cd+start));

}

}

    printf("\n對應的二進位制赫夫曼編碼為:\n");

    for(i=1;i<=l;++i)

      {printf("%s",*(HC+i));

       printf("   ");

      }

   }

}