C# Huffman编译码细节

来源:互联网 发布:网络主播服装 编辑:程序博客网 时间:2024/06/18 06:59

最近用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<this.code.GetLength(0);i++)             {                  if(this.code[i,0]=="0") code0=this.code[i,1];                  if(this.code[i,0]=="1") code1=this.code[i,1];             }while (this.m_streamReader.Peek() >= 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树随着源文件的变大,编译码的速度会很慢,很多时候代码本身还会出现内存溢出等各种错误,所以就要求仔细分析代码的效率。




0 0
原创粉丝点击