霍夫曼編碼原理 C#版本

               霍夫曼編碼原理

在數據通信時,可以用01碼的不同排列來表示字符。例如給定一段報文CAST CAST SAT AT A TASA,在報文中出現的字符集合是{C,A,S,T},各個字符出現的頻度是{2,7,4,5}。若給每個字符一個等長的二進制表示,例如 C:00 A:01 S:10 T:11,則所發的報文將是00011011 00011011 100111 0111 01 11011001,共計(2+7+5+4)*2=36個碼。若按字符出現的頻度不同給予不同長度的編碼,出現頻度較大的字符采用爲數較少的編碼,出現頻度較小的字符采用位書較多的編碼,可以是報文的碼數降到最小,這就是所謂的最小冗餘編碼問題。霍夫曼編碼就能實現這種最小冗餘編碼。上例中按字符出現的頻度進行編碼,A:0 T:10 S:110C:111,則最終的報文只有35個碼,節省了傳輸中使用的單元。因而霍夫曼編碼是一種被廣泛應用而且非常有效的數據壓縮技術。

二.編碼實現

一般情況下,霍夫曼編碼的工作主要分爲三步。

第一步是準備工作,對於需要編碼的字符(一般存在於文件裏)進行掃描,統計每個字符出現的頻次,得到一個整數數組。

第二步根據這個頻次數組構造一棵霍夫曼樹,這步是霍夫曼編碼的核心內容。

第三步,再次掃描一遍待編碼的字符,對每個字符,在霍夫曼樹裏搜索該字符,得到它的編碼。

這裏通過C#軟件實現,便於可視化的界面及操作方便性

// 學習小結 吳新強於2013年3月20日16:58:11 桂電 2507
//
//
//


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;


namespace HuffmanCoding
{
    public partial class Form1 : Form
    {


        public Form1()
        {
            InitializeComponent();
        }
        
        public struct Node//定義節點結構
        {
            public int weight; //定義權重
            public int parent, lchild, rchild;//定義父親,孩子 
        };
        public struct Min//定義最小兩位數結構
        {
            public int s1;
            public int s2;
        };
        Node[] HTN = new Node[500];
        Min Getmin(int n) //尋找最小的兩位權值
        {
            int min1, min2, i;
            Min code; //定義結構體Min
            code.s1 = 1;
            code.s2 = 1;
            min1 = 256;
            min2 = 256;
            for (i = 0; i < n; i++)//尋找最小值 
            {
                if (HTN[i].weight <= min1 && HTN[i].parent == 0)
                {
                    min1 = HTN[i].weight;
                    code.s1 = i;


                }
            }


            for (i = 0; i <= n; i++)//尋找次最小值 
            {
                if (HTN[i].weight <= min2 && i != code.s1 && HTN[i].parent == 0)
                {
                    min2 = HTN[i].weight;
                    code.s2 = i;
                }
            }
            return code;
        }
        private void Form1_Load(object sender, EventArgs e)
        {


        }
        private void label1_Click(object sender, EventArgs e)
        {


        }
        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {


        }
        private void richTextBox2_TextChanged(object sender, EventArgs e)
        {


        }
        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {


        }
        private void button1_Click(object sender, EventArgs e)//編碼響應
        {
            int length;//統計輸入的字符個數
            int Num = 0;//統計輸入字符的種類
            int i, j, k, m, start, c, f;
            Min min;
            int[] weight = new int[256];//用於統計每次字符出現的次數
            int[] ind = new int[256];//用於統計i對應的字符
            int[] wei = new int[256];//用於統計每個字符權重
            string Input = richTextBox1.Text.Trim();//輸入的編碼字符存到Input數組中
            string code = "";
            if (richTextBox1.Text == "") MessageBox.Show("請輸入編碼字符!");
            else
            {
                length = richTextBox1.Text.Length;
                for (i = 0; i < length; i++)
                    weight[Input[i]]++; //統計每個字符出現的次數即權重
                for (i = 0; i < 256; i++)
                {
                    if (weight[i] != 0) //若個數不爲0,將這個字符存入ind數組中,
                    {
                        ind[Num] = i; //Ind存放字符代碼 
                        wei[Num++] = weight[i];//相應的權重存放在weight數組中,記錄個數輸入的字符有num種
                    }
                }


                m = 2 * Num - 1;
                for (i = 0; i < Num; i++)//初始化
                {
                    HTN[i].weight = wei[i];
                    HTN[i].parent = 0;
                    HTN[i].lchild = 0;
                    HTN[i].rchild = 0;
                }
                for (; i < m; i++)
                {
                    HTN[i].weight = 0;
                    HTN[i].parent = 0;
                    HTN[i].lchild = 0;
                    HTN[i].rchild = 0;
                }


                for (i = Num; i < m; i++)//建樹
                {
                    min = Getmin(i - 1); //找出最小的兩位數
                    HTN[min.s1].parent = i;
                    HTN[min.s2].parent = i;
                    HTN[i].lchild = min.s1;
                    HTN[i].rchild = min.s2;
                    HTN[i].weight = HTN[min.s1].weight + HTN[min.s2].weight;
                }
                string[] HC = new string[Num];
                char[] cd = new char[Num + 5];
                for (i = 0; i < Num; i++)//對每個字符進行編碼
                {
                    start = Num + 5;
                    for (c = i, f = HTN[i].parent; f != 0; c = f, f = HTN[f].parent)
                    {
                        if (HTN[f].lchild == c) cd[--start] = '0';
                        else cd[--start] = '1';
                    }
                    for (j = start; j < Num + 5; j++)
                        HC[i] += cd[j];
                }


                for (i = 0; i < length; i++)//將輸入字符編程碼
                {
                    k = 0;
                    int flag = 0;
                    for (j = 0; j < Num && flag == 0; j++)
                    {
                        if (ind[j] == Input[i])//尋找該字符對應的編碼
                        {
                            k = j;
                            flag = 1;
                        }


                    }
                    code += HC[k].ToString();
                }


                richTextBox2.Text = code;//最終編碼輸出至richTextBox2中
                for (i = 0; i < Num; i++)//將每個字符編碼輸出至listbox中
                {
                    this.listBox1.Items.Add(Convert.ToString(Convert.ToChar(ind[i])) + ":  " + HC[i]);


                }
            }
        }
        private void button2_Click(object sender, EventArgs e)//重新輸入響應
        {


            richTextBox1.Text = "";
            richTextBox2.Text = "";
            this.listBox1.Items.Clear();
        }
        private void button3_Click(object sender, EventArgs e)//退出響應
        {
            this.Close();
        }
    }
}

實驗截圖:


發佈了50 篇原創文章 · 獲贊 4 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章