思路来自 《算法导论》
1 /*
2 *
3 * 1. 创建最小优先级队列
4 * 2. 用最小优先级队列创建Huffman树
5 * 3. 得到Huffman编码
6 *
7 */
8
9 using System;
10 using System.Collections.Generic;
11 using System.Collections;
12 using System.Linq;
13 using System.Text;
14 using System.IO;
15
16 namespace HuffmanTree
17 {
18
19 class Node : IComparable
20 {
21 public int data;
22 public Node left;
23 public Node right;
24 public Node parent;
25 public char character = '@';
26 public string code = "";
27 public Node() { }
28 public Node(int data, Node left = null, Node right = null, char character = '@')
29 {
30 this.data = data;
31 this.left = left;
32 this.right = right;
33 this.character = character;
34 }
35 public int CompareTo(object obj)
36 {
37 Node node = obj as Node;
38 return this.data.CompareTo(node.data);
39 }
40 }
41 /// <summary>
42 /// 最小优先级队列
43 /// 1. 取出最小元素,
44 /// 2. 得到最小元素
45 /// 3. 插入一个元素
46 /// 4. 元素个数
47 /// </summary>
48 class MinPriorityQueue
49 {
50 List<Node> list = new List<Node>();
51
52 public void Insert(Node node)
53 {
54 list.Add(node);
55 list.Sort(); // 此处可以改进(用线性插入法)
56
57 }
58
59 public Node ExtraceMin()
60 {
61 Node temp = list[0];
62 list.RemoveAt(0);
63 return temp;
64 }
65
66 public int Count // 属性:计数器
67 {
68 get { return list.Count; }
69 }
70 }
71
72 /// <summary>
73 /// 文件读取类
74 /// </summary>
75 class MyReader
76 {
77 string path;
78 Dictionary<char, int> dict = new Dictionary<char, int>();
79 public MyReader(string path = "")
80 {//初始化
81 this.path = path;
82 for (int i = 0; i < 26; i++)
83 {
84 dict.Add((char)((int)'a'+i), 0);
85 }
86
87 }
88 /// <summary>
89 /// 设置 或 返回当前文件的路径
90 /// </summary>
91 public string Path
92 {
93 get { return this.path; }
94 set { this.path = value; }
95 }
96
97 public Dictionary<char, int> Count()
98 {
99 try
100 {
101 StreamReader sr = new StreamReader(this.path);
102 string line;
103 while ((line = sr.ReadLine()) != null)
104 {
105
106 foreach (char item in line)
107 {
108 if ((item >= 'a' && item <= 'z') || (item >= 'A' && item <= 'Z'))
109 {
110 char temp = item;
111 temp = char.ToLower(temp);
112
113 dict[temp]++;
114 }
115 }
116
117 }
118 }
119 catch (System.Exception ex)
120 {
121 Console.WriteLine(ex.Message);
122 }
123
124 return dict;
125 }
126
127
128 }
129 class Program
130 {
131
132 static public Node BuildHuffmanTree(MinPriorityQueue queue)
133 {
134
135 while (queue.Count > 1)
136 {
137 Node temp = new Node();
138 Node node1 = queue.ExtraceMin();
139 Node node2 = queue.ExtraceMin();
140 temp.data = node1.data + node2.data;
141 temp.left = node1;
142 temp.right = node2;
143 node1.parent = temp;
144 node2.parent = temp;
145 queue.Insert(temp);
146 }
147 return queue.ExtraceMin();
148 }
149
150
151 /// <summary>
152 /// 通过遍历进行Hufman编码,并输出
153 /// </summary>
154 /// <param name="root"></param>
155 static public void traverse(Node root)
156 {
157 if (root != null)
158 {
159 if (root.character != '@')
160 Console.WriteLine("{1,8}{0,4} {2}", root.character, root.data, root.code);
161
162 if (root.left != null)
163 {
164 root.left.code = root.left.parent.code + "0";
165 traverse(root.left);
166 }
167 if (root.right != null)
168 {
169 root.right.code = root.left.parent.code + "1";
170 traverse(root.right);
171 }
172 }
173 }
174
175 static void Main(string[] args)
176 {
177 MinPriorityQueue queue = new MinPriorityQueue();
178
179 MyReader mr = new MyReader();
180 mr.Path = "LittlePrince.txt";
181 Dictionary<char, int> dict = mr.Count();
182 foreach (char item in dict.Keys)
183 {
184 Node node = new Node(dict[item], character:item);
185 queue.Insert(node);
186 }
187 Node root = BuildHuffmanTree(queue);
188
189 Console.WriteLine(" 频率 字符 编码");
190 traverse(root);
191
192 Console.ReadKey();
193 }
194 }
195 }
《Little Prince》中的英文字符(大小写不区分)的Huffman编码: