利用C 实现哈夫曼算法
2008-02-23 05:25:02来源:互联网 阅读 ()
class hNode { public: friend bool operator > (hNode n1,hNode n2); //定义了大于符号,供优先队列排列使用 hNode(string d="",int i=0,hNode* l = NULL,hNode* r =NULL):left(l),right(r),data(d),value(i){} hNode* left; hNode* right; string data; //储存的字符串 int value; //字符串出现的次数 }; bool operator >(hNode n1,hNode n2) { return n1.value > n2.value; } |
因为只是算法课的小作业,所以我也不准备为hNode定义完整的二叉树操作,仅仅只是存放数据的对象,所以只有一个构造函数,并且任何的data member都是公有的。
这此写这个算法会碰到大麻烦,主要因为是用了std::priority_queue容器。当时考虑到在哈夫曼中要每次挑选两个频率最小(即出现次数最小,我那个hNode里的value是出现的次数),很自然的就想到了std::priority_queue容器,优先队列每次都会弹出队列中权值最高的元素,这个特性无疑是实现哈夫曼算法的最好选择。然而因为第一次用std::priority_queue容器,结果出了不少问题,好在最后都一一解决,也学到了不少东西。
初步的设想是这样的,先把任何的hNode对象都压入优先队列中去,然后每次弹出两个,组成一个新的结点,再把新的结点压入队列,重复这一步骤,当队列中只有一个元素时,哈夫曼树也就完成了。像这样:(是错的,可别学)
while(...) { std::priority_queue<hNode> q; ..... hNode h1 = q.top(); q.pop(); hNode h2 = q.top(); q.pop(); hNode r; r.left = h1; r.right = h2; r.value = h1.value h2.value; q.push(r); } |
然而遭遇的第一个问题是,STL的任何容器的的插入都是基于by value语义的,也就是要生成一个对象的副本放在容器中。这样的后果就是hNode的left,right指针都指到不知道什么地方去了。大家能够稍微画几个图试一下,就知道出了什么问题了。考虑一下后,发现假如队列里存放hNode的指针,就不会出现这个问题了,于是改写成:
hNode* makeTree(priority_queue<hNode*> pq) { hNode* p1 = NULL; hNode* p2 = NULL; hNode* r = NULL; while( !pq.empty()) { p1 = pq.top(); pq.pop(); if (pq.empty()) { r = p1; return r; } p2 = pq.top(); pq.pop(); r =new hNode; r->left = p1; r->right = p2; r->value = p1->value p2->value; pq.push(r); } return NULL; } |
然而马上遭遇了第二个问题。std::priority_queue在判断优先关系的时候,直接比较指针的地址,而不是指针指向的对象的大小关系。而指针不是类,我没办法重写指针的比较操作。程式陷入了困境之中。std::priority_queue默认使用Greater<>模板来生成一个function object来对元素进行比较,我试图为Greater<>写一个hNode*的特化版本来改变优先队列对hNode*的比较,然而也没有成功。山重水复疑无路之时,突然想到为什么不直接为优先队列写一个function object来替代Greater<>不就能够了吗?赶快写下如下代码:
struct phNodeComp { bool operator () (const hNode*& left,const hNode*& right) const { return left->value > right->value; } }; |
然后把std::priority_queue的申明变为:
priority_queue<hNode*,vector<hNode*>,phNodeComp > pq; |
终于把这个问题给解决了。看样子仅从书本上获得的知识是不牢靠的,一定要自己实践了才会有真正的认识。
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇: C 中重载 操作符的正确方法
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash