题目
如下图:
分析
哈夫曼编码问题!
程序实现
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
const int MAXLEN = 100;
typedef struct Huffmantree
{
char ch; /*键值*/
int weight, mark; /*weight为权值,mark为标志域*/
struct Huffmantree *parent, *lchild, *rchild, *next;
}Hftree, *linktree;
/*整理输入的字符串,合并相同的项,并求出每个字符在数组中出现的次数 */
linktree tidycharacter(char character[])
{
int i = 0;
linktree tree, ptr, beforeptr, node; /*链式 ,tree为头结点,beforeptr为ptr的前一结点,node为新申请的结点*/
tree = (linktree)malloc(sizeof(Hftree));/*创建单链表的头结点*/
if (!tree)return NULL;
tree->next = NULL; /* 头结点为空,且后续结点为空*/
for (i = 0; character[i] != ' '&&character[i] != '
'; i++) /*遍历直到字符串结束为止*/
{
ptr = tree;
beforeptr = tree;
/*新申请结点node*/
node = (linktree)malloc(sizeof(Hftree));
if (!node)return NULL;
node->next = NULL;
node->parent = NULL;
node->lchild = NULL;
node->rchild = NULL; /*置空*/
node->mark = 0;
node->ch = character[i];
node->weight = 1;
/*头结点的下一结点为空,连接node*/
if (tree->next == NULL)
tree->next = node;
else
{
ptr = tree->next;
while (ptr&&ptr->ch != node->ch)
{
/*将指针移至链表尾*/
ptr = ptr->next;
/*后移*/
beforeptr = beforeptr->next;
}
if (ptr&&ptr->ch == node->ch)
{
/*如果链表中某结点的字符与新结点的字符相同*/
/*将该结点的权加一*/
ptr->weight = ptr->weight + 1;
free(node); /*释放node结点的存储空间*/
}
else
{
/*新结点与表中结点不相同,将新结点插入链表后*/
node->next = beforeptr->next;
/*node连接在beforeptr之后*/
beforeptr->next = node;
}//else
}
}
return tree;
}
/*将整理完的字符串按出现次数从小到大的顺序排列 */
linktree taxisnode(linktree tree)
{
linktree head, ph, pt, beforeph; /*head为新链表的表头结点*/
head = (linktree)malloc(sizeof(Hftree));/*创建新链表的头结点*/
if (!head)return NULL;
head->next = NULL; /*新结点的头结点为空,后续结点也为空*/
ph = head;
beforeph = head;
while (tree->next)
{
pt = tree->next;/*取被操作链表的首元结点*/
tree->next = pt->next;
pt->next = NULL; /*取出pt所指向的结点*/
ph = head->next;
beforeph = head;
if (head->next == NULL)
head->next = pt;/*创建当前操作链表首元结点*/
else
{
while (ph&&ph->weight<pt->weight)
{/*将被操作结点插入相应位置*/
ph = ph->next;
beforeph = beforeph->next;
}
pt->next = beforeph->next;
beforeph->next = pt;
}
}
free(tree);
return head;
}
/*用排完序的字符串建立霍夫曼树 */
linktree createHftree(linktree tree)
{
linktree p, q, newnode, beforep;
for (p = tree->next, q = p->next; p != NULL&&q != NULL; p = tree->next, q = p->next)
{
tree->next = q->next;
q->next = NULL;
p->next = NULL;
newnode = (linktree)malloc(sizeof(Hftree));/*申请新结点作为霍夫曼树的中间结点*/
if (!newnode)return NULL;
newnode->next = NULL;
newnode->mark = 0;
newnode->lchild = p;/*取链表头结点后的两个结点作为新结点的左、右儿子*/
newnode->rchild = q;
p->parent = newnode;
q->parent = newnode;
newnode->weight = p->weight + q->weight;
p = tree->next;
beforep = tree;
if (p != NULL&&p->weight >= newnode->weight)/*将新结点插入原链表的相应位置*/
{
newnode->next = beforep->next;
beforep->next = newnode;
}
else
{
while (p != NULL&&p->weight<newnode->weight)
{
p = p->next;
beforep = beforep->next;
}
newnode->next = beforep->next;
beforep->next = newnode;
}
}
return (tree->next);
}
/*对霍夫曼树进行编码 */
long Huffmancoding(linktree tree , int &v , int &u)
{
int index = 0;
char *code;
linktree ptr = tree;
code = (char *)malloc(10 * sizeof(char));/*此数组用于统计霍夫曼编码*/
long ret = 0;
if (ptr == NULL)
{
cout << "霍夫曼树是空的!" << endl;
exit(0);
}
else
{
while (ptr->lchild&&ptr->rchild&&ptr->mark == 0)
{
while (ptr->lchild&&ptr->lchild->mark == 0)
{
code[index++] = '0';
ptr = ptr->lchild;
if (!ptr->lchild&&!ptr->rchild)
{
ptr->mark = 1;
code[index] = ' ';
//计算信号长度
int temp = 0;
for (index = 0; code[index] != ' '; index++)
{
if (code[index] == '0')
temp += u;
else if (code[index] == '1')
temp += v;
}//for
ret = ret + (temp * ptr->weight);
ptr = tree;
index = 0;
}//while
}//while
if (ptr->rchild&&ptr->rchild->mark == 0)
{
ptr = ptr->rchild;
code[index++] = '1';
}//if
if (!ptr->lchild&&!ptr->rchild)
{
ptr->mark = 1;
code[index++] = ' ';
//计算信号长度
int temp = 0;
for (index = 0; code[index] != ' '; index++)
{
if (code[index] == '0')
temp += u;
else if (code[index] == '1')
temp += v;
}
ret += (temp * ptr->weight);
ptr = tree;
index = 0;
}//if
if (ptr->lchild->mark == 1 && ptr->rchild->mark == 1)
{
ptr->mark = 1;
ptr = tree;
index = 0;
}//if
}//while
}//else
return ret;
}
/*释放霍夫曼树所占用的空间*/
void deletenode(linktree tree)
{
linktree ptr = tree;
if (ptr)
{
deletenode(ptr->lchild);
deletenode(ptr->rchild);
free(ptr);
}
}
int main()
{
int n , u=0 , v=0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> u >> v;
char character[MAXLEN];
linktree temp, ht, htree, ptr = NULL;
cin >> character;
temp = tidycharacter(character);
ht = taxisnode(temp);
htree = createHftree(ht);
//得到发送时间最小长度
cout << Huffmancoding(htree, u, v) << endl;
//释放内存
deletenode(htree);
}//for
system("pause");
return 0;
}