哈夫曼树的创建:用一个指针数组存放每个字符的值和次数(权值),并按照权值升序规则排序,合并数组的前两个节点,并生成一个新的节点,其左右孩子即为数组的前两个元素,用根节点指向它,将其放在指针数组的首位,从第三个元素开始依次向前移动一位,重新排序,重复上述步骤直至数组中至剩下一个元素。比如:
typedef struct HuffmanNode
{
ElementType data;
int weight;
struct HuffmanNode *lchild;
struct HuffmanNode *rchild;
int flag;//用于后序查找
ElementType code[Maxsize]; //存放每个字符的哈夫曼编码
};
typedef struct MyStack
{
struct HuffmanNode *node[Maxsize];
int top;
};
void Sort(HuffmanNode *arr[],int length) //采用插入排序
{
for(int i=1;i<length;i++)
{
if(arr[i]->weight<arr[i-1]->weight)
{
HuffmanNode *temp=arr[i];
int j=0;
for(j=i;j>0&&temp->weight<arr[j-1]->weight;j--)
arr[j]=arr[j-1];
arr[j]=temp;
}
}
}
void CreateTree(HuffmanNode *arr[],int length,HuffmanNode **root)
{
if(length<2)
{
printf("创建失败.\n");
return;
}
Sort(arr,length);//按照权值从小到大排序
while(length>1)
{
//合并前两个节点
HuffmanNode *temp=(HuffmanNode*)malloc(sizeof(HuffmanNode));
temp->weight=arr[0]->weight+arr[1]->weight;
temp->data='*';
temp->lchild=arr[0];
temp->rchild=arr[1];
*root=temp;
arr[0]=temp;
//所有元素向前移动一位
for(int j=2;j<length;j++)
{
arr[j-1]=arr[j];
}
length--;
//重新按照权值升序排序
for(int i=0;i<length-1;i++)
{
if(arr[i]->weight>arr[i+1]->weight)
{
temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
}
}
编码,按照左“0”右“1”为每个叶子节点分配唯一的编码,这里使用一个字符数组,用于记录访问路径,并且使用二叉树后序遍历的方式(因为后序遍历能够得到从根到叶子节点的完整路径,而且方便与路径数组同步进行),即访问左孩子时进栈,路径数组中加入“0”,访问右孩子时路径数组加入“1”,左右孩子访问完毕后,退栈,路径数组长度减一。如遇到叶子节点,此时的路径数组即为该元素的哈夫曼编码。
void HuffmanCode(HuffmanNode *root,char _arr[])
{
if(root==NULL) return;
HuffmanNode *p=root;
HuffmanNode *_array[Maxsize];
MyStack *s=CreateStack();
char path[Maxsize]="\0";
int length=0;
int index=0;
while(p!=NULL||s->top>-1)
{
if(p!=NULL)
{
s->node[++(s->top)]=p;
if(p->data!='*')
{
HuffmanNode *temp=(HuffmanNode*)malloc(sizeof(HuffmanNode));
temp->data=p->data;
strcpy(temp->code,path);
_array[index++]=temp;
printf("%c:",p->data);
printf("%s",temp->code);
printf(" ");
}
p->flag=0;
p=p->lchild;
path[length++]='0';
}
else
{
HuffmanNode *_node=s->node[s->top];
if(_node->flag==0)
{
_node->flag=1;
p=_node->rchild;
length--;
path[length]='\0';
path[length++]='1';
}
else
{
s->node[s->top--]=NULL;
path[--length]='\0';
}
}
}
int i=0;
printf("\n");
printf("编码输出:");
while(_arr[i]!='\0')
{
for(int j=0;j<index;j++)
{
if(_arr[i]==_array[j]->data)
printf("%s",_array[j]->code);
}
i++;
}
}
样例:
输入电文字符串:AAEEFEBCCCCAGB