source:http://blog.csdn.net/yinxusen/article/details/6261549
这是别人写的Huffman
比我的功能全点,主要是欣赏一下别人的内存分配方式,它使用的指针动态分配
- #include <iostream.h>
- #include <string.h>
- /*
- 哈夫曼编码示例程序
- 作者:杨勇
- 哈夫曼建树算法描述:
- 1. 将所有权值分别构造一个只有一个结点的二叉树结点,将这些结点加入集合A(哈夫曼森林)
- 2. 检查集合A成员的个数,如果为1,则算法结束,集合A中唯一的结点为哈夫曼树的根。
- 3. 从集合A中取出根结点权值最小的两棵树a, b,集合中不再保留这两棵树。
- 4. 由a和b分别为左、右子树构造一个新的二叉树r, 令r的权值等于a的权值与b的权值之和。
- 5. 将r加入到集合A中,返回第 2 步。
- */
- struct HuffmanNode //哈夫曼树结点类型
- {
- char data; //结点上的数据
- int power; //结点的权值
- HuffmanNode *lchild; //左分支(作为二叉树结点时用)
- HuffmanNode *rchild; //右分支(作为二叉树结点时用)
- HuffmanNode *next; //后继指针(作为单链表结点时用)
- };
- //给Huffman森林(按各树根结点的值升序排列的带头结点的链表)添加一棵Huffman树
- //使得链表仍然有序
- void AddNode(HuffmanNode *headNode, HuffmanNode *pNode)
- {
- HuffmanNode *p = headNode;
- //找到第一个权值小于给定结点的结点,p指定该结点的前一个结点
- while (p->next && p->next->power < pNode->power) p = p->next;
- pNode->next = p->next;
- p->next = pNode;
- }
- //功能:构造哈夫曼树
- //参数说明
- //n: 字符的个数
- //datas: 要统计的字符
- //powers: 字符对应的权值(出现的次数)
- HuffmanNode* CreateHuffmanTree(int n, char datas[], int powers[])
- {
- HuffmanNode head;
- head.next = NULL; //初始化森林
- for (int i = 0; i < n; i++)
- {
- HuffmanNode *pNode = new HuffmanNode;
- pNode->data = datas[i];
- pNode->power = powers[i];
- pNode->lchild = pNode->rchild = pNode->next = NULL;
- AddNode(&head, pNode);
- }
- //开始构造
- while (head.next)
- {
- if (!head.next->next) //只剩最后一个结点,这就是根
- {
- return head.next;
- }
- //取前两个出来构造一棵新树(因为链表已经按权值升序排列了,前两个就是最小的两个)
- HuffmanNode *pN1, *pN2, *pRoot;
- pN1 = head.next; //第一个结点
- pN2 = pN1->next; //第二个结点
- head.next = pN2->next; //将这两个结点从链表中删除
- pRoot = new HuffmanNode; //为这两个结点建立根结点
- pRoot->power = pN1->power + pN2->power; //权值相加
- pRoot->lchild = pN1; //左分支为第一个结点
- pRoot->rchild = pN2; //右分支为第二个结点
- //将新的根加入哈夫曼森林
- AddNode(&head, pRoot);
- }
- return NULL;
- }
- //计算哈夫曼树的带权路径长度PWL
- //node: 树结点
- //level: 当前层数
- int GetPWL(HuffmanNode *node, int level)
- {
- if (!node) return 0;
- if (!node->lchild && !node->rchild) return node->power * level; //是叶结点
- return GetPWL(node->lchild, level + 1) + GetPWL(node->rchild, level+1);
- }
- //获取所有叶点的哈夫曼编码
- //node: 树结点
- //code: 上层前缀
- void GetCodes(HuffmanNode *node, const char *code)
- {
- if (!node->lchild && !node->rchild)
- {
- //是叶结点,打印编码
- cout << node->data << " " << node->power << " " << code << endl;
- return;
- }
- int len = strlen(code);
- char *newcode = new char[len+2];
- strcpy(newcode, code);
- newcode[len+1] = '/0';
- if (node->lchild) //左分支分配'1'
- {
- newcode[len] = '1';
- GetCodes(node->lchild, newcode);
- }
- if (node->rchild) //右分支分配'0'
- {
- newcode[len] = '0';
- GetCodes(node->rchild, newcode);
- }
- delete[] newcode;
- }
- //释放所有结点,要按二叉树的方式
- void FreeNodes(HuffmanNode *node)
- {
- if (!node) return;
- FreeNodes(node->lchild);
- FreeNodes(node->rchild);
- delete node;
- }
- //请尝试改变主函数,使之能统计指定文本文件中的各字母出现的次数,然后给这些字母编码,并将文本文件的内容编码后输出到out.txt中
- void main()
- {
- int n, pow;
- char ch;
- do
- {
- cout << "请输入字母个数:";
- cin >> n;
- } while (n < 1);
- char *datas = new char[n];
- int *pows = new int[n];
- for (int i = 0; i < n; i++)
- {
- cout << "请输入第 " << i+1 << " 个字母及权值:";
- cin >> ch >> pow;
- datas[i] = ch;
- pows[i] = pow;
- }
- HuffmanNode *root = CreateHuffmanTree(n, datas, pows);
- cout << "构造出哈夫曼树的权值为:" << GetPWL(root, 0) << endl;
- cout << "所有字母的哈夫曼编码如下:" << endl;
- GetCodes(root, "");
- FreeNodes(root);
- delete[] datas;
- delete[] pows;
- }