【定义】
带权路径长度(WPL):设二叉树有n个叶子节点,每个叶子节点带有权值Wk,从根节点到每个叶子节点的长度为Lk,则每个叶子节点的带权路径长度之和就是:
WPL=【求和k=1->n】WkLk
最优二叉树或者哈夫曼树:WPL最小的二叉树
/* 哈夫曼树和哈夫曼编码 */
#include<stdio.h>
#include<stdlib.h>
#define LENGTH 6
typedef int ElementType;
//哈夫曼树节点定义
typedef struct HuffmanTreeNode *Huffman;
struct HuffmanTreeNode{
ElementType data; //权值
Huffman Left;
Huffman Right;
};
Huffman CreateHuffmanTree(ElementType arr[]); //创建哈夫曼树
int CalculateWPL(Huffman PtrTree,int len); //计算带权路径长度
void HuffmanCoding(Huffman PtrTree,int len); //哈夫曼编码
void PreOrderPriHuffmanTreeNode(Huffman PtrTree);//先序打印哈夫曼树
void MidOrderPriHuffmanTreeNode(Huffman PtrTree);//中序打印哈夫曼树
int main()
{
ElementType arr[]={9,12,6,3,5,15};
Huffman Proot=CreateHuffmanTree(arr);
puts("PreOrderPriHuffmanTreeNode: ");
PreOrderPriHuffmanTreeNode(Proot);
putchar('\n');
puts("MidOrderPriHuffmanTreeNode: ");
MidOrderPriHuffmanTreeNode(Proot);
putchar('\n');
HuffmanCoding(Proot,0);
printf("WPL=%d\n", CalculateWPL(Proot,0));
system("pause");
return 0;
}
Huffman CreateHuffmanTree(ElementType arr[])
{
Huffman PtrArr[LENGTH];
Huffman PtrT;
Huffman Proot=NULL;
/*
[1]将各个权值看成n棵树的森林(每棵树仅有一个节点)
构建一个结构体指针数组,每个数组元素均是一棵树
*/
for(int i=0;i<LENGTH;i++){
PtrT=(Huffman)malloc(sizeof(struct HuffmanTreeNode));
PtrT->data=arr[i];
PtrT->Left=NULL;
PtrT->Right=NULL;
PtrArr[i]=PtrT;
}
/* 循环建立哈夫曼树 */
for(int i=1;i<LENGTH;i++){
int k1=-1; //权值最小的树节点的下标
int k2; //次小节点
for(int j=0;j<LENGTH;j++){
if(PtrArr[j]!=NULL&&k1==-1){
k1=j;
continue;
}
if(PtrArr[j]!=NULL){
k2=j;
break;
}
}
/*
选择排序
for n=第二个元素至末元素
{找出剩余元素的最小值,并将其放在第n个元素中}
找出第n个元素与第一个元素,如果第n个元素更小,交换这两个元素的值
时间复杂性 O(N^2)
此处要记录最小和次小元素
*/
for(int j=k2;j<LENGTH;j++){
if(PtrArr[j]!=NULL){
if(PtrArr[j]->data<PtrArr[k1]->data){
k2=k1;
k1=j;
}else if(PtrArr[j]->data<PtrArr[k2]->data){
k2=j;
}
}
}
/*
[2]在森林中选出两个根结点的权值最小的树合并,
作为一棵新树的左、右子树,
新树的根结点权值为其左、右子树根结点权值之和
Proot 指向其根节点
*/
Proot=(Huffman)malloc(sizeof(struct HuffmanTreeNode));
Proot->data=PtrArr[k1]->data + PtrArr[k2]->data;
Proot->Left=PtrArr[k1];
Proot->Right=PtrArr[k2];
//新树插入森林
PtrArr[k1]=Proot;
PtrArr[k2]=NULL;
}
return Proot;
}
int CalculateWPL(Huffman PtrTree,int len)
{
if(!PtrTree){
return 0;
}else{
if(PtrTree->Left==NULL&&PtrTree->Right==NULL){
return PtrTree->data * len;
}else{
return CalculateWPL(PtrTree->Left,len+1)+CalculateWPL(PtrTree->Right,len+1);
}
}
}
void HuffmanCoding(Huffman PtrTree,int len)
{
static int arr[20];
if(PtrTree){
if(PtrTree->Left==NULL&&PtrTree->Right==NULL){
printf("Weight: %d\n", PtrTree->data);
for(int i=0;i<len;i++){
printf("%d", arr[i]);
}
putchar('\n');
}else{
arr[len]=0;
HuffmanCoding(PtrTree->Left,len+1);
arr[len]=1;
HuffmanCoding(PtrTree->Right,len+1);
}
}
}
void PreOrderPriHuffmanTreeNode(Huffman PtrTree)
{
if(!PtrTree){
return;
}else
{
printf("%d ", PtrTree->data);
PreOrderPriHuffmanTreeNode(PtrTree->Left);
PreOrderPriHuffmanTreeNode(PtrTree->Right);
}
}
void MidOrderPriHuffmanTreeNode(Huffman PtrTree)
{
if(!PtrTree){
return;
}else
{
printf("%d ", PtrTree->data);
MidOrderPriHuffmanTreeNode(PtrTree->Left);
MidOrderPriHuffmanTreeNode(PtrTree->Right);
}
}
输出示例
PreOrderPriHuffmanTreeNode:
50 21 9 12 29 14 6 8 3 5 15
MidOrderPriHuffmanTreeNode:
50 21 9 12 29 14 6 8 3 5 15
Weight: 9
00
Weight: 12
01
Weight: 6
100
Weight: 3
1010
Weight: 5
1011
Weight: 15
11
WPL=122