數據結構哈夫曼樹中每次尋找的最小結點和次小結點穩定在二到四個結點中產生


原理:

      給定n個權值作為n個葉子結點,構建一棵二叉樹,若帶權值路徑長度達到最小,稱這樣的二叉樹為哈夫曼樹。
Huffman樹是一種特殊的二叉樹,其葉結點的編碼是一種前綴碼,同時,通過統計字符的頻度,能夠達到編碼電文的最小化。
假設有n個權值,則構造出的哈夫曼樹有n個葉子結點。n個權值分別設為w1、w2、···、wn,則哈夫曼樹的構造規則為:
(1) 將w1、w2、···、wn看成有n棵樹的森林(每棵樹僅有一個結點);
(2) 在森林中選出兩個根結點的權值最小的樹合並,作為一棵新樹的左、右子樹,且新樹的根結點權值為其左、右子樹根結點權值之和;
(3) 將新樹加入森林中;
(4) 重復(2)、(3)步,直到森林中的樹都被比較過為止,該樹即為所求得的哈夫曼樹。

 

實現步驟:

1.建立哈夫曼樹前先根據權值對結點進行從小到大的排序1...n;

2.哈夫曼樹的總結點數為2*n-1,新節點下標從n+1到2*n-1新節點從小到大產生;

3.最小結點和次小結點在舊結點未加入樹里的最小兩個結點和新結點未被加入到樹里的最小的兩個結點總共四個結點中產生;設置舊結點未加入樹里的最小結點的下標為kfirst,新節點未被加入到樹里的最小結點的下標為ksum:

      (1)當產生第一個新結點即下標為n+1的結點時,最小結點和次小結點的下標分別是1和2;

      (2)當產生第二個新結點即下標為n+2的結點時,最小結點和次小結點的下標在3,4和n+1中產生;

      (3)當產生新結點的下標大於n+2時,最小結點和次小結點的下標在kfirst,kfirst+1和ksum,ksum+1中產生;

 

畫圖顯示藍色表示新節點,紅色表示舊結點:

 

總流程圖,紅色表示舊結點:

