C# Huffman编译码细节

最近用C#写huffman编译码程序的时候发现了一些问题,这里整理一下(新手勿喷):  [文件为非中文文件]

 1.文件中出现的各个字符的出现频率的取得。其实现方法如下:

     1.1很容易想到一种一个个(Streamreader.read)读入或者一行行(Streamreader.readLine)读入或者整个文本读入(Streamreader.readToEnd),再进行匹配。可以预见,这个方法非常慢,对于几百kb的txt或者几Mb的txt会很慢。

     1.2这里看到一种方法是读入后,进行整个文本的查找,替换成空,前后的字符串长度的变化即为这个字符出现的频次。

c2 = str.Length - str.Replace("A", String.Empty).Length;

    1.3 根据1.2,想到另外一种方法。即要查找的字符作为分隔符,将原字符串分隔为多个子串,然后求子串的数目即可

c3 = str.Split(new char[] { 'A' }).Length - 1;
   统计整个文本的字符时应注意以下问题:

  • 注意读入文本时所用的方法的异同;read()返回对应的ASCII,readLine()遇到“\n”,“\r\n”等会对文本中出现的换行有影响,建议使用整个文本读入,速度也快。
  • 由于我是静态开辟的数组存储对应的字符频次,所以使用的是ASCII表,这里当然会有一些字符对应的频次是0,故这些要去掉,不去掉的话对后面的Huffman编码影响较大,个人建议使用动态开辟的;
 2.根据字符的频率进行Huffman编码,这里仅贴一下代码:

 //通过遍历进行Hufman编码,并输出
        public void traverse(Node root)
        {
            if (root != null)
            {
                if (root.character != "NO CHAR")
                    {
                    this.code[this.i, 0] = root.character; 
                    this.code[this.i, 1] = root.code;
                    this.i++; }
                if (root.left != null)
                {
                    root.left.code = root.left.parent.code + "0";
                    traverse(root.left);
                }
                if (root.right != null)
                {
                    root.right.code = root.left.parent.code + "1";
                    traverse(root.right);
                }
            }
        }
 3.对文件进行Huffman编码。
        很容易想到每个字符对应每个Huffman码,那么直接替换就可以了。但是要注意0和1的特殊性,所以这里要对0和1在文本的字符进行优先处理,而且要注意到两个之间任意一个先替换都会影响后一个的替换。所以只能是将文本读入的信息进行一次0和1处理(我目前只想到了这个,不过貌似可以记录已经编码的字符位置,然后来实现)。

       对于其他非0和1字符,直接进行全文替换就可以了。

//按照编码顺序一行行编码,实为按照编码替换
public void make_string()
  { 
this.m_streamReader.BaseStream.Seek(0, SeekOrigin.Begin);// 从数据流中读取每一行,直到文件的最后一行
            int strLine;
            //查到0和1的编码
            string  code0=null,code1=null;
             for(int i=0;i= 0)
            {
                strLine = this.m_streamReader.Read();
                switch (strLine)
                {
                    case 48: this.s += code0; break;
                    case 49: this.s += code1; break;
                    default: this.s += (char)strLine; break;
                }
             
            }
            this.m_streamReader.Close();
            this.fs1.Close();
          
          for (int i = 0; i < this.code.GetLength(0); i++)
               if ((this.code[i, 0]!= "0") && (this.code[i, 0]!= "1"))
                    this.s = this.s.Replace(this.code[i, 0], this.code[i, 1]);
        }
   4.Huffman译码的实现。根据输入的文本信息01流,按照Huffman树进行依次查找。这里直接贴代码

 //通过遍历进行Huffman译码,并输出
        public Node decode(int a,Node root)
        {
                Node node=null;
                if (root != null)
                {
                    if (a == 48)//左子树
                    {
                        if (!root.left.isLeaf())
                        {
                            node = root.left;
                        }
                        else
                        {
                            this.txt += root.left.character;
                            node = this.root;
                        }
                    }
                    if (a == 49)
                    {
                        if (!root.right.isLeaf())
                        {
                            node = root.right;
                        }
                        else
                        {
                            this.txt += root.right.character;
                            node = this.root;
                        }
                    }
                }
                return node;
        }
        注意Huffman树随着源文件的变大,编译码的速度会很慢,很多时候代码本身还会出现内存溢出等各种错误,所以就要求仔细分析代码的效率。




你可能感兴趣的:(C#)