C++哈弗曼編碼

  1 // haffman.cpp : 定義控制檯應用程序的入口點。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include<iostream>
  6 using namespace std;
  7 
  8 typedef struct hfnode
  9 {
 10     char ch;      //存儲字符
 11     int weight;   //存儲權值
 12     int parent;   //雙親結點位置
 13     int lchild;   //左右孩子結點位置
 14     int rchild;
 15 } hfnode,*hfmtree;
 16 
 17 typedef struct node
 18 {
 19     char code[10];
 20 } node,*hfcode;
 21 
 22 #define Nsymbols 10
 23 
 24 hfnode *Inithfm(hfnode *tree,int n)  //千萬不能用關鍵字命名。把這些節點做爲帶權值的二叉樹的根節點,左右子樹爲空
 25 {
 26     //tree = new hfnode[n]; //多餘了,已經在main函數中聲明瞭。
 27     for(int i = 0;i < n; i++)
 28     {
 29         tree[i].ch = '0';
 30         tree[i].weight = 0;
 31         tree[i].lchild = 0;
 32         tree[i].rchild = 0;
 33         tree[i].parent = 0;
 34     }
 35     cout << "請輸入想要編碼的字符序列,按照先字符後次數的順序輸入" << endl;
 36     for(int i = 0;i < 4; i++)
 37     {
 38         cin >> tree[i].ch >>tree[i].weight;
 39     }
 40      cout <<endl; 
 41 
 42     for(int i = 0;i < 4;i++)
 43         cout << tree[i].ch << " "<<tree[i].weight<<" ";
 44     cout << endl;
 45     return tree;
 46 }
 47 
 48 void select(hfnode *tree,int n,int *p1,int *p2) //選擇兩棵根結點權值最小的樹做爲左右子樹構造一棵新的二叉樹,且至新的二叉樹的根結點的權值爲其左右子樹上根結點的權值之和。
 49 {
 50     //找一個做爲參考,返回的是結點
 51     int x,y;
 52     for(int i = 0;i <= n;i++)
 53     {
 54         if(tree[i].parent==0)
 55         {
 56             x = i;
 57             break;//找到一個參考點便可
 58         }
 59     }
 60 
 61 
 62     for(int i = 0;i <= n;i++)  //找出最小的結點
 63     {
 64         if((tree[i].parent==0)&&(tree[i].weight!=0))
 65         {
 66             if(tree[i].weight < tree[x].weight)
 67                 x = i;
 68         }
 69     }
 70 
 71    for(int j = 0;j <= n;j++)
 72     {
 73         if((tree[j].parent==0)&&(j!=x))
 74         {
 75             y = j;
 76             break;//找到一個參考點便可
 77         }
 78     }
 79    for(int j = 0;j <= n;j++)   //找出次小的結點
 80     {
 81         if((tree[j].parent==0)&&(tree[j].weight!=0)&&j!=x)
 82         {
 83             if(tree[j].weight < tree[y].weight)
 84                 y = j;
 85         }
 86     }
 87        *p1 = x;
 88        *p2 = y;
 89 }
 90 //對哈弗曼樹進行編碼。
 91 
 92 void HfCode(hfnode *tree,int n,node *hfmcode,int m)
 93 {
 94      int c,f;
 95      int start = 0;
 96 
 97      for(int i=0;i<10;i++)
 98      {
 99          for(c=i,f=tree[c].parent;f!=0;c=f,f=tree[c].parent) //追溯法,從葉子節點出發,一路往上追溯。
100          {
101              if(tree[f].lchild==c)
102                  hfmcode[i].code[start++] = '0';
103              else 
104                  hfmcode[i].code[start++] = '1';
105          }
106          start = 0;
107      }   
108 }
109 
110 void Print(node *hfmcode,int m)
111 {
112     for(int i = 0;i < m;i++)
113     {
114         for(int j = 0;j < m;j++)
115           cout <<hfmcode[i].code[j];
116         cout << endl;
117     }
118     cout << endl;
119 }
120 
121 
122 
123 int main()
124 {
125     int p1=0,p2=0; //爲了接收最小和次小的兩個節點
126     hfnode tree[Nsymbols]; //當咱們不是用指針,這種狀況下,已經所有賦值了。不用再一次賦值了。
127     Inithfm(tree,Nsymbols); //初始化結構體數組。
128   
129     //創建哈弗曼樹
130 
131     for(int m = 4;m < 2*4-1;m++) //二叉樹性質
132     {
133         select(tree,m-1,&p1,&p2);
134         tree[p1].parent = m;
135         tree[p2].parent = m;
136         tree[m].lchild = p1;
137         tree[m].rchild = p2;
138         tree[m].weight = tree[p1].weight + tree[p2].weight;
139         tree[m].parent =0; //其實這句也能夠不用,由於初始化時已經初始化爲0了。
140     }
141 
142    node hfmcode[4];
143 // 初始化,否則打印的時候會出現未知錯。
144    for(int i = 0;i < 4;i++)
145     {
146         for(int j = 0;j < 4;j++)
147          hfmcode[i].code[j]='\0';
148     }
149 
150    HfCode(tree,Nsymbols,hfmcode,4); //編碼函數
151    Print(hfmcode,4);  //打印函數
152     return 0;
153 }