C語言源代碼:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<malloc.h>
  4 #include<string.h>
  5 typedef struct{
  6     unsigned int weight;//權值
  7     unsigned int parent, lchild,rchild;//父結點,左孩子,右孩子
  8 }HTNode,*HuffmanTree;
  9 typedef char ** HuffmanCode;
 10 //舊結點根據權值由小到大排序
 11 int sort(HuffmanTree t,int n)
 12 { 
 13     int i,j,k;
 14     for(i=1;i<n;i++){    
 15         for(j=1;j<=n-i;j++)        
 16             if(t[j].weight>t[j+1].weight)        
 17             {        
 18                 k=t[j].weight;        
 19                 t[j].weight=t[j+1].weight;        
 20                 t[j+1].weight=k;        
 21             }
 22     }
 23     return 1;
 24 }
 25 //找出未被加入樹里的最小結點和次小結點下標
 26 int Select(HuffmanTree HT,int n,int *s1,int *s2,int i,int &kfirst,int &ksum)
 27 {    
 28     if(i==n+1)
 29     {
 30         *s1=1;
 31         *s2=2;
 32         kfirst=3;
 33         ksum=n+1;
 34     }
 35     else{
 36         int b[4]={0,0,0,0}; 
 37         int index[4];
 38         int ii,j;
 39         //把舊結點中未加入樹中的最小和次小值加到b數組中
 40         for(j=0, ii=kfirst;ii<kfirst+2&&ii<=n&&j<4;ii++,j++){        
 41             b[j]=HT[ii].weight;
 42             index[j]=ii;
 43         }
 44         //把新結點中未加入樹中的最小和次小值加到b數組中
 45         for(j=j, ii=ksum;ii<ksum+2&&ii<=i-1&&j<4;ii++,j++){
 46             b[j]=HT[ii].weight;
 47             index[j]=ii;
 48         }
 49         //把最小值和次小值得下標分別放到index[0]和index[1]中
 50         for(int aa=0;aa<2;aa++){
 51             if(aa==0){
 52                 for(int k=1;k<4&&b[k]>0;k++){
 53                     if(b[0]>b[k]){
 54                         int temp=b[0];
 55                         int subtemp=index[0];
 56                         b[0]=b[k];
 57                         index[0]=index[k];
 58                         b[k]=temp;
 59                         index[k]=subtemp;
 60                     }
 61                 }
 62             }
 63             else{
 64                 for(int k=2;k<4&&b[k]>0;k++){
 65                     if(b[1]>b[k]){
 66                         int temp=b[1];
 67                         int subtemp=index[1];
 68                         b[1]=b[k];
 69                         index[1]=index[k];
 70                         b[k]=temp;
 71                         index[k]=subtemp;
 72                     }
 73                 }
 74             }
 75         }    
 76         *s1=index[0];
 77         *s2=index[1];
 78         //找出舊結點中未加入到樹中的最小結點對應的下標kfirst和新結點中未加入到樹中的最小結點對應的下標ksum
 79         if(index[1]==kfirst+1&&kfirst+2<=n){
 80             kfirst=kfirst+2;    
 81         }else if(index[1]==ksum+1&&ksum+2<=2*n-1){
 82             ksum=ksum+2;
 83         }
 84         else{
 85             kfirst=kfirst+1;
 86             ksum=ksum+1;
 87         }
 88     }
 89     return 1;
 90 }
 91 
 92 void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n,int &kfirst,int &ksum)
 93 {
 94     int i,m,s1,s2,start;
 95     char *cd;
 96     unsigned int c,f;
 97     if(n<=1) exit(1);
 98     m=2*n-1;      
 99     for(i=n+1;i<=m;i++)
100     {
101         HT[i].parent=0;
102     }
103     //產生新節點
104     for(i=n+1;i<=m;i++)
105     {
106         Select(HT,n,&s1,&s2, i,kfirst,ksum);
107         HT[s1].parent=i;HT[s2].parent=i;
108         HT[i].lchild=s1;HT[i].rchild=s2;
109         HT[i].weight=HT[s1].weight+HT[s2].weight;      
110     }
111     HC=(HuffmanCode )malloc((n+1)*sizeof(char* ));
112     cd=(char *)malloc(n*sizeof(char ));
113     cd[n-1]='\0';
114     for(i=1;i<=n;i++)
115     {
116         HC[i]=(char*)malloc((n-start)*sizeof(char));
117         start=n-1;
118         for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)
119         {
120             if(HT[f].lchild==c) 
121             {
122                 cd[--start]='0';            
123             }
124             else
125             {
126                 cd[--start]='1';
127             }                        
128             
129             strcpy(HC[i],&cd[start]);
130         }
131     }
132     free(cd);
133 }
134 void main()
135 {
136     HuffmanTree HT;
137     HuffmanCode HC;
138     int *w,n,j,K;
139     int i,m,s1,s2;//i為結點的下標,m為總結點數,s1為最小結點下標,s2為次小結點的下標
140     int kfirst=0,ksum=0;//舊結點未加入樹里的最小結點的下標kfirst,新節點未被加入到樹里的最小結點的下標ksum:
141     HuffmanTree p;
142     char *cd;    
143     printf("結點的個數為:\n");
144     scanf("%d",&n);
145     w=(int *)malloc(n*sizeof(int));
146     for(i=1;i<=n;i++)
147     {
148         printf("第%d個結點的權值為:",i);
149         scanf("%d",w+i-1);
150     }        
151     if(n<=1) exit(1);
152     m=2*n-1;//總結點數
153     HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
154     for(i=1;i<=n;i++,w++)
155     {
156         HT[i].weight=*w;
157         HT[i].parent=0;
158         HT[i].lchild=0;
159         HT[i].rchild=0;
160     }
161     sort(HT, n);
162     HuffmanCoding(HT,HC,w, n,kfirst,ksum);     
163       for(i=1;i<=n;i++)
164       {
165           printf("權值為%d結點的哈夫曼編碼:",HT[i].weight);
166           puts(HC[i]);
167       }
168       for(i=1;i<=n;i++)
169           free(HC[i]); 
170       free(HC); 
171       free(HT);
172 }

 

 

 

運行結果:


