哈夫曼树压缩C#算法,huffman

算法原理:http://www.cnblogs.com/skywang12345/p/3706833.html。

上代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.IO;
using System.Web.Script;
using System.Web.Script.Serialization;

namespace ConsoleApplication2
{
    public class Program
    {
        public static void Main()
        {
            string content = @"bacbccddeeeddee";
            Console.WriteLine("需要压缩的内容(长度:" + content.Length + "):");
            Console.WriteLine(content);
            Console.WriteLine();

            HuffmanTree huffman = new HuffmanTree();

            string compressionString = huffman.Compression(content);
            Console.WriteLine("压缩后的内容(长度:" + compressionString.Length + "):");
            Console.WriteLine(compressionString);
            Console.WriteLine();

            string unZipContent = huffman.Unzip(compressionString);
            Console.WriteLine("解压后的的内容:");
            Console.WriteLine(unZipContent);
            Console.Read();
        }
    }

    public class HuffmanTreeInfo
    {
        public string ZipCode { get; set; }
        public string ZipCodeRemainder { get; set; }
        public Dictionary<string, char> UnZipDictionary { get; set; }
    }

    public class HuffmanTree
    {
        public class HuffmanNote
        {
            public int Weight { get; set; }
            public char Word { get; set; }
            public HuffmanNote LeftNote { get; set; }
            public HuffmanNote RightNote { get; set; }
            public char HuffmanCode { get; set; }
        }

        public string Compression(string content)
        {
            HuffmanNote huffmanNote = CreateHuffmanTree(CreateWordWeightDictionary(content));

            Dictionary<char, string> encodeDictionary = new Dictionary<char, string>();
            CreateWordCodeDictionay(huffmanNote, "", encodeDictionary);

            StringBuilder sb = new StringBuilder(content.Length);
            foreach (var item in content)
            {
                sb.Append(encodeDictionary[item]);
            }

            string huffmanCode = sb.ToString();

            HuffmanTreeInfo huffmanTreeInfo = new HuffmanTreeInfo();
            huffmanTreeInfo.ZipCodeRemainder = huffmanCode.Substring(huffmanCode.Length - huffmanCode.Length % 8);
            huffmanTreeInfo.ZipCode = HuffmanCodeToByte(huffmanCode.Substring(0, huffmanCode.Length - huffmanCode.Length % 8));
            huffmanTreeInfo.UnZipDictionary = CreateUnZipDictionary(encodeDictionary);

            return ObjectToJson(huffmanTreeInfo);
        }

        private string ObjectToJson(object obj)
        {
            return new JavaScriptSerializer().Serialize(obj);
        }

        private T JsonToObject<T>(string json)
        {
            return new JavaScriptSerializer().Deserialize<T>(json);
        }

        private List<HuffmanNote> CreateWordWeightDictionary(string content)
        {
            Dictionary<char, int> wordWeightDictionary = new Dictionary<char, int>();

            foreach (var item in content)
            {
                if (wordWeightDictionary.ContainsKey(item))
                {
                    wordWeightDictionary[item] += 1;
                }
                else
                {
                    wordWeightDictionary[item] = 1;
                }
            }

            List<HuffmanNote> huffmanNoteList = new List<HuffmanNote>();
            foreach (var item in wordWeightDictionary)
            {
                huffmanNoteList.Add(new HuffmanNote()
                {
                    Weight = item.Value,
                    Word = item.Key
                });
            }
            return huffmanNoteList;
        }

        public string Unzip(string content)
        {
            HuffmanTreeInfo huffmanTreeInfo = JsonToObject<HuffmanTreeInfo>(content);

            StringBuilder sb = new StringBuilder(huffmanTreeInfo.ZipCode.Length);
            for (int i = 0; i < huffmanTreeInfo.ZipCode.Length; i++)
            {
                sb.Append(Convert.ToString((int)huffmanTreeInfo.ZipCode[i], 2).PadLeft(8, '0'));
            }
            string huffmanCodes = sb.ToString() + huffmanTreeInfo.ZipCodeRemainder;

            StringBuilder decode = new StringBuilder(huffmanCodes.Length);
            string temp = string.Empty;
            for (int i = 0; i < huffmanCodes.Length; i++)
            {
                temp += huffmanCodes[i].ToString();
                if (huffmanTreeInfo.UnZipDictionary.ContainsKey(temp))
                {
                    decode.Append(huffmanTreeInfo.UnZipDictionary[temp]);
                    temp = string.Empty;
                }
            }
            return decode.ToString();
        }

        private string HuffmanCodeToByte(string huffmanCodes)
        {
            StringBuilder sb = new StringBuilder(huffmanCodes.Length);
            for (int i = 0; i*8 < huffmanCodes.Length; i++)
            {
                sb.Append((char)Convert.ToInt32(huffmanCodes.Substring(i * 8, 8), 2));
            }
            return sb.ToString();
        }

        private Dictionary<string, char> CreateUnZipDictionary(Dictionary<char, string> encodeDictionary)
        {
            Dictionary<string, char> unZipDictionary = new Dictionary<string, char>();
            foreach (var item in encodeDictionary)
            {
                unZipDictionary.Add(item.Value, item.Key);
            }
            return unZipDictionary;
        }

        private HuffmanNote CreateHuffmanTree(List<HuffmanNote> huffmanNoteList)
        {
            if (huffmanNoteList.Count == 1)
            {
                return huffmanNoteList[0];
            }

            var huffmanNoteListBySort = huffmanNoteList.OrderBy(o => o.Weight).ToList();

            var minWeight2Note = huffmanNoteListBySort.Take(2).ToList();
            huffmanNoteListBySort.RemoveAt(0);
            huffmanNoteListBySort.RemoveAt(0);

            var leftNote = minWeight2Note[0];
            leftNote.HuffmanCode = '0';

            var rightNote = minWeight2Note[1];
            rightNote.HuffmanCode = '1';

            var newNote = new HuffmanNote()
            {
                LeftNote = leftNote,
                RightNote = rightNote,
                Weight = leftNote.Weight + rightNote.Weight
            };

            huffmanNoteListBySort.Add(newNote);

            return CreateHuffmanTree(huffmanNoteListBySort);
        }

        private void CreateWordCodeDictionay(HuffmanNote huffmanNote, string HuffmanCode, Dictionary<char, string> encodeDictionary)
        {
            if (huffmanNote.LeftNote == null)
            {
                encodeDictionary[huffmanNote.Word] = HuffmanCode.Substring(1) + huffmanNote.HuffmanCode;//HuffmanCode.Substring(1) 为什么有这句呢  因为char默认值是\0  所以这里要把第一个字符\0去掉
                return;
            }
            HuffmanCode += huffmanNote.HuffmanCode;

            CreateWordCodeDictionay(huffmanNote.LeftNote, HuffmanCode, encodeDictionary);
            CreateWordCodeDictionay(huffmanNote.RightNote, HuffmanCode, encodeDictionary);
        }
    }
}