實驗名稱:哈弗曼編碼node

實驗目的:瞭解前綴編碼的概念,理解數據壓縮的基本方法;ios

      掌握Huffman編碼的設計思想並能熟練應用。編程

實驗要求:對有字符集{A,B,C,D},各字符在電文中出現的次數集爲{1,3,4,7};數組

要求編程實現Huffman樹的構造,並在此基礎上編程實現Huffman編碼。函數

實驗步驟及內容工具

一、首先創建一個定義哈弗曼樹的結構體Node,及結構體指針LinkList,該結構體包含一個存儲字符的ch,存儲權值的weight,存儲雙親結點的parent,存儲左右孩子的lchild與rchild。代碼以下:編碼

   typedef struct hfnodespa

{設計

    char ch;      //存儲字符指針

    int weight;   //存儲權值

    int parent;   //雙親結點位置

    int lchild;   //左右孩子結點位置

    int rchild;

} hfnode,*hfmtree;

二、定義一個存儲編碼的結構體,主要是爲了方便打印,代碼以下:

 typedef struct node

{

    char code[10];

} node,*hfcode;

 

三、初始化函數,由於默認值是一個不肯定的值,必須進行初始化才行。

hfnode *Inithfm(hfnode *tree,int n)  //千萬不能用關鍵字命名。把這些節點做爲帶權值的二叉樹的根節點,左右子樹爲空

{

    //tree = new hfnode[n]; //多餘了,已經在main函數中聲明瞭。

    for(int i = 0;i < n; i++)

    {

        tree[i].ch = '0';

        tree[i].weight = 0;

        tree[i].lchild = 0;

        tree[i].rchild = 0;

        tree[i].parent = 0;

    }

    cout << "請輸入想要編碼的字符序列,按照先字符後次數的順序輸入" << endl;

    for(int i = 0;i < 4; i++)

    {

        cin >> tree[i].ch >>tree[i].weight;

    }

     cout <<endl;

 

    for(int i = 0;i < 4;i++)

        cout << tree[i].ch << " "<<tree[i].weight<<" ";

    cout << endl;

    return tree;

}

四、選擇兩棵根結點權值最小的樹做爲左右子樹。

void select(hfnode *tree,int n,int *p1,int *p2) //選擇兩棵根結點權值最小的樹做爲左右子樹構造一棵新的二叉樹,且至新的二叉樹的根結點的權值爲其左右子樹上根結點的權值之和。

{

    //找一個做爲參考,返回的是結點

    int x,y;

    for(int i = 0;i <= n;i++)

    {

        if(tree[i].parent==0)

        {

            x = i;

            break;//找到一個參考點便可

        }

    }

 

 

    for(int i = 0;i <= n;i++)  //找出最小的結點

    {

        if((tree[i].parent==0)&&(tree[i].weight!=0))

        {

            if(tree[i].weight < tree[x].weight)

                x = i;

        }

    }

 

   for(int j = 0;j <= n;j++)

    {

        if((tree[j].parent==0)&&(j!=x))

        {

            y = j;

            break;//找到一個參考點便可

        }

    }

   for(int j = 0;j <= n;j++)   //找出次小的結點

    {

        if((tree[j].parent==0)&&(tree[j].weight!=0)&&j!=x)

        {

            if(tree[j].weight < tree[y].weight)

                y = j;

        }

    }

       *p1 = x;

       *p2 = y;

}

五、構造哈弗曼樹

        //創建哈弗曼樹

 

    for(int m = 4;m < 2*4-1;m++) //二叉樹性質

    {

        select(tree,m-1,&p1,&p2);

        tree[p1].parent = m;

        tree[p2].parent = m;

        tree[m].lchild = p1;

        tree[m].rchild = p2;

        tree[m].weight = tree[p1].weight + tree[p2].weight;

        tree[m].parent =0; //其實這句也能夠不用,由於初始化時已經初始化爲了。

    }

六、對哈弗曼樹進行編碼。編碼函數以下:

    //對哈弗曼樹進行編碼。

 

void HfCode(hfnode *tree,int n,node *hfmcode,int m)

{

     int c,f;

     int start = 0;

 

     for(int i=0;i<10;i++)

     {

         for(c=i,f=tree[c].parent;f!=0;c=f,f=tree[c].parent) //追溯法,從葉子節點出發,一路往上追溯。

         {

             if(tree[f].lchild==c)

                 hfmcode[i].code[start++] = '0';

             else

                 hfmcode[i].code[start++] = '1';

         }

         start = 0;

     }  

}

七、打印編碼

 

void Print(node *hfmcode,int m)

{

    for(int i = 0;i < m;i++)

    {

        for(int j = 0;j < m;j++)

          cout <<hfmcode[i].code[j];

        cout << endl;

    }

    cout << endl;

}

 

另配上一副本身用畫圖工具畫的理論分析圖:

 

結果與C++代碼結果一致。

總結:

這次實驗,讓我理解告終構體數組的使用以及初始化,內存管理等方面的熟悉,感受收穫挺大的。

相關文章
相關標籤/搜索