Java源代碼:

 

 
         
  1 import java.util.Scanner;
  2 
  3 //結點類
  4 class HTNode {
  5     int weight;
  6     int parent, lchild, rchild;
  7 }
  8 
  9 public class HuffmanDemo {
 10     static int[] s = new int[3];
 11     static int kfirst = 1;//舊結點未加入樹里的最小結點的下標kfirst
 12     static int ksum;//新節點未被加入到樹里的最小結點的下標ksum:
 13 
 14     public static void main(String[] args) {
 15         HuffmanDemo hf = new HuffmanDemo();
 16 
 17         int n;
 18         System.out.println("結點的個數為:");
 19         Scanner sc = new Scanner(System.in);
 20         n = sc.nextInt();
 21         ksum = n + 1;//新結點從n+1開始,由小到大產生
 22         HTNode[] HT = new HTNode[2 * n];//總結點數為2*n-1,從下標1開始
 23         for (int i = 0; i <= 2 * n - 1; i++) {
 24             HT[i] = new HTNode();
 25         }
 26         hf.input(n, HT);
 27         StringBuilder[] HC = new StringBuilder[n + 1];
 28         hf.sort(HT, n);
 29         StringBuilder[] hcret;
 30         hcret = hf.HuffmanCoding(HT, HC, n);
 31         for (int i = 1; i <= n; i++) {
 32             System.out.print("權值為" + HT[i].weight + "結點的哈夫曼編碼:");
 33             System.out.println(hcret[i].reverse());
 34         }
 35     }
 36 
 37     // 輸入結點權值
 38     void input(int n, HTNode[] HT) {
 39         Scanner sc = new Scanner(System.in);
 40         int[] w = new int[20];
 41         int i;
 42         for (i = 1; i <= n; i++) {
 43             System.out.println("第" + i + "個結點的權值為:");
 44             w[i] = sc.nextInt();
 45         }
 46         if (n <= 1)
 47             System.exit(1);
 48         for (i = 1; i <= n; i++) {
 49             HT[i].weight = w[i];
 50             HT[i].parent = 0;
 51             HT[i].lchild = 0;
 52             HT[i].rchild = 0;
 53         }
 54     }
 55 
 56     // 結點根據權值由小到大排序
 57     int sort(HTNode[] t, int n) {
 58         int i, j, k;
 59         for (i = 1; i < n; i++)
 60             for (j = 1; j <= n - i; j++)
 61                 if (t[j].weight > t[j + 1].weight) {
 62                     k = t[j].weight;
 63                     t[j].weight = t[j + 1].weight;
 64                     t[j + 1].weight = k;
 65                 }
 66         return 1;
 67     }
 68 
 69     // 找出未被加入樹里的最小結點和次小結點下標
 70     public int[] Select(HTNode[] HT, int n, int[] s, int i) {
 71         if (i == n + 1) {
 72             s[1] = 1;
 73             s[2] = 2;
 74             kfirst = 3;
 75             ksum = n + 1;
 76         } else {
 77             int b[] = { 0, 0, 0, 0 };
 78             int index[] = new int[4];
 79             int ii, j;
 80             // 把舊結點中未加入樹中的最小和次小值加到b數組中
 81             for (j = 0, ii = kfirst; ii < kfirst + 2 && ii <= n && j < 4; ii++, j++) {
 82                 b[j] = HT[ii].weight;
 83                 index[j] = ii;
 84             }
 85             // 把新結點中未加入樹中的最小和次小值加到b數組中
 86             for (ii = ksum, j = j; ii < ksum + 2 && ii <= i - 1 && j < 4; ii++, j++) {
 87                 b[j] = HT[ii].weight;
 88                 index[j] = ii;
 89             }
 90             // 把最小值和次小值得下標分別放到index[0]和index[1]中
 91             for (int aa = 0; aa < 2; aa++) {
 92                 if (aa == 0) {
 93                     for (int k = 1; k < 4 && b[k] > 0; k++) {
 94                         if (b[0] > b[k]) {
 95                             int temp = b[0];
 96                             int subtemp = index[0];
 97                             b[0] = b[k];
 98                             index[0] = index[k];
 99                             b[k] = temp;
100                             index[k] = subtemp;
101                         }
102                     }
103                 } else {
104                     for (int k = 2; k < 4 && b[k] > 0; k++) {
105                         if (b[1] > b[k]) {
106                             int temp = b[1];
107                             int subtemp = index[1];
108                             b[1] = b[k];
109                             index[1] = index[k];
110                             b[k] = temp;
111                             index[k] = subtemp;
112                         }
113                     }
114                 }
115             }
116             s[1] = index[0];
117             s[2] = index[1];
118             // 找出舊結點中未加入到樹中的最小結點對應的下標kfirst和新結點中未加入到樹中的最小結點對應的下標ksum
119             if (index[1] == kfirst + 1 && kfirst + 2 <= n) {
120                 kfirst = kfirst + 2;
121             } else if (index[1] == ksum + 1 && ksum + 2 <= 2 * n - 1) {
122                 ksum = ksum + 2;
123             } else {
124                 kfirst = kfirst + 1;
125                 ksum = ksum + 1;
126             }
127         }
128         return s;
129     }
130 
131     // 編碼
132     StringBuilder[] HuffmanCoding(HTNode[] HT, StringBuilder[] HC, int n) {
133 
134         int i, m, start;
135         char[] cd = new char[100];
136         int c, f;
137         if (n <= 1)
138             System.exit(1);
139         m = 2 * n - 1;
140         for (i = n + 1; i <= m; i++) {
141             HT[i].parent = 0;
142         }
143         for (i = n + 1; i <= m; i++) {
144             int[] ss = new int[3];
145             int[] sa = new int[3];
146             sa = Select(HT, n, ss, i);
147             HT[sa[1]].parent = i;
148             HT[sa[2]].parent = i;
149             HT[i].lchild = sa[1];
150             HT[i].rchild = sa[2];
151             HT[i].weight = HT[sa[1]].weight + HT[sa[2]].weight;
152         }
153         cd[n - 1] = '\0';
154         for (i = 1; i <= n; i++) {
155             HC[i] = new StringBuilder();
156             start = n - 1;
157             for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent) {
158                 if (HT[f].lchild == c) {
159                     cd[--start] = '0';
160                 } else {
161                     cd[--start] = '1';
162                 }
163                 HC[i].append((char) cd[start]);
164             }
165         }
166         return HC;
167     }
168 }
 
         

 

 

 

運行結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM